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生成器generator用法实例分析
Jun 04 Python
在MAC上搭建python数据分析开发环境
Jan 26 Python
python 列表删除所有指定元素的方法
Apr 19 Python
Python元组常见操作示例
Feb 19 Python
python 应用之Pycharm 新建模板默认添加编码格式-作者-时间等信息【推荐】
Jun 17 Python
Python基于Opencv来快速实现人脸识别过程详解(完整版)
Jul 11 Python
python IDLE 背景以及字体大小的修改方法
Jul 12 Python
python 利用turtle模块画出没有角的方格
Nov 23 Python
使用 pytorch 创建神经网络拟合sin函数的实现
Feb 24 Python
jupyter实现重新加载模块
Apr 16 Python
python实现简易名片管理系统
Apr 11 Python
python获取对象信息的实例详解
Jul 07 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 Token(令牌)设计
2008/03/15 PHP
php一些公用函数的集合
2008/03/27 PHP
PHP实现定时生成HTML网站首页实例代码
2008/11/20 PHP
PHP取进制余数函数代码
2012/01/19 PHP
php弹出对话框实现重定向代码
2014/01/23 PHP
PHP简单实现断点续传下载的方法
2015/09/25 PHP
详解PHP字符串替换str_replace()函数四种用法
2017/10/13 PHP
在Laravel5.6中使用Swoole的协程数据库查询
2018/06/15 PHP
php利用array_search与array_column实现二维数组查找
2019/07/08 PHP
js弹窗代码 可以指定弹出间隔
2010/07/03 Javascript
ExtJs Excel导出并下载IIS服务器端遇到的问题
2011/09/16 Javascript
判断js对象是否拥有某一个属性的js代码
2013/08/16 Javascript
使用jquery.qrcode生成彩色二维码实例
2014/08/08 Javascript
JavaScript检测字符串中是否含有html标签实现方法
2015/07/01 Javascript
seajs学习之模块的依赖加载及模块API的导出
2016/10/20 Javascript
Vue.js中组件中的slot实例详解
2017/07/17 Javascript
使用vue完成微信公众号网页小记(推荐)
2019/04/28 Javascript
[10:53]2018DOTA2国际邀请赛寻真——EG
2018/08/11 DOTA
python处理二进制数据的方法
2015/06/03 Python
Python argv用法详解
2016/01/08 Python
Python实现的归并排序算法示例
2017/11/21 Python
Django + Uwsgi + Nginx 实现生产环境部署的方法
2018/06/20 Python
Python tkinter label 更新方法
2018/10/11 Python
Python requests模块实例用法
2019/02/11 Python
Python+OpenCV+pyQt5录制双目摄像头视频的实例
2019/06/28 Python
Django认证系统user对象实现过程解析
2020/03/02 Python
python实现吃苹果小游戏
2020/03/21 Python
selenium学习教程之定位以及切换frame(iframe)
2021/01/04 Python
html5教你做炫酷的碎片式图片切换 (canvas)
2017/07/28 HTML / CSS
GIVENCHY纪梵希官方旗舰店:高定彩妆与贵族护肤品
2018/04/16 全球购物
总账会计岗位职责
2014/03/13 职场文书
爱祖国演讲稿
2014/05/04 职场文书
幼儿园家长反馈意见
2015/06/03 职场文书
Go缓冲channel和非缓冲channel的区别说明
2021/04/25 Golang
python如何做代码性能分析
2021/04/26 Python
python通过新建环境安装tfx的问题
2022/05/20 Python