Django密码存储策略分析
作者:蓝绿色~菠菜 发布时间:2022-03-10 04:16:33
一、源码分析
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自带的降低很多,但是需求就是这样的,必须满足。
来源:https://blog.csdn.net/bocai_xiaodaidai/article/details/103872716
猜你喜欢
- 在python中,通过内嵌集成re模块,程序媛们可以直接调用来实现正则匹配。本文重点给大家介绍python中正则表达式 re.findall
- 提起Apple,大部分人都会提起Apple的设计,除了Apple里拥有一批天才设计师外,还因为乔布斯对于设计有着苛刻的要求。所以在IT界,A
- 本文实例讲述了python创建关联数组(字典)的方法。分享给大家供大家参考。具体分析如下:关联数组在python中叫字典,非常有用,下面是定
- 摘要:随着应用领域的不断拓展和多媒体技术, 人们发现关系数据库的许多限制和不足,因而数据库技术进入了“后关系数据库时代”。文件数据库由此应运
- 本文实例讲述了Python实现的读取文件内容并写入其他文件操作。分享给大家供大家参考,具体如下:文件目录结构,如图:read_file.py
- python菜鸟,每天都要进步一点点。二维元组的例子:A = ((1, 1, 1), (1, 1, 1),(1, 1, 1),(0, 0,
- 修改 index.js 内容,写一些 ES6 的语法:const arr = [ new Promise(() => {}
- 前段时间自学了python,作为新手就想着自己写个东西能练习一下,了解到python编写爬虫脚本非常方便,且最近又学习了MongoDB相关的
- 一扯上文化二字,总觉虚无缥缈、漫无边际,或者老气横秋,如何有趣地利用中华文化的思想和符号,结合现代的元素,使其成为有意思的传播手法,这个问题
- 一.摘要做接口自动化测试时,常常需要使用python发送一些json内容的接口报文,如果使用urlencode对内容进行编码解析并发送请求,
- subprocess.run()运行并等待args参数指定的指令完成,返回CompletedProcess实例。参数:(*popenargs
- 如下所示:#-*- coding: utf-8 -*-import pandas as pdimport numpy as npfrom p
- 文件拆分代码:#-*-encoding:utf-8-*-import osimport sysimport threadingdef get
- 这篇文章主要介绍了Python input函数使用实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋
- 前言最近做了一个爬取妹子套图的小功能,小伙伴们似乎很有兴趣,为了还特意组建了一个Python兴趣学习小组,来一起学习。十个python九个爬
- Python获取图片的大小了解过Pillow的都知道,Pillow是一个非常强大的图片处理器,这篇文章主要记录一下Pillow对图片信息的获
- 阅读上一篇:WEB2.0网页制作标准教程(11)不用表格的菜单辛苦了好多天,我们努力学习使用XHTML+CSS来重新设计我们的网站。那么我们
- 这篇文章主要介绍了简单了解Python读取大文件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 前言前两篇我们分别爬取了糗事百科和妹子图网站,学习了 Requests, Beautiful Soup 的基本使用。不过前两篇都是从静态 H
- 您可能听说过,带有 yield 的函数在 Python 中被称之为 generator(生成器),何谓 generator ?我们先抛开 g