Nabity w pendrive’a

Dałem się nabrać. Szukałem metalowych pendrive’ów. Takie idealnie pasują mi jako brelok do kluczy. Do tej pory używałem 32 GB kupionych na Aliexpress, ale pomału zaczynało brakować miejsca. Zajrzałem ponownie na Aliexpress, znalazłem inne, także metalowe.

Od razu odniosę się do komentarza znajomych, którzy brzmiał:
Sorry ale kto normalny kupuje pendriva na Ali?
Kupowałem tam różną drobną elektronikę. Z dotarciem, jakością czy wręcz działaniem bywało różnie, choć zwykle było OK. I jak do tej pory zawsze reklamacje były bezproblemowe. Jak nie dotarło (najczęstsza przyczyna), to oddawali kasę bez większego marudzenia. Jak raz jedna z dwóch kart WiFi przyszła padnięta (błędy w dmesg, w ogóle nie miała napisu 802.1n), to wystarczył screenshot (sic!) z dmesg i także był zwrot pieniędzy. Zresztą szybko nauczyłem się zamawiać po dwie sztuki na tę okoliczność. Takie przydasie typu pendrive, karta SD do zabaw z Banana Pi czy karta WiFi zawsze albo giną, albo potrzebne są kolejne.

Tym razem było inaczej. Pendrive’y przyszły i nic nie zapowiadało problemów. No dobrze, po czasie stwierdzam, że pewne podejrzenia mógł wzbudzić woreczek. Jeśli woreczek, w którym jest pendrive ma napis USB cable, to wiedz, że coś się dzieje. Z drugiej strony to był elegancki woreczek, nie zwykły strunowy.

Pendrive czy kabel? Źródło: fot. własna

W każdym razie postanowiłem przetestować zakup przed użyciem. Co prawda i tak po zapisie zawsze sprawdzam sumy kontrolne, ale zanim dojdę do pełnej pojemności, to może trochę potrwać. Początkowo wyglądało OK, ale po dograniu któregoś z którychś z kolei kopii plików, suma kontrolna się nie zgadzała. Pomyślałem, że uszkodzony i zacząłem sprawdzać drugi. Podobnie. Złożyłem reklamację i… zaczęły się schody.

Najpierw zaproponowali albo zwrot całości kwoty i odesłanie towaru na mój koszt[1], albo zwrot 0%. I zażyczyli sobie video pokazujące, jak pendrive’y nie działają. Podesłałem screenshoty, a także zdjęcia opakowania, oraz ciekawostkę – każdy z pendrive’ów ma odwrotnie włożoną elektronikę.

Niebieskie na górze, niebieskie na dole. Źródło: fot. własna

W międzyczasie pogadałem z ludźmi i dowiedziałem się o programie do sprawdzania pamięci flash f3 – Fight Flash Fraud. Fajne, nie znałem. W Debianie to po prostu pakiet f3 w repozytorium. Działa znacznie szybciej, niż kopiowanie plików i sprawdzanie sum kontrolnych. Przykładowy wynik to:

f3probe -t /dev/sdc
F3 probe 8.0
Copyright (C) 2010 Digirati Internet LTDA.
This is free software; see the source for copying conditions.
 
WARNING: Probing normally takes from a few seconds to 15 minutes, but
         it can take longer. Please be patient.
 
Probe finished, recovering blocks... Done
 
