2013-05-22 10 views
21

W języku Java starym sposobem przechowywania tajnego klucza, takiego jak hasło, było użycie char[], ponieważ można było nadpisać jego dane po zakończeniu. Jednak od tego czasu okazało się, że jest to niebezpieczne, ponieważ śmieciarz będzie kopiować rzeczy w trakcie reorganizacji sterty. W niektórych architekturach możliwe jest, że strona zostanie zwolniona, a sekret pozostanie, gdy inny program przydzieli tę samą stronę.Czy można przechowywać sekrety na stosie w java?

To jest okropnie brzydkie, ale co, jeśli sekret był przechowywany na stosie metody run Nici? Trzeba jeszcze uważać, aby zakończyć wątek z wdziękiem, aby mógł wyzerować swoje dane, ale problem ten był obecny również w starym stylu.

Jednym z głównych problemów, które widzę od razu, jest to, że nie mogę wymyślić bezpiecznego sposobu na wejście i wyjście danych z pojemnika. Możesz zminimalizować prawdopodobieństwo wycieku hasła, używając strumieni o bardzo małych wewnętrznych buforach, ale na końcu kończy się ten sam problem co char[]. [Edytuj: Czy będzie działał pojedynczy element private static byte i flaga? Chociaż to ograniczyłoby Cię do jednego sekretu na ClassLoader. To dodaje więcej brzydoty, ale może być łatwo ukryć się za dobrze napisanym interfejsem.]

Mam naprawdę sporo pytań.

Czy stert jest bezpieczniejszy od tego typu ataków niż sterty? Czy istnieją mechanizmy czystego Java do wykonywania stosu między dwiema ramkami stosów w sposób, który byłby przydatny dla tego problemu? Jeśli nie, czy JVM wesprze ten typ operacji w bajtodzie?

[Edytuj: Zanim ludzie martwią się zbytnio, jest to bardziej eksperyment myślowy niż cokolwiek innego. Nie mam absolutnie żadnego zamiaru "testowania w produkcji" ani używania go w żadnym bieżącym projekcie. Zdaję sobie sprawę, że to, o czym mówię, jest naprawdę brzydkie, prawdopodobnie strasznie nieporęczne i działa przeciwko całej strukturze JVM. Interesuje mnie tylko to, czy jest to możliwe, czy faktycznie osiąga moje cele i jakie heroiczne działania wymagałoby, aby tak się stało.]

+5

Jeśli masz uzasadnioną obawę, że atakujący uzyska dostęp do danych w ten sposób, istnieje duże prawdopodobieństwo, że zostaniesz sparaliżowany, ponieważ każdy atakujący wyrafinowany na tyle, by martwić się na tym poziomie, jest na tyle zaawansowany, aby złamać większość wszystkiego, co możesz. rzuć na nich. –

+0

Zasadniczo zgadzam się, ale to bardzo słaby argument na zamknięcie zagrożenia. Tak czy siak, rozpocząłem tę drogę podczas przeglądania listy wymagań bezpieczeństwa dostarczonych mi przez mojego klienta. Jednym z nich jest to, że zawsze wyłapujemy tajemnice w pamięci. Nieprzestrzeganie tego zostanie przechwycone przez klienta podczas sprawdzania. Klient jest na tyle sprytny, aby zrozumieć, że 'char []' nie będzie działał, jednak oni również upoważniają nas do korzystania z Javy. Na szczęście są to rozsądni ludzie, rozpoznają konflikt i nie są zbytnio zainteresowani. Ale zmusiło mnie to do myślenia ... –

+0

bardzo słaby argument przeciwko zamknięciu zagrożenia * - przepraszam, czas edycji minął. –

Odpowiedz

12

Użyłbym bezpośredniego ByteBuffera. Pamięć, której używa, nie jest kopiowana i znajduje się tylko w jednym miejscu, przez cały okres istnienia ByteBuffer. BTW nie używaj clear(), ponieważ to tylko resetuje pozycję. Można zastąpić go

bb.clear(); 
while(bb.remaining() >= 8) bb.putLong(0); 
while(bb.remaining() > 0) bb.put((byte) 0); 

Czy stos bardziej bezpieczne od tych typów ataków niż hałdy?

Nie sądzę.

Czy istnieją mechanizmy czystego Java do wykonywania stosu między dwiema ramkami stosów w sposób, który byłby przydatny dla tego problemu?

Możesz przechowywać sekret jako jeden lub dwa long s.

Jeśli nie, to czy JVM wesprze ten typ operacji w bajtodzie?

Kod bajtowy jest przeznaczony do obsługi języka Java i jest niewiele więcej niż to, co można zrobić w Javie.

Jestem zainteresowany, czy jest to możliwe, czy rzeczywiście realizuje swoje cele i jakie rodzaje bohaterstwo zajęłoby aby tak się stało

Użyj bezpośredni ByteBuffer jak sugerowali. ;)

+0

"Pamięć, której używa, nie jest kopiowana ..." - Czy nie używa ona "byte []" wewnętrznie? To jest przechowywane na stercie i tak samo podatne jak każda inna tablica (jak "char []", o którym wspomniałem powyżej), aby dokonać reorganizacji przez GC. –

+2

A heap ByteBuffer używa bajtu [], bezpośredni ByteBuffer wykorzystuje pamięć rodzimą. Natywna pamięć nie jest dotykana przez gc. –

+0

Pytam, czy jest to bezpieczniejsze niż przechowywanie w pamięci jvm? –

Powiązane problemy