django加密簽名

Sing.py 中實現了一系列的加密方式:signer 和TimestampSigner
一些加密可能須要首先在settings.py 中添加 SECRET_KEY django

具體的使用方法能夠使用以下:dom

from django.core.signing import Signer
signer = Signer()
value = signer.sign('My string')
value
'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w'ide

若是您不但願特定字符串的每次出現具備相同的簽名散列,您能夠使用可選的salt參數到Signer類,解密的時候不須要傳入salt 參數函數

signer = Signer()
signer.sign('My string')ui

'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w'this

signer = Signer(salt='extra')
signer.sign('My string')加密

'My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw'設計

signer = Signer(salt='e')
signer.sign('My string')code

'My string:9v2dnmMn6i6XkGqoz1sYnKk-GjE'three

signer.unsign('My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw')

'My string'

Timestamp Signer是Singer的一個子類,它將一個帶符號的時間戳附加到該值。 這容許您確認在指定的時間段內建立了一個簽名的值:

from datetime import timedelta
from django.core.signing import TimestampSigner
signer = TimestampSigner()
value = signer.sign('hello')
value

'hello:1NMg5H:oPVuCqlJWmChm1rA2lyTUtelC-c'

signer.unsign(value)

'hello'

signer.unsign(value, max_age=10)

...
SignatureExpired: Signature age 15.5289158821 > 10 seconds

signer.unsign(value, max_age=20)

'hello'

signer.unsign(value, max_age=timedelta(seconds=20))

'hello'

保護數據,要傳遞一些敏感數據,能夠使用加密傳動

from django.core import signing
value = signing.dumps({"foo": "bar"})
value

'eyJmb28iOiJiYXIifQ:1NMg1b:zGcDE4-TCkaeGzLeW9UQwZesciI'

signing.loads(value)

{'foo': 'bar'}

多個數據

from django.core import signing
value = signing.dumps(('a','b','c'))
signing.loads(value) ['a', 'b', 'c']

用戶名的密碼加密解密方式:

加密

用戶名的加密方式在Django 源碼裏使用了make_password() 這個方法實現
函數的原型是:
def make_password(password, salt=None, hasher='default'):

"""
Turn a plain-text password into a hash for database storage

Same as encode() but generates a new random salt.
If password is None then a concatenation of
UNUSABLE_PASSWORD_PREFIX and a random string will be returned
which disallows logins. Additional random string reduces chances
of gaining access to staff or superuser accounts.
See ticket #20079 for more info.
"""
if password is None:
    return UNUSABLE_PASSWORD_PREFIX + get_random_string(UNUSABLE_PASSWORD_SUFFIX_LENGTH)
hasher = get_hasher(hasher)

if not salt:
    salt = hasher.salt()#get_random_string
return hasher.encode(password, salt)

#這裏面設計到sha256, randow.getstate(),random.speed()

random.getstate()

(3, (2147483648, 4018322764, 577648385, 1526147929, 1680474043, 3919679311, 2889319108, 4191545603,                            2720450620, 3365467495, 3734949539, 673801099,None)

hashlib.sha256(('%s' % time.time).encode('utf-8')).digest()

b"1=_\xaa\x90\xa4\xe9\x86au\xb0'\xfaJ\x83\xb9%\x11E\x9f\xed\x0c\x15}\x9d&\xfb\xc72\xa6Z\xcf"

def get_random_string(length=12,

allowed_chars='abcdefghijklmnopqrstuvwxyz'
                                'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'):
"""
Returns a securely generated random string.

The default length of 12 with the a-z, A-Z, 0-9 character set returns
a 71-bit value. log_2((26+26+10)^12) =~ 71 bits
"""
if not using_sysrandom:
    # This is ugly, and a hack, but it makes things better than
    # the alternative of predictability. This re-seeds the PRNG
    # using a value that is hard for an attacker to predict, every
    # time a random string is required. This may change the
    # properties of the chosen random sequence slightly, but this
    # is better than absolute predictability.
    random.seed(
        hashlib.sha256(
            ("%s%s%s" % (
                random.getstate(),
                time.time(),
                settings.SECRET_KEY)).encode('utf-8')
        ).digest())
return ''.join(random.choice(allowed_chars) for i in range(length))

最後結合這兩個函數生成一個密文hasher.encode(password, salt)

slat 參數

默認提供了一個隨機的salt 參數,所以對於同一個密碼每次都會有不一樣的密文出現例如:

make_password('test')
'pbkdf2_sha256$36000$isQNwbk2iwg1$nVHLwSeHziSu/N2gP8QJNgAJjBb879hOdDMim++t0SU='
make_password('test')

'pbkdf2_sha256$36000$QxlN97KubUTA$U2GGmXhL3cBgVpYfwXGgW659EYV8W/MJBFzH/v6IN3A='

make_password('test')

'pbkdf2_sha256$36000$80Z9aOgA7IX9$+3lWsQvl1qENNfrxt5ThoYbStk+xh+wXbYZznqSlvPA='

解密

解密一樣提供了一個方式check_password:

check_password('test','pbkdf2_sha256$36000$80Z9aOgA7IX9$+3lWsQvl1qENNfrxt5ThoYbStk+xh+wXbYZznqSlvPA=')

True

函數原型

def check_password(password, encoded, setter=None, preferred='default'):

"""
Returns a boolean of whether the raw password matches the three
part encoded digest.

If setter is specified, it'll be called when you need to
regenerate the password.
"""
if password is None or not is_password_usable(encoded):
    return False

preferred = get_hasher(preferred)
hasher = identify_hasher(encoded)

hasher_changed = hasher.algorithm != preferred.algorithm
must_update = hasher_changed or preferred.must_update(encoded)
is_correct = hasher.verify(password, encoded)

# If the hasher didn't change (we don't protect against enumeration if it
# does) and the password should get updated, try to close the timing gap
# between the work factor of the current encoded password and the default
# work factor.
if not is_correct and not hasher_changed and must_update:
    hasher.harden_runtime(password, encoded)

if setter and is_correct and must_update:
    setter(password)
return is_correct
相關文章
相關標籤/搜索