Dlaczego k-anonimowość nie jest dobra przy hasłach?

Na z3s.pl pojawił się artykuł o tym, czym jest k-anonimowość. Jest to dobry artykuł i warto go przeczytać przed lekturą tego wpisu. Nie zgadzam się jedynie z tezą, że w przypadku haseł jest to bezpieczna metoda sprawdzania. Napisałem komentarz, ale pewnie nie wszyscy czytelnicy bloga tam trafią. Ponieważ bawię się z bazą hashy z HIBP i planuję wkrótce wpis na ten temat, uznałem, że jest dobra okazja do wstępu.

Moja teza jest taka, że w przypadku haseł k-anonimowość wcale nie jest taka bezpieczna, jak jest to przedstawiane. Zgodnie z artykułem obecnie dla hashy z bazy HIBP pierwsze 5 znaków występuje od 381 do 584. Czyli podczas sprawdzenia strona trzecia nie poznaje ani hasła, ani jego pełnego hasha. Przekazywane jest jedynie pierwszych 5 znaków hasha, czyli – tu moja interpretacja – ma jedynie 1/381 do 1/584 prawdopodobieństwo, że zna właściwy hash.

Gdyby przyjąć, że strona trzecia jest złośliwa, warto też przyjąć, że jest inteligentna. Czyli zamiast prawdopodobieństwa zwykłego użyje prawdopodobieństwa ważonego, uwzględniając ilość wystąpień danego hasha. Dla przykładu z artykułu na z3s.pl i hasła P@ssw0rd mamy zwracanych 543 różnych hashy:

curl -s https://api.pwnedpasswords.com/range/21BD1 | wc -l

Natomiast suma wystąpień wszystkich hashy w momencie pisania tego wpisu wynosi 60808.

curl -s https://api.pwnedpasswords.com/range/21BD1 | awk -F ":" '{sum += $2} END {print sum}'

Nasz hash wystąpił 52579 razy. Znając zwyczaje ludzi dotyczące haseł i stosując prawdopodobieństwo ważone uzyskujemy 86% szansę na to, że chodzi o hash należący do hasła P@ssw0rd. Pewności nie ma, ale z 1/543 czyli z ~0,18% robi się 86%, czyli jakieś 467 razy więcej. Ups!

Oczywiście nie znamy tu samego hasła. Znamy jedynie – a i to jedynie ze sporym prawdopodobieństwem – jego hash. O tym, że to niekoniecznie jest problem, może będzie w którymś kolejnym wpisie.

W każdym razie gdybym był serwisem, to bałbym się odpytywać serwis trzeci o hashe haseł moich użytkowników. Użytkowników podejrzewam o proste, słownikowe hasła, jakiś serwis trzeci. Zwłaszcza jeśli ten serwis ma/może mieć także inne informacje, które pozwalają mu ustalić kto pyta o hasło. Tak właśnie może być w przypadku Cloudflare, który może dostawać część ruchu od użytkownika w ramach CDN, DNS lub DoH. Prosta korelacja czasowa może w tym przypadku prowadzić do powiązania hasha hasła z IP użytkownika. Jeśli chcemy sprawdzać hasła, to lepszym rozwiązaniem jest stworzenie lokalnej kopii bazy którą pobierzemy z HIBP.

Co nie znaczy oczywiście, że k-anonimowość ogólnie nie spełnia swojego zadania. Po prostu mam wrażenie, że akurat w przypadku hashy hasła i tej konkretnej implementacji nie jest tak bezpieczna, jak jest to przedstawiane.

Warto też zauważyć, że hasło z którym mamy tu do czynienia jest proste/populare. Dla innych pięcioznakowych początków hashy wystąpienia mogą rozkładać się inaczej, bez tak silnego wskazania na konkretny hash.

UPDATE Tak naprawdę nie ma potrzeby używania całej bazy hashy i ilości ich wystąpień z HIBP (>20GB). Najczęściej występujące 100 tys. hashy to raptem 3,2 MB. Najczęstszy milion – 32 MB.

Niedoszła afera z Brave

Wszystko zaczęło się od wpisu o nieco przydługim tytule The Brave web browser is hijacking links, and inserting affiliate codes, który podrzucił kumpel z pracy. Z tytułu wynika, że Brave podmienia linki tak, aby używane były jego kody afiliacyjne.

