Kontroller om dit Password er Lækket med Python

Hvert evig eneste år hører vi om store datalækager, hvor millioner af brugeres adgangskoder fra diverse tjenester lander i hendene på kriminelle – og til sidst spredes offentligt på internettet. Have I Been Pwned (HIBP), skabt af sikkerhedsforskeren Troy Hunt, er den gyldne standard til at tjekke, om netop din adgangskode florerer derude blandt milliarder af lækkede linjer.

Men hvordan tjekker vi et kodeord, uden at give Troy Hunt vores kodeord? Det gør vi gennem en kryptografisk proces kaldet k-Anonymity.

I denne artikel forklarer vi konceptet og skriver et lille Python script, som du selv kan køre for at teste dine kodeord fuldstændig anonymt!

Er det sikkert at slå op? (k-Anonymity Modellen)

Når vi forespørger HaveIBeenPwned-databasen for at se om Password123! eksisterer, sender vi under ingen omstændigheder Password123! i ren tekst til deres server. Hvis API’et blev hacket i det øjeblik, ville angriberne jo netop se dit password.

I stedet benytter vi Hashing (som altid er en-vejs):

  1. Dit password (Password123!) laves lokalt på din PC om til en usynlig SHA-1 hash-streng før det forlader huset. Eksempelvis bliver det til: CBFDAAC37CE3FDE8A5495FE8FC12EE4B25FBBEFA.
  2. Vi sender nu KUN de første 5 tegn af hashet (CBFDA) afsted til HIBP API’et.
  3. Serveren hos HIBP søger deres masive database igennem for alle hashede data-læk, som starter med eksakt netop de 5 tegn, og returnerer en lang liste med alle hash-slutningerne der fuldfører stregen (Og de svarer ofte med 500+ forskellige match).
  4. Maskinen hos HIBP ved dermed kun, at du har adgangskode der deler præfix med 500 andre koder. De ved absolut ikke hvilken én.
  5. Din maskine og Python-scriptet sammenligner nu selv lokalt, om resten af din SHA-1 hash (de sidste 35 tegn) findes i listen over de returnerede hashes. C-I-A er fuldt og helt bevaret!

Python Adgangskode Checker (Script)

Her er koden, der implementerer præcis ovenstående k-Anonymity model, så du kan tjekke lynhurtigt fra din egen terminal.

Du skal bruge requests modulet (installeres med: pip install requests).

import hashlib
import requests
import sys

def request_api_data(query_char):
    # Danner vores URL med de første 5 hash-karakterer
    url = 'https://api.pwnedpasswords.com/range/' + query_char
    res = requests.get(url)
    
    # 200 = Success status-kode fra webserveren
    if res.status_code != 200:
        raise RuntimeError(f'Fejl: Serveren returnerede status {res.status_code}. Tjek AP-Iet.')
    return res

def get_password_leaks_count(hashes, hash_to_check):
    # Deler serverens rå svar-data op i det resterende hash, og count over hvor mange gange det er blevet lækket
    hashes = (line.split(':') for line in hashes.text.splitlines())
    
    for h, count in hashes:
        if h == hash_to_check:
            # Vi har fundet et eksakt lokalt match for vores adgangskode!
            return count
    return 0

def pwned_api_check(password):
    # Hasher password med SHA-1 modulet og laver store bogstaver da API'et forventer det
    sha1password = hashlib.sha1(password.encode('utf-8')).hexdigest().upper()
    
    # Adskil de første 5 tegn og rest-tegnene
    first5_chars, tail = sha1password[:5], sha1password[5:]
    
    # Sender kun de 5 første tegn
    response = request_api_data(first5_chars)
    
    # Tjekker mod det modtagne datasæt om vores specifikke 'tail' befinder sig og matcher i listen.
    return get_password_leaks_count(response, tail)

def main(args):
    # Loop over alt input fra terminalen
    for password in args:
        count = pwned_api_check(password)
        if count:
            print(f'[ADVARSEL] Dit password "{password}" blev fundet lækket {count} gange... Du burde skifte det nu!')
        else:
            print(f'[SIKKER] "{password}" blev ikke fundet i HIBP databasen. Du burde være sikker!')
    return 'Tjek afsluttet.'

if __name__ == '__main__':
    # Henter passwords ind fra terminal-input under kørsel af script
    # F.eks.: python pwned_check.py mitadgangskode123 qwertypassword
    sys.exit(main(sys.argv[1:]))

Brug Python og en CLI som ovenstående for hurtigt i recon-fasen af sikkerhedstests eller i dit personlige sikkerheds-workflow at validere, om et kompromitteret password reelt set udgør en fare-zonen.

Kilder

> Quiz: Test din viden

1. Hvad er k-Anonymity i HIBP-sammenhæng?

2. Hvad returnerer HIBP-API'et til Python-scriptet?

3. Hvilken hash-algoritme bruges til at tjekke kodeordet mod HIBP?

4. Kan HIBP eller nogen anden se dit faktiske kodeord med k-Anonymity?