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, password, 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, password, salt, iterations=None): assert password is not None assert salt and '$' not in salt if not iterations: iterations = self.iterations hash = pbkdf2(password, salt, iterations, digest=self.digest) hash = base64.b64encode(hash).decode('ascii').strip() return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash) def verify(self, password, encoded): algorithm, iterations, salt, hash = encoded.split('$', 3) assert algorithm == self.algorithm encoded_2 = self.encode(password, salt, int(iterations)) return constant_time_compare(encoded, encoded_2) def safe_summary(self, encoded): algorithm, iterations, salt, hash = encoded.split('$', 3) assert algorithm == self.algorithm return OrderedDict([ (_('algorithm'), algorithm), (_('iterations'), iterations), (_('salt'), mask_hash(salt)), (_('hash'), mask_hash(hash)), ]) def must_update(self, encoded): algorithm, iterations, salt, hash = encoded.split('$', 3) return int(iterations) != self.iterations def harden_runtime(self, password, encoded): algorithm, iterations, salt, hash = encoded.split('$', 3) extra_iterations = self.iterations - int(iterations) if extra_iterations > 0: self.encode(password, salt, 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', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.Argon2PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', ]
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, password, salt): assert password is not None hash = hashlib.md5(password).hexdigest().upper() return hash def verify(self, password, encoded): encoded_2 = self.encode(password, '') return encoded.upper() == encoded_2.upper() def safe_summary(self, encoded): return OrderedDict([ (_('algorithm'), algorithm), (_('salt'), ''), (_('hash'), mask_hash(hash)), ])
之后可以在数据库中看到,密码确实使用了自定义的加密方式。
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自带的降低很多,但是需求就是这样的,必须满足。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。
相关文章
Django def clean()函数对表单中的数据进行验证操作
这篇文章主要介绍了Django def clean()函数对表单中的数据进行验证操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-09- 这篇文章主要介绍了在Django中使用MQTT的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-05-10
解决导入django_filters不成功问题No module named 'django_filter'
这篇文章主要介绍了解决导入django_filters不成功问题No module named 'django_filter',具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-15- 本文主要介绍了Django项目连接MongoDB的三种方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-27
详解如何使用Docker部署Django+MySQL8开发环境
这篇文章主要介绍了详解如何使用Docker部署Django+MySQL8开发环境,文中通过示例代码以及图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-07-19- 这篇文章主要介绍了Django 解决由save方法引发的错误,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-21
- 这篇文章主要介绍了django前端页面下拉选择框默认值设置方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-10
- 这篇文章主要介绍了django数据模型中null和blank的区别说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-03
- 这篇文章主要介绍了Django表单外键选项初始化的问题及解决方法,需本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,要的朋友可以参考下...2021-04-29
Django开发RESTful API实现增删改查(入门级)
这篇文章主要介绍了Django开发RESTful API实现增删改查(入门级),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-05-10- 这篇文章主要给大家介绍了关于使用AJAX和Django获取数据的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-25
- 这篇文章主要介绍了django ajax发送post请求的两种方法,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...2020-04-30
Django获取model中的字段名和字段的verbose_name方式
这篇文章主要介绍了Django获取model中的字段名和字段的verbose_name方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-20- 这篇文章主要介绍了django中url映射规则和服务端响应顺序的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-05-10
- 在本篇文章里小编给大家整理的是一篇关于Django后台管理系统的图文使用教学内容,需要的朋友们参考下。...2020-04-22
- 本文总结了如何获得SSL证书并给Django项目配置HTTPS,建议先收藏再阅读,将来有一天你很可能会用到它。...2021-05-01
- 这篇文章主要介绍了django 连接数据库出现1045错误的解决方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-15
- 这篇文章主要介绍了Django-ORM-连表正反操作,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-06-13
- 这篇文章主要介绍了Python Django搭建文件下载服务器的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-05-10
Django数据库迁移报错InconsistentMigrationHistory
最近在使用Django,学习了一下Django数据库迁移,在执行迁移命令时,突然报错,本文就总结了一下原因,感兴趣的小伙伴们可以参考一下...2021-05-31