SIKS – Vježba 5 – Implementacija autentikacije u Pythonu

SIKS / Predavanja / Vježbe

Zadatak: Izrada programa za provjeru autentikacije korisnika

Cilj Zadatka:

Autentikacija korisnika je važan aspekt sigurnosti u računalnim sustavima. Ovaj zadatak će demonstrirati kako implementirati program za provjeru autentikacije korisnika u Pythonu, uz primjenu različitih sigurnosnih mjera poput hashiranja lozinki, dodavanja soli i ograničavanja broja neuspjelih pokušaja prijave.

Teorijska podloga:

Hashiranje je proces transformacije lozinke u fiksnu duljinu niza znakova pomoću hash funkcije. Hashiranje je jednosmjerna operacija, što znači da se iz hasha ne može rekonstruirati izvorna lozinka. Hashiranje lozinki je sigurnija praksa od pohrane lozinki u izvornom obliku jer, čak I ako napadač dobije pristup bazi podataka, neće moći saznati izvorne lozinke.

Sol (engl. Salt) je nasumična vrijednost koja se dodaje lozinki prije hashiranja. Dodavanje soli otežava napade pomoću rainbow tablica I brute-force napade. Sol treba biti jedinstvena za svakog korisnika I pohranjena zajedno s hashom lozinke.

Ograničavanje broja neuspjelih pokušaja prijave je mjera zaštite od brute-force napada. Nakon određenog broja neuspjelih pokušaja, korisnički račun se privremeno blokira na neko vrijeme kako bi se spriječilo prekomjerno opterećenje sustava I otežali napadi.

Implementacija jednostavne autentikacije

Upute:

  1. Definiranje Korisničkih Podataka:
    • Na početku programa definirajte rječnik korisnici koji će sadržavati korisnička imena kao ključeve i pripadajuće lozinke kao vrijednosti. Na primjer: korisnici = {'korisnik1': 'lozinka1', 'korisnik2': 'lozinka2'}
  2. Zahtjev za Unosom:
    • Zatražite od korisnika da unese svoje korisničko ime i lozinku koristeći funkcije input().
  3. Provjera Autentikacije:
    • Provjerite postoji li uneseno korisničko ime u rječniku korisnici. Ako postoji, provjerite odgovara li unesena lozinka pripadajućoj lozinki u rječniku.
    • Ako su i korisničko ime i lozinka točni, ispišite poruku “Uspješna autentikacija!”.
    • Ako korisničko ime ne postoji ili lozinka nije točna, ispišite poruku “Pogrešno korisničko ime ili lozinka!”.

Napomena: Ovaj zadatak služi kao osnova za razumijevanje kako funkcionira autentikacija u programiranju. U stvarnim aplikacijama autentikacija zahtijeva mnogo složenije mehanizme sigurnosti, uključujući korištenje vanjskih biblioteka za upravljanje lozinkama i korisničkim sesijama.

Autentikacija korisnika kriptiranom lozinkom – simetrična kriptografija

Ako već imate kriptiranu lozinku generiranu korištenjem OpenSSL naredbe openssl enc -aes-256-cbc -in plaintext.txt -out encrypted_text.txt -pass file:symmetric_key.txt, možemo jednostavno pročitati kriptiranu lozinku iz datoteke i koristiti je za dekripciju prilikom autentikacije korisnika.

import subprocess

# Unaprijed definirani kredencijali
korisnicko_ime = "korisnik123"
simetricni_kljuc_datoteka = "symmetric_key.txt"
kriptirana_lozinka_datoteka = "encrypted_text.txt"

# Funkcija za dekripciju lozinke
def dekriptiraj_lozinku():
    output = subprocess.check_output(["openssl", "enc", "-d", "-aes-256-cbc", "-in", kriptirana_lozinka_datoteka, "-pass", "file:" + simetricni_kljuc_datoteka]).decode().strip()
    return output

# Funkcija za autentikaciju korisnika
def autenticiraj_korisnika():
    uneseno_korisnicko_ime = input("Unesite korisničko ime: ")
    
    # Provjera postojanja simetričnog ključa
    try:
        # Pokušaj dekriptiranja lozinke
        dekriptirana_lozinka = dekriptiraj_lozinku()
    except subprocess.CalledProcessError:
        print("Greška prilikom dekriptiranja lozinke.")
        return
    
    if uneseno_korisnicko_ime == korisnicko_ime:
        unesena_lozinka = input("Unesite lozinku: ")
        
        # Provjera ispravnosti lozinke
        if unesena_lozinka == dekriptirana_lozinka:
            print("Uspješno ste autenticirani.")
        else:
            print("Pogrešna lozinka. Pokušajte ponovno.")
    else:
        print("Pogrešno korisničko ime. Pokušajte ponovno.")

# Pozivanje funkcije za autentikaciju korisnika

autenticiraj_korisnika()

Ovaj kod čita kriptiranu lozinku iz datoteke encrypted_text.txt i dekriptira je koristeći simetrični ključ pohranjen u datoteci symmetric_key.txt. Nakon toga, provjerava se ispravnost unesene lozinke s dekriptiranom lozinkom. Ako su lozinke jednake, korisnik je uspješno autenticiran.