Krótko o afiliacji – serwisy internetowe płacą za ruch, albo, dokładniej, za określone akcje użytkowników. Np. rejestracja w serwisie czy zakup produktu. Zwykle wejście od określonego polecającego jest identyfikowane przez odpowiedni parametr w URL, zliczana jest liczba interakcji, a na koniec okresu rozliczeniowego podmiot kierujący użytkowników do serwisu dostaje pieniądze. Takie płatne polecanie.

Z kolei Brave to przeglądarka, która reklamuje się jako szybka, bezpieczna. Blokuje reklamy i trackery, w zamian oferując użytkownikom możliwość zarabiania za oglądanie reklam i dzielenia się z twórcami stron WWW. Brzmi nieco utopijnie i podchodziłem nieco sceptycznie, ale… sprawdziłem, faktycznie jest szybka i bardzo łatwo pozwala na blokowanie reklam, bez konieczności zabawy z rozszerzeniami typu uBlock. Nie jestem fanem, ale przyznaję, że to świetna kombinacja do niektórych zastosowań.

Jak widać w artykule kręcona jest afera, jakoby przeglądarka Brave podmieniała linki i wstawiała swoje kody. Tak naprawdę użytkownikowi końcowemu jest raczej obojętne, kto skorzysta na jego rejestracji w jakimś serwisie. Oczywiście cicha podmiana psułaby biznes afiliacyjny, ale byłby to raczej problem wydawców. I żeby doszło do podmiany, użytkownik i tak musiałby wykonywać interakcję z portalem, na którym uruchomiona jest afiliacja. Biorąc pod uwagę, że chodzi o kilka portali związanych z krytpowalutami, szansa na to jest
niewielka. Więc nawet gdyby o to chodziło, to wpływ na użytkownika końcowego jest dyskusyjny i nie widzę powodu by rezygnować z dobrej przeglądarki. Choć oczywiście takie działanie byłoby kontrowersyjne od strony etycznej i ingerowałoby w wolność użytkowników.

Trochę dziwne byłoby jednak trzymanie listy „cichych podmian” publicznie w źródłach na GitHubie, prawda? No właśnie… Używam od pewnego czasu trybu przypuszczającego, bo tak naprawdę nie o podmienianie linków tak naprawdę chodzi. Z tego co sprawdziłem, nie chodzi o cichą podmianę bez wiedzy użytkownika, tylko o… wyświetlenie w sugerowanych stron z linkiem afiliacyjnym w ramach podpowiedzi, gdy użytkownik wpisuje odpowiedni ciąg w adresie strony.

Podpowiedź w pasku adresu w przeglądarce Brave

Użytkownik musi samodzielnie, ręcznie wybrać URL będący linkiem afiliacyjnym. Co więcej, opcję podpowiadania można w ogóle wyłączyć w ustawieniach, po prostu klikając, nie trzeba używać żadnych ukrytych opcji.

Wiadomo, że Brave to projekt komercyjny, więc jakoś zarabiać musi, ale w tym przypadku w mojej ocenie nie dzieje się nic złego. Nadal spokojnie można używać Brave, jeśli komuś zależy na szybkiej przeglądarce z wbudowanym blokowaniem reklam. Z racji tego, że źródła Brave są dostępne na GitHubie, ciche nadużycia będą raczej trudne do przeprowadzenia.

UPDATE: Dodałem screenshot poglądowy jak to wygląda. Ale przyznaję, że sprawdziłem niedokładnie i trochę racji w zarzutach jest – jeśli wpiszemy cały ciąg binance.us to jako podpowiedź wskakuje pierwszy URL, więc wciśnięcie klawisza enter w tym momencie spowoduje wejście z linkiem afiliacyjnym od Brave:

Podpowiedź w pasku adres w przeglądarce Brave – pełna nazwa, podświetlony link, który będzie użyty po wciśnięciu enter.
Podpowiedź w pasku adres w przeglądarce Brave – pełna nazwa plus spacja, podświetlony link, który będzie użyty po wciśnięciu enter.

Jak widać jest to widoczne dla użytkownika, jak widać powyżej dodanie jakiegokolwiek znaku (spacja, /) po binance.us spowoduje wejście bezpośrednie, bez podpowiedzi, ale… jest.

Instalacja podatnych wersji oprogramowania HOWTO

