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 中的list和array的不同之处及转换问题
Mar 13 Python
python字典快速保存于读取的方法
Mar 23 Python
Python3.4 tkinter,PIL图片转换
Jun 21 Python
Python实现string字符串连接的方法总结【8种方式】
Jul 06 Python
Python判断一个文件夹内哪些文件是图片的实例
Dec 07 Python
用Python画一个LinkinPark的logo代码实例
Sep 10 Python
torch 中各种图像格式转换的实现方法
Dec 26 Python
Python namedtuple命名元组实现过程解析
Jan 08 Python
python爬虫模块URL管理器模块用法解析
Feb 03 Python
tensorflow生成多个tfrecord文件实例
Feb 17 Python
python实现贪吃蛇双人大战
Apr 18 Python
python中turtle库的简单使用教程
Nov 11 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 5.3 下载时 VC9、VC6、Thread Safe、Non Thread Safe的区别分析
2011/03/28 PHP
PHP代码优化技巧小结
2015/09/29 PHP
详解PHP的Yii框架中扩展的安装与使用
2016/04/01 PHP
thinkPHP3.2简单实现文件上传的方法
2016/05/16 PHP
关于php中的json_encode()和json_decode()函数的一些说明
2016/11/20 PHP
每天一篇javascript学习小结(基础知识)
2015/11/10 Javascript
JavaScript获取图片像素颜色并转换为box-shadow显示
2016/03/11 Javascript
JavaScript实现阿拉伯数字和中文数字互相转换
2016/06/12 Javascript
window.open打开窗口被拦截的快速解决方法
2016/08/04 Javascript
AngularJS 单元测试(一)详解
2016/09/21 Javascript
详解vue中computed 和 watch的异同
2017/06/30 Javascript
深入理解Vue 的条件渲染和列表渲染
2017/09/01 Javascript
arcgis for js栅格图层叠加(Raster Layer)问题
2017/11/22 Javascript
js正则表达式校验指定字符串的方法
2018/07/23 Javascript
深入了解响应式React Native Echarts组件
2019/05/29 Javascript
微信小程序如何访问公众号文章
2019/07/08 Javascript
ionic3双击返回退出应用的方法
2019/09/17 Javascript
js计时事件实现圆形时钟
2020/03/25 Javascript
vue 实现tab切换保持数据状态
2020/07/21 Javascript
Python模拟浏览器上传文件脚本的方法(Multipart/form-data格式)
2018/10/22 Python
Django REST framework视图的用法
2019/01/16 Python
Pandas之ReIndex重新索引的实现
2019/06/25 Python
pandas删除行删除列增加行增加列的实现
2019/07/06 Python
python3字符串操作总结
2019/07/24 Python
pytorch torch.nn.AdaptiveAvgPool2d()自适应平均池化函数详解
2020/01/03 Python
详解CSS3开启硬件加速的使用和坑
2017/08/21 HTML / CSS
澳大利亚在线时尚精品店:Hello Molly
2018/02/26 全球购物
Myholidays美国:在线旅游网站
2019/08/16 全球购物
乌克兰巴士票购买网站:inBus
2021/03/12 全球购物
求职意向书
2014/04/01 职场文书
大学生应聘导游自荐信
2014/06/02 职场文书
副主任竞聘演讲稿
2014/08/18 职场文书
会议接待欢迎词范文
2015/01/26 职场文书
2016年劳模先进事迹材料
2016/02/25 职场文书
基于HTML十秒做出淘宝页面
2021/10/24 HTML / CSS
世界十大儿童漫画书排名,法国国宝漫画排第五,第二是轰动日本连环
2022/03/18 欧美动漫