Django密码存储策略分析
|
一、源码分析 Django 发布的 1.4 版本中包含了一些安全方面的重要提升。其中一个是使用 PBKDF2 密码加密算法代替了 SHA1 。另外一个特性是你可以添加自己的密码加密方法。 Django 会使用你提供的第一个密码加密方法(在你的 setting.py 文件里要至少有一个方法) PASSWORD_HASHERS = [ 'django.contrib.auth.hashers.PBKDF2PasswordHasher','django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher','django.contrib.auth.hashers.Argon2PasswordHasher','django.contrib.auth.hashers.BCryptSHA256PasswordHasher','django.contrib.auth.hashers.BCryptPasswordHasher',] 我们先一睹自带的PBKDF2PasswordHasher加密方式。
class BasePasswordHasher(object):
"""
Abstract base class for password hashers
When creating your own hasher,you need to override algorithm,verify(),encode() and safe_summary().
PasswordHasher objects are immutable.
"""
algorithm = None
library = None
def _load_library(self):
if self.library is not None:
if isinstance(self.library,(tuple,list)):
name,mod_path = self.library
else:
name = mod_path = self.library
try:
module = importlib.import_module(mod_path)
except ImportError:
raise ValueError("Couldn't load %s password algorithm "
"library" % name)
return module
raise ValueError("Hasher '%s' doesn't specify a library attribute" %
self.__class__)
def salt(self):
"""
Generates a cryptographically secure nonce salt in ascii
"""
return get_random_string()
def verify(self,password,encoded):
"""
Checks if the given password is correct
"""
raise NotImplementedError()
def encode(self,salt):
"""
Creates an encoded database value
The result is normally formatted as "algorithm$salt$hash" and
must be fewer than 128 characters.
"""
raise NotImplementedError()
def safe_summary(self,encoded):
"""
Returns a summary of safe values
The result is a dictionary and will be used where the password field
must be displayed to construct a safe representation of the password.
"""
raise NotImplementedError()
class PBKDF2PasswordHasher(BasePasswordHasher):
"""
Secure password hashing using the PBKDF2 algorithm (recommended)
Configured to use PBKDF2 + HMAC + SHA256.
The result is a 64 byte binary string. Iterations may be changed
safely but you must rename the algorithm if you change SHA256.
"""
algorithm = "pbkdf2_sha256"
iterations = 36000
digest = hashlib.sha256
def encode(self,salt,iterations=None):
assert password is not None
assert salt and '$' not in salt
if not iterations:
iterations = self.iterations
hash = pbkdf2(password,iterations,digest=self.digest)
hash = base64.b64encode(hash).decode('ascii').strip()
return "%s$%d$%s$%s" % (self.algorithm,hash)
def verify(self,encoded):
algorithm,hash = encoded.split('$',3)
assert algorithm == self.algorithm
encoded_2 = self.encode(password,int(iterations))
return constant_time_compare(encoded,encoded_2)
def safe_summary(self,3)
assert algorithm == self.algorithm
return OrderedDict([
(_('algorithm'),algorithm),(_('iterations'),iterations),(_('salt'),mask_hash(salt)),(_('hash'),mask_hash(hash)),])
def must_update(self,3)
return int(iterations) != self.iterations
def harden_runtime(self,3)
extra_iterations = self.iterations - int(iterations)
if extra_iterations > 0:
self.encode(password,extra_iterations)
正如你看到那样,你必须继承自BasePasswordHasher,并且重写 verify() , encode() 以及 safe_summary() 方法。 Django 是使用 PBKDF 2算法与36,000次的迭代使得它不那么容易被暴力破解法轻易攻破。密码用下面的格式储存: algorithm$number of iterations$salt$password hash” 例:pbkdf2_sha256$36000$Lx7auRCc8FUI$eG9lX66cKFTos9sEcihhiSCjI6uqbr9ZrO+Iq3H9xDU= 二、自定义密码加密方法 1、在settings.py中加入自定义的加密算法: PASSWORD_HASHERS = [ 'myproject.hashers.MyMD5PasswordHasher','django.contrib.auth.hashers.PBKDF2PasswordHasher',] 2、再来看MyMD5PasswordHasher,这个是我自定义的加密方式,就是基本的md5,而django的MD5PasswordHasher是加盐的:
from django.contrib.auth.hashers import BasePasswordHasher,MD5PasswordHasher
from django.contrib.auth.hashers import mask_hash
import hashlib
class MyMD5PasswordHasher(MD5PasswordHasher):
algorithm = "mymd5"
def encode(self,salt):
assert password is not None
hash = hashlib.md5(password).hexdigest().upper()
return hash
def verify(self,encoded):
encoded_2 = self.encode(password,'')
return encoded.upper() == encoded_2.upper()
def safe_summary(self,encoded):
return OrderedDict([
(_('algorithm'),''),])
之后可以在数据库中看到,密码确实使用了自定义的加密方式。 3、修改认证方式 AUTHENTICATION_BACKENDS = ( 'framework.mybackend.MyBackend',#新加 'django.contrib.auth.backends.ModelBackend','guardian.backends.ObjectPermissionBackend',) 4、再来看自定义的认证方式
framework.mybackend.py:
import hashlib
from pro import models
from django.contrib.auth.backends import ModelBackend
class MyBackend(ModelBackend):
def authenticate(self,username=None,password=None):
try:
user = models.M_User.objects.get(username=username)
print user
except Exception:
print 'no user'
return None
if hashlib.md5(password).hexdigest().upper() == user.password:
return user
return None
def get_user(self,user_id):
try:
return models.M_User.objects.get(id=user_id)
except Exception:
return None
当然经过这些修改后最终的安全性比起django自带的降低很多,但是需求就是这样的,必须满足。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
