2013-06-17 8 views
14

Czy używanie odbicia do szorowania String powoduje, że używanie String jest tak bezpieczne, jak używanie haseł pod char[]?Bezpieczne używanie ciągu znaków do haseł za pomocą odbicia w celu wyszorowania zawartości przed odbiorem śmieci.

Z punktu widzenia bezpieczeństwa ogólnie uważa się, że najlepszą praktyką jest używanie char[] do przechowywania/przekazywania haseł, ponieważ można wyzerować zawartość tak szybko jak to możliwe w kodzie, co może znacznie wydać się zanim garbage collector go wyczyści i pamięć jest ponownie wykorzystywana (usuwając cały ślad), ograniczając okno czasu na atak pamięci.

Jednak char[] nie jest tak wygodne jak String, więc byłoby przydatne, jeśli ktoś może „zarośla” a String w razie potrzeby, dzięki czemu String jako bezpieczne jak char[].

Poniżej znajduje się metoda, która używa odbicia, aby wyzerować pola String.

Czy ta metoda jest "OK", i czy osiąga ona cel polegający na tym, aby String był tak bezpieczny jak char[] dla haseł?

public static void scrub(String str) throws NoSuchFieldException, IllegalAccessException { 
    Field valueField = String.class.getDeclaredField("value"); 
    Field offsetField = String.class.getDeclaredField("offset"); 
    Field countField = String.class.getDeclaredField("count"); 
    Field hashField = String.class.getDeclaredField("hash"); 
    valueField.setAccessible(true); 
    offsetField.setAccessible(true); 
    countField.setAccessible(true); 
    hashField.setAccessible(true); 
    char[] value = (char[]) valueField.get(str); 
    // overwrite the relevant array contents with null chars 
    Arrays.fill(value, offsetField.getInt(str), countField.getInt(str), '\0'); 
    countField.set(str, 0); // scrub password length too 
    hashField.set(str, 0); // the hash could be used to crack a password 
    valueField.setAccessible(false); 
    offsetField.setAccessible(false); 
    countField.setAccessible(false); 
    hashField.setAccessible(false); 
} 

Oto prosty test:

String str = "password"; 
scrub(str); 
System.out.println('"' + str + '"'); 

wyjściowa:

"" 

Uwaga: Można założyć, że hasła nie są String stałe, a więc wywołanie tej metody nie będzie mieć niekorzystny wpływ na internowane łańcuchy.

Poza tym, metoda oparta na zasadzie prostoty jest dość "surowa". Gdybym go używał, nie zadeklarowałbym wyjątków (spróbuj/złap/zignoruj) i powtarzającego się kodu refaktora.

+0

Wydaje się, że zeruje znaki, ale czy nie jest to całkowicie zależne od implementacji maszyny JVM? – fge

+0

węszenie pamięci? to jest atak fantasy. dlaczego nie martwić się o coś bardziej realistycznego, np. NSA szpiegującego twój ruch sieciowy. – ZhongYu

+0

Krzyczy "niezdefiniowane zachowanie" u mnie. Powodzenia ze smokami, velociraptorami i czarnymi dziurami :) – CodesInChaos

Odpowiedz

7

Istnieją dwa potencjalne względy bezpieczeństwa:

  1. String mogą dzielić się swoją tablicę podkładową z innymi smyczki; na przykład jeśli String został utworzony przez wywołanie substring na większym String. Tak więc, gdy zerujesz całą tablicę value, możesz nadpisać stan innych ciągów ... które nie zawierają haseł.

    Utwardzanie polega tylko na wyzerowaniu części tablicy podkładu, która jest używana przez łańcuch hasła.

  2. JLS (17.5.3) ostrzega, że ​​efekty użycia refleksji do zmiany zmiennych są niezdefiniowane.

    Jednak kontekstem jest model pamięci Java oraz fakt, że kompilator może agresywnie buforować zmienne final.W tym przypadku:

    • można się spodziewać, że łańcuch jest thread-ograniczony, a

    • nie należy używać żadnej z tych zmiennych ponownie.

nie spodziewałbym jeden z nich będzie realne problemy ... modulo mocujące zerowanie nadmiernie agresywny z value.


Ale prawdziwym problemem jest Velociraptors. :-)


Jestem zdziwiony, że naprawdę zawracasz sobie głowę zapuszczaniem takich haseł. Kiedy myślisz o tym, przed czym chronisz, jest możliwość, że ktoś może odczytać pamięć procesową ... lub plik zrzutu pamięci lub plik wymiany ... aby odzyskać hasła. Ale jeśli ktoś może to zrobić, bezpieczeństwo twojego systemu musi być już naruszone ... ponieważ te rzeczy najprawdopodobniej wymagają dostępu (lub równoważnego). A jeśli mają dostęp root, mogą "debugować" swój program i przechwycić hasła przed twoja aplikacja je zapala.

+0

Być może kod jest zbyt brutalny/prosty. Co jeśli wycięto tylko wskazaną część tablicy? I tylko licznik jest ustawiony na zero (aby usunąć ślad długości hasła)? – Bohemian

+0

Ta troska nie ma wpływu na główny problem, bezpieczeństwo. Ciąg znaków może być obserwowany jako uszkodzony po zresetowaniu. –

+0

OK - Edytowałem kod tak, aby szorować tylko część aktualnie używanej macierzy. – Bohemian

1

Jednym z argumentów przeciwko Stringowi jest to, że zbyt łatwo nieumyślnie wykonać kopię. Używanie łańcuchów bezpiecznie jest możliwe w teorii, ale cały ekosystem biblioteki opiera się na założeniu, że kopiowanie ciągów jest całkowicie OK. W końcu, biorąc pod uwagę wszystkie ograniczenia, łańcuchy mogą nie być tak wygodne dla tego przypadku użycia, jak to zwykle bywa.

+0

Ale można też skopiować 'char []'. Mimo że Twój punkt jest ważny, kodowanie disiplin wokół haseł powinno być dokładnie sprawdzone, aby upewnić się, że kopie nie zostaną wykonane, niezależnie od ich typu. – Bohemian

+1

Może dotyczyć utraty wygody. –

Powiązane problemy