Aplikacje w Javie niekoniecznie bezpieczne

Powszechne jest wyobrażenie, że Java jest bezpieczna. Że dzięki jej konstrukcji oraz zabezpieczeniom nasze dane są bezpieczne. Czy rzeczywiście tak jest? Po pierwsze musimy rozdzielić aplety umieszczone na stronach www od aplikacji, które uruchamiamy lokalnie. Domyślnie te pierwsze są chronione, podczas gdy te drugie nie. Jeżeli po instalacji nie zmienimy nic w konfiguracji, to w przypadku apletów jesteśmy bezpieczni. Będą one uruchamiane w domyślnej piaskownicy, z zainstalowanym Menedżerem Bezpieczeństwa, który ochroni nasze dane przed dostępem apletu. W przypadku aplikacji, którą ściągnęliśmy na dysk i uruchamiamy lokalnie, np. poprzez:
java -jar aplikacja.jar
lub skrypt, który uruchamia aplikację w Javie w analogiczny sposób, to już nie będziemy bezpieczni. W ich przypadku zakładane jest, że robimy to świadomie, zatem aplikacja będzie miała dostęp do wszystkiego. Żeby tak nie było należy dodać parametr wywołania, np. tak:
java -Djava.security.manager -jar aplikacja.jar
Czy jednak zawsze w przypadku apletów i tak wywołanych aplikacji będziemy bezpieczni? To zależy od konfiguracji naszego bezpieczeństwa. Jeżeli nic w nim nie zmienialiśmy, to tak. Jeżeli jednak daliśmy się komuś przekonać, żeby na potrzeby jego aplikacji zmienił konfigurację i w pliku z polisą dodał wpis:
grant {
permission java.security.AllPermission;
};
to zdjęliśmy zabezpieczenie nie tylko dla danej aplikacji, ale od tej pory każdy aplet będzie miał prawo do wszystkiego. Teraz nawet te aplety, które wydawały się nam bezpieczne mogą zacząć stanowić zagrożenie. Problem w tym, że w przypadku, gdy aplet natrafi na blokadę bezpieczeństwa (np. nie będzie mógł się dobrać do naszego pliku), to zostanie wyrzucony wyjątek. A ten można przechwycić i ukryć przed użytkownikiem. W ten sposób niepostrzeżenie dla nas może dochodzić do testowania naszych zabezpieczeń. W przypadku gdy złośliwy kod wykryje, że mamy lukę może po prostu sobie z niej skorzystać. Pora na test! Celem testu jest uruchomienie jednego i tego samego apletu i weryfikacja zachowania w przypadku domyślnej oraz zmodyfikowanej konfiguracji. Posłużmy się jednym, prostym apletem:
import javax.swing.JApplet;
import javax.swing.JTextArea;
import java.io.File;

public class AppletSecurityTest extends JApplet {

final JTextArea textArea = new JTextArea(5, 60);

public void init() {
super.init();
textArea.setWrapStyleWord(true);
add(textArea);
}

public void start() {
super.start();

final StringBuffer buffer = new StringBuffer();
final String sep = System.getProperty("file.separator");
File testFile;
final String filename = '.' + sep + "test.file";
try {
testFile = new File(filename);
buffer.append("tworzę plik...\n");
testFile.createNewFile();
buffer.append("Utworzono plik: ").append(testFile.getAbsolutePath()).append('\n');
buffer.append("usuwam plik...\n");
testFile.delete();
buffer.append("Plik usunięty").append('\n');
} catch (Throwable t) {
buffer.append("Nie udało się dostać do pliku: ").append(filename).append('\n');
buffer.append(t.toString()).append('\n');
}

textArea.setText(buffer.toString());
}

}
Całość interesującego kodu znajduje się oczywiście w metodzie
start()
gdzie będziemy próbować utworzyć plik w domyślnym katalogu, a następnie go usunąć. Przechwytując wszystkie wyjątki ukrywamy ewentualne błędy przed przeglądarką. W tym przypadku wypiszemy je na ekran, ale złośliwy kod mógłby nic nie pokazywać. A oto ten aplet osadzony na stronie:


Przegladarka nie potrafi obslugiwac apletow lub są one zablokowane.

Teraz pozostaje nam tylko potestować co się stanie gdy będziemy zmieniać uprawnienia. W przypadku domyślnie zdefiniowanej polityki bezpieczeństwa powyższy aplet pokaże:

tworzę plik...
Nie udało się dostać do pliku: ./test.file
java.security.AccessControlException: access denied (java.io.FilePermission ./test.file write)
Świetnie, o to chodziło. A co będzie jak dodamy wspomniane na wstępie uprawnienie? Aby to zrobić potrzebujemy zmodyfikować plik z polisą (java.policy), umieszczony w katalogu JAVA_HOME/jre/lib/security (gdzie JAVA_HOME określa katalog, w którym znajduje się wersja javy używana przez przeglądarkę). Znajdźmy sekcję grant {, w której będziemy dokonywać wpisów. Dopiszmy nowe uprawnienie:
permission java.security.AllPermission;
a następnie przeładujmy stronę z apletem (czyli np. ten wpis w blogu). Okaże się, że aplet wykona co chce, nie napotkawszy sprzeciwu:
tworzę plik...
Utworzono plik: /home/zgibek/./test.file
usuwam plik...
Plik usunięty
Okazuję się zatem, że chęć pójścia na łatwiznę może spowodować rezygnację ze wszystkiego dobrego, co niosła ze sobą Java. A w sumie wystarczyłoby niewiele, tym bardziej, że możliwości jest sporo, ale przede wszystkim można było ustawić ograniczenie na miejsce pochodzenia kodu. Zmodyfikujmy zatem plik polisy usuwając nadane wcześniej pozwolenie i sprawdzając, że aplet znowu przestał działać. Następnie dodajmy całą domenę protekcji, według poniższego wzoru:
grant codebase "http://zgibek.com/blogger/" {
permission java.security.AllPermission;
};
(podany w codebase adres wskazuje na miejsce, gdzie jest skompilowana klasa powyższego apletu). Podsumowując - jeżeli koniecznie chcemy nadać wszystkie uprawnienia, to przynajmniej ograniczmy to źródłem kodu, któremu na to zezwalamy. Tak niewiele, a wystarczająco dużo, żeby z małej dziurki nie powstał gigantyczny krater. I generalnie - należy przyjąć zasadę, że jeżeli nadajemy jakieś uprawnienia, to podajmy zawsze źródło, którego zezwolenie dotyczy. Ale może o tej konfiguracji warto jeszcze oddzielnie napisać...

blog comments powered by Disqus