Niekiedy zachodzi potrzeba uruchomienia starej, podatnej wersji systemu lub usługi w celu przetestowania czegoś, np. exploita. W przypadku Debiana i podobnych dystrybucji opartych na pakietach deb, instalacja starej wersji systemu bywa nieco problematyczna. Po pierwsze, system pakietów nie wspiera downgrade’u, po drugie, domyślnie instalator instaluje najnowsze wersje pakietów, jeśli tylko ma taką możliwość.

Sposoby instalacji podatnych wersji oprogramowania

Sposobów na instalację starszych, podatnych wersji pakietów jest wiele. Można kompilować określoną wersję, ale nie jest to wygodne, jest czasochłonne i niekoniecznie uzyskamy wersję dokładnie taką, jaka była w systemie, np. z powodu patchy nakładanych przez Debiana czy nieco innego środowiska w którym pakiet był budowany[1].

Skoro jednak korzystamy z dystrybucji opartej o pakiety binarne, można także próbować robić downgrade pakietów, albo usuwać pakiety i instalować przy pomocy dpkg zamiast apt[2]. Jeśli nie mamy pecha, wszystko zadziała czy to od razu, czy po małym force przy instalacji. Można też instalować ze starych obrazów instalacyjnych, bez dostępu do sieci. Czasem jednak nie mamy szczęścia. A wszystko można zrobić szybciej i prościej.

Repozytorium starych wersji pakietów Debiana

Przede wszystkim, i tak trzeba jakoś zdobyć podatne wersje pakietów. W przypadku Debiana istnieje snapshot.debian.org, czyli serwis z oficjalnymi, snapshotami mirrorami repozytoriów Debiana. Doskonałe miejsce pozwalające i na pobranie pakietów w takich wersjach, w jakich były w danym momencie w repo, i na postawienie całego systemu w stanie na dany dzień. Snapshoty wykonywane są częściej, niż raz dziennie. Poza głównym repozytorium pakietów dostępne inne, w tym security i backports, więc trudno sobie wyobrazić coś lepszego. Pozostaje instalacja systemu z wykorzystaniem powyższych repozytoriów.

Naprościej można to zrobić z użyciem debootstrap, poprzez podanie mirrora., z którego mają być pobierane pakiety. Przykładowo, aby zainstalować Debiana Buster w wersji, w jakiej był on dostępny dzień po wydaniu:

debootstrap buster /chrooted/ https://snapshot.debian.org/archive/debian/20190707T150059Z/

Po instalacji należałoby jeszcze wejść do chroota i uzupełnić sources.list o wpisy dla repozytorium security, zaktulizować pakiety i… gotowe. W katalogu /chrooted będzie dostępny podatny system. Jeśli był tam podmontowany dysk zdalny, to można uruchomić podatną maszynę według podlinkowanej wyżej instrukcji.

Wykorzystanie LXC do uruchamiania podatnych wersji

Istnieje jeszcze szybszy i IMO wygodniejszy sposób uruchomienia podatnej wersji systemu. Można wykorzystać kontenery LXC do instalacji, a następnie uruchomienia podatnego systemu. O tyle wygodne i bezpieczne, że kontener LXC może być dostępny – i jest to domyślna konfiguracja – wyłącznie z poziomu hypervisora, bez udostępniania go na świat. Kontener z Debianem Buster w wersji na dzień po wydaniu z użyciem LXC tworzymy:

lxc-create -n test -t debian -- -r buster -a amd64 --mirror=https://snapshot.debian.org/archive/debian/20190707T150059Z/ --security-mirror=https://snapshot.debian.org/archive/debian-security/20190707T153344Z/

I gotowe. Po zakończeniu powinniśmy mieć dostępny kontener LXC z podatną wersją systemu. W tym przypadku o nazwie test, którym możemy zarządzać w standardowy sposób, czyli sources.list będziemy mieli:

cat /etc/apt/sources.list
deb https://snapshot.debian.org/archive/debian/20190707T150059Z/          buster         main
deb https://snapshot.debian.org/archive/debian-security/20190707T153344Z/ buster/updates main

[1] Przy weryfikacji zgodności pakietów pomóc mogą reproducible builds.
[2] W tym miejscu nadal odsyłam do wpisu o wajig i zachęcam do zapoznania się z narzędziem. To stary wpis, nie wszystkie opisane okoliczności muszą być prawdziwe, ale wajig ma się dobrze. Warto więc zatem go poznać.