Bad news: The device `/dev/sdc' is a counterfeit of type limbo
 
You can "fix" this device using the following command:
f3fix --last-sec=67108863 /dev/sdc
 
Device geometry:
	         *Usable* size: 32.00 GB (67108864 blocks)
	        Announced size: 58.59 GB (122880000 blocks)
	                Module: 64.00 GB (2^36 Bytes)
	Approximate cache size: 255.00 MB (522240 blocks), need-reset=no
	   Physical block size: 512.00 Byte (2^9 Bytes)
 
Probe time: 9'07"
 Operation: total time / count = avg time
      Read: 41.71s / 1572537 = 26us
     Write: 8'22" / 3656905 = 137us
     Reset: 2us / 2 = 1us

Jak widać kupione pendrive’y to tak naprawdę 32 GB udające 64 GB. I program od razu podaje sposób „naprawy”. Pomyślę.

A jak się skończyła cała sprawa? Ano zmieniłem typ zgłoszenia na fraud (patrz komentarze negatywne do hxxps://www.aliexpress.com/item/1005001801649163.html, to nie jest jednostkowy przypadek), kontaktowałem się z supportem. Uzupełniłem zgłoszenie, pojawiły się dwie propozycje: odesłanie na mój koszt i zwrot 20% wartości zamówienia. Nie dosłałem filmu w ciągu trzech dni, więc zwrócili 20% i zamknęli reklamację. Bez możliwości ponownego otwarcia, choć nie minął termin zwrotu.

Złożyłem apelację, opisując wszystkie szczegóły, oczywiście rozpatrzoną negatywnie. I tyle. Jak widać oferta nadal jest aktywna, a Aliexpress wychodzi najwidoczniej z założenia, że jeśli sprzedawca oszukuje klienta, to koszt tego powinien ponosić klient.

Nieco się nauczyłem i nie była to droga nauka. O programie do testowania pamięci flash było już wyżej. Zaś jeśli chodzi o zakupy na Aliexpress, to jeśli kiedykolwiek coś jeszcze tam kupię, to wyłącznie korzystając z płatności kartą, by móc skorzystać z chargebacku. Inny lifehack jest taki, że jeśli towar z Aliexpress dotrze uszkodzony, niezgodny z opisem, czy w inny sposób kwalifikujący się na pełen zwrot środków, to w przypadku przesyłki nierejestrowanej lepiej jest twierdzić, że w ogóle nie dotarł. Może nie jest to do końca uczciwe, ale wygląda na skuteczne.

Już po napisaniu tego wpisu, ale przed wysłaniem, skontakowałem się z Przelewy24 i… będzie kolejny wpis. Bowiem dowiedziałem się, że po pierwsze, mogą wystąpić do sprzedawcy o zwrot w moim imieniu (o co poprosiłem), a po drugie, mogę próbować jeszcze chargebacku w banku, niezależnie od sposobu płatności. Stay tuned.

[1] Nie mam problemu z odesłaniem, tylko nie rozumiem, czemu ja miałbym za to płacić.

Książki, Biblionetka, BookWyrm

Od zawsze korzystam z Biblionetki, dziś przeczytałem wpis o BookWyrm. Przypomniał mi o moich skomplikowanych relacjach z Biblionetką. Serwisu używam od zawsze, ale nie raz myślałem o migracji. Dawno temu serwis co prawda żył, ale wyrosła mu międzynarodowa konkurencja w postaci Goodreads. Wyglądał na nierozwijany programistycznie, a międzynarodowa konkurencja w social media raczej nie służy serwisom lokalnym. Patrz Nasza Klasa.

Potem Biblionetka została odświeżona, ponadto nie jest to serwis krytyczny z mojego punktu widzenia, dodatkowo okazało się, że na Goodreads brakuje wielu pozycji, które były na Biblionetce. Nie zmigrowałem więc. Stwierdziłem, że poczekam.

Poczekałem nieco dłużej, niż planowałem i… okazało się, że Goodreads likwiduje API. I w tym momencie gdybym korzystał z Goodreads, to rozważałbym ucieczkę. Albo raczej szukał miejsca, do którego się przenieść. Nie żeby Biblionetka miała API. Ale da się skorzystać z jej danych, co pokazuje choćby serwis do korelacji, o którym pisałem w jaką książkę warto przeczytać. Nie ma API, ale rozwiązanie 3rd party działa po niemal dekadzie. Szacun.

Tymczasem wpis o BookWyrm wspomina o możliwości importu danych z innych serwisów. Na przykład z Goodreads. O Biblionetce nic nie ma, ale nie dziwi mnie to. Stwierdziłem, że w sumie może warto robić backup ocen. Albo mieć skrypt, który zescrapuje dane ze strony i zwróci formę łatwą do parsowania.

Nie mam złudzeń, ze względu na różnice językowe to rozwiązanie nie wystarczy do eksportu do BookWyrm. Ale na pewno taką migrację ułatwi. Autor albo nie będzie wymagał interwencji, albo co najwyżej wystarczy zmapować raz. Przypuszczam, że autor plus automatyczne tłumaczenie tytułu pozwoli w wielu przypadkach na określenie tytułu.

Tak czy inaczej powstał taki oto scrapper Biblionetki. I jeśli ktoś przypuszcza, że można w ten sposób pobrać oceny wszystkich użytkowników, to prawdopodobnie ma rację. Publikuję, bo podstawowe, założone użycie to backup własnych ocen.

PINy, hasła – less is more

Będzie o PINach, a ogólniej o hasłach, bo PIN to specyficzny rodzaj hasła. Less is more to w tym przypadku mniej ograniczeń przekładających się na większe bezpieczeństwo. Zaczęło się od wpisu na Twitterze gdzie pokazano ograniczenia nakładane na PIN w pewnej aplikacji.

Zastanowiło mnie, czy da się policzyć o ile takie ograniczenia zmniejszą bezpieczeństwo, rozumiane jako przestrzeń możliwych poprawnych kombinacji PINu.

Na wstępie widać, że pierwsza cyfra PINu musi być inna niż 0 oraz 1. Już sam ten warunek zmniejsza przestrzeń poprawnych PINów o 20%. I to niezależnie od długości PINu.

Tu moja matematyka wysiada i sięgam po symulacje. Skrypt w Pythonie, który sprawdza wszystkie czterocyfrowe kombinacje i podaje, czy PIN jest poprawny (True) czy błędny (False) może wyglądać tak:

def is_valid(a, b, c, d):
    if a < 2:
        return False
    if ((a - b) == (b - c) or (b - c) == (c - d)):
        return False
    if (a == b) or (b == c) or (c == d):
        return False
    if ((b - a > 0) and (c - b > 0) and ((d - c > 0)) or (b - a < 0) and (c - b < 0) and (d - c < 0)):
        return False
    return True


for a1 in range(0, 10):
    for a2 in range(0, 10):
        for a3 in range(0, 10):
            for a4 in range(0, 10):
                result = is_valid(a1, a2, a3, a4)
                print(a1, a2, a3, a4, result)
python piny.py | grep -c True
5120

Jak widać, dla PINów o czterech cyfrach, wprowadzone ograniczenia zmniejszają przestrzeń dozwolonych PINów aż o niemal połowę.

Po co te ograniczenia i jak to zrobić poprawnie?

I teraz o motywacji. Jestem pewnien, że była ona szczytna i chodziło o podniesienie bezpieczeństwa. Jestem prawie pewien, że twórcy chodziło o wyeliminowanie prostych, schematycznych PINów. 0000, 1111, 1234 itp. Jak widać, w praktyce konsekwencje były dalej idące.

Najlepiej biorąc pod uwagę statystyki najczęściej występujących PINów i tworząc krótką listę PINów zabronionych. Wg statystyk PIN 1234 odpowiada za ponad 10% wystąpień wśród używanych PINów. 20 najczęściej używanych PINów jest używanych w 26% przypadków. Taka lista podniesie bezpieczeństwo, rozumiane jako „wymuszenie mało popularnego PINu” równie skutecznie, co proponowane ograniczenia. Zaś bezpieczeństwo rozumiane jako „ilość możliwych kombinacji” zostanie zmniejszone jedynie minimalnie.

Przypadki brzegowe

Jeśli przypuszczamy, że nasi klienci mają znacząco różne preferencje niż te z powyższych statystyk, robi się trudniej. W ogólności najlepiej walidować hasła na obecność zabronionych ciągów już w momencie ustalania hasła przez użytkownika. Zabronić można nazwy firmy, zasobu do którego jest chroniony dostęp, roku, czy popularnych ciągów znaków.

Jeśli jednak tego nie zrobiliśmy zawczasu, nadal nie wszystko stracone, choć robi się nieco ślisko. Nie znamy przecież PINów, co najwyżej mamy dostęp do hashy, więc ciężko będzie określić, których używają nasi klienci. Na ratunek przychodzi hashcat. Niezależnie od użytej funkcji hashującej, brute force krótkich PINów trwa moment. Jeśli korzystamy z bezpiecznych, wolno liczonych hashy, a użytkowników jest wielu, nie ma potrzeby robienia brute force wszystkich. Wystarczy analiza próbki statystycznej. Oczywiście taki audyt to operacja bardzo delikatna, więc nie zabieramy się za to bez stosownych umocowań i zachowania właściwej higieny.

UPDATE: Wersja uogólniona skryptu poniżej. Ilość cyfr w PIN regulowana ilością powtórzeń alfabetu w funkcji product. Dla dłuższych PINów warto skorzystać z pypy, które potrafi być szybsze.

import itertools
alphabet = list(range(0, 10))

def is_valid(i):
    if i[0] < 2:
        return False

    for n in range(0, len(i)-2):
        if i[n] - i[n+1] == i[n+1] - i[n+2]:
            return False

    for n in range(0, len(i)-1):
        if i[n] == i[n+1]:
            return False

    monotonic = True
    for n in range(0, len(i)-2):
        if (i[n] - i[n+1]) * (i[n+1] - i[n+2]) < 0:
            return True
    if monotonic:
        return False

    return True

for i in itertools.product(alphabet, alphabet, alphabet, alphabet):
    result = is_valid(i)
    print(i, result)