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之让人欢喜让人忧的迭代
Oct 02 Python
Python编程入门之Hello World的三种实现方式
Nov 13 Python
python中函数传参详解
Jul 03 Python
Python设计模式之中介模式简单示例
Jan 09 Python
详解Python之unittest单元测试代码
Jan 24 Python
Python使用遗传算法解决最大流问题
Jan 29 Python
Python从零开始创建区块链
Mar 06 Python
Pycharm无法使用已经安装Selenium的解决方法
Oct 13 Python
Python中安装easy_install的方法
Nov 18 Python
使用tqdm显示Python代码执行进度功能
Dec 08 Python
python-sys.stdout作为默认函数参数的实现
Feb 21 Python
python实现图片转字符画的完整代码
Feb 21 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实用代码片段
2016/02/02 PHP
JQuery打造PHP的AJAX表单提交实例
2009/11/03 Javascript
js 操作select与option(示例讲解)
2013/12/20 Javascript
jquery实现简单的遮罩层
2016/01/08 Javascript
javascript用正则表达式过滤空格的实现代码
2016/06/14 Javascript
js仿腾讯QQ的web登陆界面
2016/08/19 Javascript
Javascrip实现文字跳动特效
2016/11/27 Javascript
详解JS: reduce方法实现 webpack多文件入口
2017/02/14 Javascript
canvas红包照片实例分享
2017/02/28 Javascript
JS实现颜色动态淡化效果
2017/03/06 Javascript
详解Js里的for…in和for…of的用法
2019/03/28 Javascript
Vue防止白屏添加首屏动画的实例
2019/10/31 Javascript
如何利用JavaScript编写更好的条件语句详解
2020/08/10 Javascript
[00:18]天涯墨客三技能展示
2018/08/25 DOTA
一步步解析Python斗牛游戏的概率
2016/02/12 Python
Python3 循环语句(for、while、break、range等)
2017/11/20 Python
Python实现可自定义大小的截屏功能
2018/01/20 Python
如何实现删除numpy.array中的行或列
2018/05/08 Python
Python 给屏幕打印信息加上颜色的实现方法
2019/04/24 Python
python pytest进阶之conftest.py详解
2019/06/27 Python
python实现图像检索的三种(直方图/OpenCV/哈希法)
2019/08/08 Python
Python 随机生成测试数据的模块:faker基本使用方法详解
2020/04/09 Python
Django web自定义通用权限控制实现方法
2020/11/24 Python
你正在寻找的CSS3 动画技术
2011/07/27 HTML / CSS
英国在线定做百叶窗网站:Make My Blinds
2020/08/17 全球购物
酒店总经理欢迎词
2014/01/08 职场文书
美德少年事迹材料
2014/01/23 职场文书
管理学院毕业生自荐信范文
2014/03/10 职场文书
美容院经理岗位职责
2014/04/03 职场文书
操行评语大全
2014/04/30 职场文书
2014银行领导班子群众路线对照检查材料思想汇报
2014/09/17 职场文书
2015年安全员工作总结范文
2015/04/22 职场文书
2019年鼓励无偿献血倡议书
2019/09/17 职场文书
《游戏王:大师决斗》将推出新卡牌包4月4日上线
2022/03/31 其他游戏
德劲DE1107指针试高灵敏度全波段收音机机评
2022/04/05 无线电
浅谈为什么我的 z-index 又不生效了
2022/07/15 HTML / CSS