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)

Płomień i krzyż

Jakiś czas temu skusiłem się na Empik Premium. Co prawda z cashback Empik się wycofał, ale nadal uważam, że w sumie warto, bo głównie o dostęp do audiobooków w ramach Empik Go mi chodziło. W każdym razie 50 zł[1] za rok wydawało się niewygórowane. I choć mam wrażenie, że na początku dostępnych było więcej tytułów, to nadal uważam, że to fajna opcja.

W każdym razie szukałem jakiegoś audiobooka do posłuchania na Empik Go. Jakoś padło na Płomień i krzyż autorstwa Jacka Piekary. Niczego tego autora nie znałem, choć nazwisko kojarzyłem. Polska fantastyka, ilość tytułów, ocena w okolicy 4 i do tego opowiadania nie nastrajały zbyt optymistycznie. Jednak stwierdziłem, że dam szansę. Pozytywne zaskoczenie: lekko się czyta (słucha!), ciekawy pomysł i na dobrą sprawę, z uwagi na powiązania, spokojnie można uznać te niby opowiadania za kolejne rozdziały powieści.

Disclaimer po rozmowie ze znajomymi: nie zwracałbym większej uwagi na krótkie opisy traktujące o alternatywnej historii w religii. Tzn. to jak najbardziej ma miejsce, ale – przynajmniej z tego co dotychczas czytałem – jest bardziej tłem zdarzeń, nie ich osią.

Jestem po lekturze tomu pierwszego[2] i wyrażam umiarkowany zachwyt. Intryga zgrabnie się rozwija, jeśli w kolejnych tomach będzie utrzymany poziom, to gdzie jest serial, ja się pytam? Bo z tego co do tej pory poznałem, to aż się prosi o ekranizację.

I jeszcze taka zabawna sytuacja. W polu wyszukiwania w Empik Go wpisałem płomień i krzyż, wybrałem tom drugi z podpowiedzi, zatwierdziłem wyszukanie i ujrzałem coś takiego:

Wyszukanie płomień i krzyż tom 2 w Empik Go - screenshot
Wyszukiwanie tomu II w Empik Go, smartfon Android

Pytania konkursowe (nagród nie przewiduję, ale konkurs może być, prawda?):

  1. Co kryją poszczególne pozycje?
  2. Którą z pozycji należy wybrać, aby otworzyć wyszukiwany tom 2?
  3. Co się stanie po zmianie położenia smartfona z prezentowanego na poziome?

Rozwiązanie za jakiś tydzień w formie aktualizacji wpisu. Podpowiem tylko, że kto w IT pracuje, ten w cyrku się nie śmieje.

UPDATE Pora na nieco spóźnione rozwiązanie zagadki.

  1. Są to kolejne trzy tomy cyklu. Skoro wyszukuję tom 2 to pewnie jestem zainteresowany także 1 i 3. Logiczne.
  2. Nie wiem. Trzeba próbować. Ale jest pozytyw: po powrocie pozycje się nie zmieniają, więc czekają nas najwyżej trzy próby.
  3. Nic. Skoro se user przechyla smartfona, to chce oglądać ekran bokiem, a ustawienia systemowe kłamią. Oczywiste.

[1] Świta mi, że wtedy było 40 zł. Nieistotne w sumie, historii płatności sprawdzać nie będę.
[2] Przynajmniej wg Biblionetki bo wg Wikipedii wygląda nieco inaczej. W każdym razie niczego nie brakuje i wszystko się spina.

UPDATE Jakoś rok później dotarłem do końca, przynajmniej istniejących pozycji. Czyli przeczytałem Przeklęte przeznaczenie. Jak miałem wrażenie w pewnym momencie, że robi się nieco wtórnie, tak ta pozycja mi się bardzo podobała. Z posłowia można dowiedzieć się, że powstaje gra oraz coś filmowego się dzieje. I bardzo to cieszy.