Umjesto korištenja simetrične kriptografije za enkripciju i dekripciju lozinki, razmotrite korištenje jednosmjernih hash funkcija, poput SHA-256, uz dodatak soli (salt). Hashiranje lozinke sa solju znatno otežava napade na lozinke koristeći metode kao što su “rainbow tables”.

Implementacija hashiranja:

1. Definiranje korisničkih podataka

Definirajte rječnik korisnici koji sadrži korisnička imena kao ključeve i pripadajuće hashirane lozinke kao vrijednosti.

import hashlib

korisnici = {
    "korisnik1": "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",  # SHA-256 hash od "lozinka1"
    "korisnik2": "5c29a959abce4eda5f0e7a4e7ea53dce7280a8be29d7e15a3f556dcd6e3b6e7e"   # SHA-256 hash od "lozinka2"
}

2. Provjera autentikacije

Implementirajte funkciju provjeri_autentikaciju koja prima korisničko ime i lozinku, te provjerava njihovu ispravnost.

def provjeri_autentikaciju(korisnicko_ime, lozinka):
    if korisnicko_ime in korisnici:
        lozinka_hash = hashlib.sha256(lozinka.encode()).hexdigest()
        if lozinka_hash == korisnici[korisnicko_ime]:
            return True
    return False

3. Dodavanje soli prilikom hashiranja lozinke

Generirajte nasumičnu vrijednost soli i dodajte je lozinki prije hashiranja.

import os

sol = os.urandom(16)  # Generiranje nasumične vrijednosti soli
lozinka_hash = hashlib.sha256((lozinka + sol).encode()).hexdigest()

4. Ograničavanje broja neuspjelih pokušaja

Implementirajte logiku za ograničavanje broja neuspjelih pokušaja prijave i privremeno blokiranje korisničkog računa.

import time

broj_pokusaja = 0
max_pokusaja = 3
vrijeme_blokade = 30  # sekundi

while broj_pokusaja < max_pokusaja:
    korisnicko_ime = input("Unesite korisničko ime: ")
    lozinka = input("Unesite lozinku: ")

    if provjeri_autentikaciju(korisnicko_ime, lozinka):
        print("Uspješna autentikacija!")
        break
    else:
        broj_pokusaja += 1
        print(f"Pogrešno korisničko ime ili lozinka. Pokušaj {broj_pokusaja}/{max_pokusaja}")

        if broj_pokusaja == max_pokusaja:
            print(f"Prekoračen broj pokušaja. Pokušajte ponovno za {vrijeme_blokade} sekundi.")
            time.sleep(vrijeme_blokade)
            broj_pokusaja = 0
import hashlib
import os
import time

# Definiranje korisničkih podataka s hashiranim lozinkama i solju
korisnici = {
    "korisnik1": {
        "salt": os.urandom(16),
        "hash": ""
    },
    "korisnik2": {
        "salt": os.urandom(16),
        "hash": ""
    }
}

# Inicijalno hashiranje lozinki
for korisnik, podaci in korisnici.items():
    lozinka = "lozinka" + korisnik[-1]  # Pretpostavka za primjer
    salt = podaci["salt"]
    podaci["hash"] = hashlib.sha256(lozinka.encode() + salt).hexdigest()

# Funkcija za provjeru autentikacije
def provjeri_autentikaciju(korisnicko_ime, lozinka):
    if korisnicko_ime in korisnici:
        korisnik = korisnici[korisnicko_ime]
        salt = korisnik["salt"]
        lozinka_hash = hashlib.sha256(lozinka.encode() + salt).hexdigest()
        if lozinka_hash == korisnik["hash"]:
            return True
    return False

# Logika za ograničavanje broja neuspjelih pokušaja
max_pokusaja = 3
vrijeme_blokade = 10  # sekundi

def autenticiraj_korisnika():
    broj_pokusaja = 0
    while broj_pokusaja < max_pokusaja:
        korisnicko_ime = input("Unesite korisničko ime: ")
        lozinka = input("Unesite lozinku: ")

        if provjeri_autentikaciju(korisnicko_ime, lozinka):
            print("Uspješna autentikacija!")
            break
        else:
            broj_pokusaja += 1
            print(f"Pogrešno korisničko ime ili lozinka. Pokušaj {broj_pokusaja}/{max_pokusaja}")

            if broj_pokusaja == max_pokusaja:
                print(f"Prekoračen broj pokušaja. Pokušajte ponovno za {vrijeme_blokade} sekundi.")
                time.sleep(vrijeme_blokade)
                broj_pokusaja = 0

autenticiraj_korisnika()

Zaključak:

Ovaj zadatak prikazuje različite aspekte autentikacije korisnika i sigurnosne mjere koje se mogu implementirati kako bi se povećala sigurnost sustava. Hashiranje lozinki, dodavanje soli i ograničavanje broja neuspjelih pokušaja su ključne tehnike za zaštitu od napada i neovlaštenog pristupa. Važno je napomenuti da su prikazani primjeri ilustrativni i da u stvarnim aplikacijama treba koristiti provjerene i sigurne biblioteke za upravljanje lozinkama i autentikacijom. Implementacijom ovih sigurnosnih mjera, program za provjeru autentikacije korisnika postaje otporniji na različite vrste napada i pruža veću sigurnost korisničkih podataka.