30 mai 2012

Secure cookies

import hmac

# hashing with HMAC
CHEIE = "secret"

def hash_str_hmac (s):
    return hmac.new(CHEIE, s).hexdigest()

def make_secure_val(s):
    return "%s|%s" % (s, hash_str_hmac(s))

def check_secure_val(h):
    val = h.split('|')[0]
    if h == make_secure_val(val):
        return val

Mecanism:
* vrem sa setam un cookie de tipul: camp=valoare
Daca setam cookie-ul in acest format, el va fi usor de modificat din browser-ul clientului.
Altfel, putem sa ii atasam un hash, noua valoare devenind: valoare|hash(valoare)
* ca algoritm de hashing, putem folosi md5 sau chiar mai sigur, hmac - acesta implica si contributia unei chei secrete cunoscute doar de noi ("secret")
* noul cookie este transmis serverului, exemplu de format:  user_id=3|890b62425d300574b7bcdf60a5bc6059
3 este valoarea care ne intereseaza, pe cand sirul ce ii urmeaza este criptarea cu cheia secreta CHEIE a numarului 3. ~ make_secure_val()
* pe server, din cookie este extrasa valoarea 3, si hash-ul lui 3 este comparat cu hash-ul primit in cookie. Daca valorile nu coincid, valoarea extrasa este considerata invalida. ~ check_secure_val()

In acest fel, serverul este sigur ca cookie-urile nu au fost modificate fortat de client.

* Setare cookie (in webapp2):
self.response.headers.add_header('Set-Cookie', 'user_id=%s' % mycookie + ';Path=/')
* Stergere cookie - cookie-ul nu se chiar sterge, ci valoarea campului respectiv devine vida
self.response.headers.add_header('Set-Cookie', 'user_id=; Path=/')
" Path=/ " este optionala, dar este important ca de fiecare data cand se doreste suprascrierea, cookie-ul sa fie referit de pe aceeasi cale (path). Nu pot exista 2 cookies care sa contina informatii despre acelasi camp ("user_id"), decat daca sunt salvate in locatii/cai diferite.

Niciun comentariu: