摘要原理
摘要是一種算法的總稱, 使用這種算法對(duì)原始數(shù)據(jù)進(jìn)行運(yùn)算后生成字符串.不同的原始數(shù)據(jù)理論上計(jì)算的結(jié)果是不同的.
這樣達(dá)到的效果是針對(duì)原始數(shù)據(jù)生成其獨(dú)一無二的'指紋'.通過對(duì)比數(shù)據(jù)的'指紋'可以識(shí)別數(shù)據(jù)的真?zhèn)?摘要算法是不可逆的, 即使拿到了這個(gè)指紋, 也無法利用這個(gè)指紋恢復(fù)出原始數(shù)據(jù).因此安全性有一定的保障.
常見的摘要算法有md5, sha1, sha256等.md5和sha1現(xiàn)在已經(jīng)不是安全的摘要算法了.谷歌號(hào)稱已經(jīng)可以產(chǎn)生任意"碰撞".碰撞的意思是說不同的原始數(shù)據(jù)有了同樣的運(yùn)算結(jié)果.如果可以產(chǎn)生任意碰撞, 就意味著任意的結(jié)果都可以用另一個(gè)原始數(shù)據(jù)來仿冒, 所以不安全了.
在保存用戶的密碼時(shí),常用的方法是使用摘要算法生成用戶密碼原始數(shù)據(jù)的摘要,在服務(wù)器數(shù)據(jù)庫里面只保存這個(gè)摘要而不是用戶的原始密碼.這樣做的好處是即使數(shù)據(jù)庫被黑客攻破, 被盜的也只是用戶的密碼的摘要而不是原始密碼.安全性有一定的提高.
可即便是這樣做, 安全性的提高也是有限的, 因?yàn)楹芏嘤脩羰褂玫氖呛唵蚊艽a.而這些簡單密碼的"指紋"早已被計(jì)算出來并生成了一個(gè)"指紋庫", 即彩虹表.如果用戶使用了簡單的密碼, 如生日/單詞等, 黑客可以通過比對(duì), 輕易地獲得用戶的原始密碼.
為了解決這個(gè)問題, 進(jìn)一步提高安全性, "加鹽"的操作被應(yīng)用在用戶密碼保存上.
加鹽原理
為了避免用戶的簡單密碼可以被輕易識(shí)別, 在生成摘要時(shí), 我們可以加點(diǎn)作料.作料可以是一個(gè)固定的字符串, 也可以是一個(gè)根據(jù)用戶不同的隨機(jī)字符串.如果是后者, 這個(gè)隨機(jī)字符串也需要被存儲(chǔ)在服務(wù)器中.
具體流程
1.用戶輸入密碼
2.服務(wù)接受到密碼后加鹽轉(zhuǎn)成復(fù)雜字符串
3.對(duì)這個(gè)字符串使用摘要算法
4.和數(shù)據(jù)庫中存儲(chǔ)結(jié)果比對(duì).
Python實(shí)現(xiàn)
# 定義函數(shù)將用戶密碼轉(zhuǎn)為加鹽字符串
@staticmethod
def salted_password(password, salt='$!@><?>HUI&DWQa`'):
"""$!@><?>HUI&DWQa`"""
salted = password + salt
hash = hashlib.sha256(salted.encode('ascii')).hexdigest()
return hash
# 用戶登錄時(shí)比對(duì)加鹽字符串
@classmethod
def login(cls, form):
salted = cls.salted_password(form['password'])
u = User.find_by(username=form['username'], password=salted)
if u is not None:
result = '登錄成功'
return u, result
else:
result = '用戶名或者密碼錯(cuò)誤'
return User.guest(), result
#用戶注冊(cè)時(shí)存儲(chǔ)加鹽字符串
@classmethod
def register(cls, form):
valid = len(form['username']) > 2 and len(form['password']) > 2
if valid:
form['password'] = cls.salted_password(form['password'])
u = User.new(form)
result = '注冊(cè)成功<br> <pre>{}</pre>'.format(User.all())
return u, result
else:
result = '用戶名或者密碼長度必須大于2'
return User.guest(), result