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实现更改图片尺寸大小的方法(基于Pillow包)
Sep 19 Python
Python开发中爬虫使用代理proxy抓取网页的方法示例
Sep 26 Python
Python简单实现查找一个字符串中最长不重复子串的方法
Mar 26 Python
Python第三方库face_recognition在windows上的安装过程
May 03 Python
Python跳出多重循环的方法示例
Jul 03 Python
python自动保存百度盘资源到百度盘中的实例代码
Aug 26 Python
关于python3.7安装matplotlib始终无法成功的问题的解决
Jul 28 Python
Python调用jar包方法实现过程解析
Aug 11 Python
Python3 pyecharts生成Html文件柱状图及折线图代码实例
Sep 29 Python
解决使用Pandas 读取超过65536行的Excel文件问题
Nov 10 Python
用Python提取PDF表格的方法
Apr 11 Python
python文件名批量重命名脚本实例代码
Apr 22 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写的serv-u的web申请账号的程序
2006/10/09 PHP
用js进行url编码后用php反解以及用php实现js的escape功能函数总结
2010/02/08 PHP
用sql命令修改数据表中的一个字段为非空(not null)的语句
2010/06/04 PHP
php中通过eval实现字符串格式的计算公式
2017/03/18 PHP
js中arguments,caller,callee,apply的用法小结
2014/01/28 Javascript
EasyUI实现二级页面的内容勾选的方法
2015/03/01 Javascript
jquery平滑滚动到顶部插件使用详解
2017/05/08 jQuery
angularjs实现搜索的关键字在正文中高亮出来
2017/06/13 Javascript
javascript cookie的基本操作(添加和删除)
2017/07/24 Javascript
微信小程序使用Socket的实例
2017/09/19 Javascript
微信小程序实现导航栏选项卡效果
2020/06/19 Javascript
微信小程序画布圆形进度条显示效果
2020/11/17 Javascript
vue 自定义提示框(Toast)组件的实现代码
2018/08/17 Javascript
使用vue.js在页面内组件监听scroll事件的方法
2018/09/11 Javascript
从Vuex中取出数组赋值给新的数组,新数组push时报错的解决方法
2018/09/18 Javascript
微信小程序基于canvas渐变实现的彩虹效果示例
2019/05/03 Javascript
Vue中使用JsonView来展示Json树的实例代码
2020/11/16 Javascript
python基于phantomjs实现导入图片
2016/05/13 Python
Python 通过URL打开图片实例详解
2017/06/01 Python
Python if语句知识点用法总结
2018/06/10 Python
Django组件之cookie与session的使用方法
2019/01/10 Python
python删除列表元素的三种方法(remove,pop,del)
2019/07/22 Python
Python使用os.listdir和os.walk获取文件路径
2020/05/21 Python
Python如何基于Tesseract实现识别文字功能
2020/06/05 Python
浅谈amaze-ui中datepicker和datetimepicker注意的几点
2020/08/21 HTML / CSS
英国名牌服装购物网站:OD’s Designer
2019/09/02 全球购物
网络工程与软件技术毕业生自荐信
2013/09/24 职场文书
银行会计职员个人的自我评价
2013/09/29 职场文书
外语系毕业生自荐信范文
2013/12/16 职场文书
社会保险接收函
2014/01/12 职场文书
开业主持词
2014/03/21 职场文书
农村党员学习党的群众路线教育实践活动心得体会
2014/11/04 职场文书
转正申请报告格式
2015/05/15 职场文书
大学学生会竞选稿
2015/11/19 职场文书
html css3不拉伸图片显示效果
2021/06/07 HTML / CSS
Python实现视频中添加音频工具详解
2021/12/06 Python