Django密码存储策略分析


Posted in Python onJanuary 09, 2020

一、源码分析

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自带的降低很多,但是需求就是这样的,必须满足。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python读取json文件并将数据插入到mongodb的方法
Mar 23 Python
Python遍历文件夹和读写文件的实现代码
Aug 28 Python
使用PyV8在Python爬虫中执行js代码
Feb 16 Python
Python编程实现生成特定范围内不重复多个随机数的2种方法
Apr 14 Python
解决Pycharm运行时找不到文件的问题
Oct 29 Python
python将处理好的图像保存到指定目录下的方法
Jan 10 Python
Python3解释器知识点总结
Feb 19 Python
python的依赖管理的实现
May 14 Python
python快速排序的实现及运行时间比较
Nov 22 Python
python编写微信公众号首图思路详解
Dec 13 Python
Python 使用office365邮箱的示例
Oct 29 Python
Python实战之用tkinter库做一个鼠标模拟点击器
Apr 27 Python
python 实现Flask中返回图片流给前端展示
Jan 09 #Python
Python注释、分支结构、循环结构、伪“选择结构”用法实例分析
Jan 09 #Python
python将图片转base64,实现前端显示
Jan 09 #Python
Python 解码Base64 得到码流格式文本实例
Jan 09 #Python
Python变量、数据类型、数据类型转换相关函数用法实例详解
Jan 09 #Python
Python+OpenCV实现旋转文本校正方式
Jan 09 #Python
Python 实现OpenCV格式和PIL.Image格式互转
Jan 09 #Python
You might like
php若干单维数组遍历方法的比较
2011/09/20 PHP
php中通过curl检测页面是否被百度收录
2013/09/27 PHP
PHP列出MySQL中所有数据库的方法
2015/03/12 PHP
PHP入门教程之上传文件实例详解
2016/09/11 PHP
Prototype的Class.create函数解析
2011/09/22 Javascript
下拉列表选择项的选中在不同浏览器中的兼容性问题探讨
2013/09/18 Javascript
JQuery中$.ajax()方法参数详解及应用
2013/12/12 Javascript
js函数与php函数的区别实例浅析
2015/01/12 Javascript
javascript实现字符串反转的方法
2015/02/05 Javascript
javascript处理a标签超链接默认事件的方法
2015/06/29 Javascript
基于JQuery实现分隔条的功能
2016/06/17 Javascript
微信小程序中实现一对多发消息详解及实例代码
2017/02/14 Javascript
关于Mac下安装nodejs、npm和cnpm的教程
2018/04/11 NodeJs
vue this.reload 方法 配置
2018/09/12 Javascript
详解Vue一个案例引发「内容分发slot」的最全总结
2018/12/02 Javascript
深入解析微信小程序开发中遇到的几个小问题
2020/07/11 Javascript
解决vuecli3中img src 的引入问题
2020/08/04 Javascript
js实现批量删除功能
2020/08/27 Javascript
Python中解析JSON并同时进行自定义编码处理实例
2015/02/08 Python
python WindowsError的错误代码详解
2017/07/23 Python
在Python web中实现验证码图片代码分享
2017/11/09 Python
Python图片转换成矩阵,矩阵数据转换成图片的实例
2018/07/02 Python
Python数据可视化:泊松分布详解
2019/12/07 Python
python 实现socket服务端并发的四种方式
2020/12/14 Python
详解python日志输出使用配置文件格式
2021/02/10 Python
html5与css3小应用
2013/04/03 HTML / CSS
Madewell美德威尔美国官网:美国休闲服饰品牌
2016/11/25 全球购物
英国领先的狗和宠物美容专家:Christies Direct
2017/04/03 全球购物
Kathmandu澳洲户外商店:新西兰户外运动品牌
2017/11/12 全球购物
goodhealth官方海外旗舰店:新西兰国民营养师
2017/12/15 全球购物
澳大利亚领先的优质葡萄酒拍卖会:Langton’s Fine Wines
2019/03/24 全球购物
图书馆标语
2014/06/19 职场文书
2014年妇委会工作总结
2014/12/10 职场文书
微信早安问候语
2015/11/10 职场文书
2016年共产党员个人承诺书
2016/03/24 职场文书
《现实主义勇者的王国再建记》第三弹OST全曲试听片段公开
2022/04/04 日漫