Django 密码与安全

Django 密码与安全

密码是一种用来混淆的技术(把用公开的、标准的信息编码表示的信息通过一种变换手段,将其变为除通信
双方以外其他人所不能读懂的信息编码)。就是将正常的(可识别的)信息转变为无法识别的信息。
但这种无法识别的信息部分是破解(密码泄漏)。

密码的设计需遵守 柯克霍夫原则

即使密码系统的任何细节已为人悉知,只要密匙(key,又称密钥或秘钥)未泄漏,它也应是安全的。

Django 如何存储密码?

User 对象的 password 属性是如下这种格式:

<algorithm>$<iterations>$<salt>$<hash>

包括:哈希算法 $ 算法迭代次数(在哈希上运行的次数)$ 随机 Salt $ 密码哈希值

Django 使用PASSWORD_HASHERS的设置来选择算法,PASSWORD_HASHERS是settings配置文件中的一个配置项,这是一个 Django 支持的哈希算法类列表,
第一个条目将被用来存储密码。如果你想使用不同算法,你需要修改 PASSWORD_HASHERS ,
在列表中首选列出你的算法

Django 密码与安全

注:Django 1.3版本及之前使用sha1算法加密用户密码, 存储格式为(<algorithm>$<salt>$<hash>):
Django 密码与安全
1.4及以后版本默认选择settings.PASSWORD_HASHERS[0]
作为加密用户密码的算法(默认为PBKDF2PasswordHasher(pbkdf2_sha256)), NIST (美国国家标准与技术研究院 ) 推荐的机制。存储格式为(<algorithm>$<iterations>$<salt>$<hash>):
Django 密码与安全

什么是PBKDF2?

PBKDF2算法通过多次hash来对密码进行加密。原理是通过password和salt进行hash,然后将结果作为salt在
与password进行hash,多次重复此过程,生成最终的密文。盐值的添加也会增加“彩虹表”攻击的难度,
此过程可能达到上千次,逆向破解的难度太大,破解一个密码的时间可能需要几百年,所以PBKDF2算法是安全的.**

Hasher该如何选择?

Django提供了很多的PASSWORD_HASHERS,Django自带的Hasher之间的对比如下:

Django 密码与安全

但并非所有都是推荐的,目前最为推荐的是默认的PBKDF2PasswordHasher,因为它足够安全。
同时对于一些易破解的加密算法,如:md5,sha1(因为可以通过 预计算哈希链集、彩虹表 破解)所以对于一些安全程度较低的加密算法,我们应该去做对应的升级。

Hasher 有哪些方法?

hasher提供的方法如下:

  • 密码加密 encode

  • 密码校验 verify

  • 更改迭代次数(iterations)的判断

    Hasher配置iterations次数与数据库密码的中的iterations次数做比较

  • 额外进行hash次数

Django 密码与安全

check_password之巧妙设计

1. 获取所需的hasher
2. 获取老密码的hasher
3. 是否需要强化算法,增加复杂度
4. 加密算法是否改变判断
5. 密码校验verify
7. 额外进行hash次数

(应用:比如想提高迭代次数提高密码安全性,
更改了Hasher的iterations数量,当检测到与数据库中的数量不一致,
则会额外进行iterations - int(数据库iterations) 次迭代)

6. 更改老的加密算法

(应用:用户登陆时,密码自动升级,只需调整PASSWORD_HASHERS顺序,如:sha1 -> pbkdf2_sha1)

Django 密码与安全

如何做系统的密码升级

如果公司要你升级密码系统要如何做?比如之前使用的sha1

用户登陆时,密码自动升级

只需调整PASSWORD_HASHERS顺序,如:sha1 -> pbkdf2_sha1,当用户之前的密码校验通过后

用户为登陆时,密码升级

如果数据库拥有老旧低效的哈希算法,比如 MD5 或 SHA1,那么你也许希望自己升级哈希而不是等待用户登录后
升级(如果一个用户不再登录站点,数据库一直是老密码,密码就不会升级了)
步骤:

   1. 取出数据库中用户密码,把此时加密的密码再进行一次加密,生成pbkdf2_wrapped_sha1的马甲密码, 此时数据库中的马甲密码格式为:pbkdf2_wrapped_sha256$216000$4YfO8YTUgTO9$xxxxxxx
   2. PASSWORD_HASHERS 中添加处理中间 PBKDF2WrappedSHA1PasswordHasher 类
   3. 当用户登陆时,走到PBKDF2WrappedSHA1PasswordHasher的encode方法,把密码也加密成马甲密码
   4. 然后执行密码校验,两次马甲密码一致,通过密码校验
   5. 触发登陆更改密码更改老的加密算法条件。密码改成:pbkdf2_sha256$216000$GS9f0OKOxxQE$xxxxxx

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K0EqSNDn-1624274177083)(http://share-images.chunyu.mobi//donghao/20210621190611.png)]

参考以下代码:

from django.contrib.auth import get_user_model
from django.core.management import BaseCommand
from django.contrib.auth.hashers import (
    PBKDF2PasswordHasher, SHA1PasswordHasher,
)
class PBKDF2WrappedSHA1PasswordHasher(PBKDF2PasswordHasher):
    algorithm = 'pbkdf2_wrapped_sha1'

    def encode_sha1_hash(self, sha1_hash, salt, iterations=None):
        return super().encode(sha1_hash, salt, iterations)

    def encode(self, password, salt, iterations=None):
        """
        用户 登陆时候的密码,要进行一次老的sha1 hash运算,然后进行转换成pbkdf2_sha256 hash密码
        """
        _, _, sha1_hash = SHA1PasswordHasher().encode(password, salt).split('$', 2)
        return self.encode_sha1_hash(sha1_hash, salt, iterations)


class Command(BaseCommand):
    def handle(self, *args, **options):
        """
        sha1密码升级 -> pbkdf2_sha1
        """
        User = get_user_model()
        users = User.objects.filter(password__startswith='sha1$')
        hasher = PBKDF2WrappedSHA1PasswordHasher()
        for user in users:
            algorithm, salt, sha1_hash = user.password.split('$', 2)
            user.password = hasher.encode_sha1_hash(sha1_hash, salt)
            user.save(update_fields=['password'])

Django 如何做密码校验?

内置的密码校验器

Django提供了可插入的密码验证。可以同时配置多个密码验证器。Django中包含一些验证器,也可非常简单的实现自定义验证器。
配置于在settings文件中的AUTH_PASSWORD_VALIDATORS。只用于 Django Admin、command指令创建、修改用户的密码

Django 密码与安全

提供的功能分别为:
Django 密码与安全

  • CommonPasswordValidator:通过与定义的一些普通的密码校验。common-passwords.txt 定义了近2w个普通密码。
  • NumericPasswordValidator:isdigit 进行数字判断
  • MinimumLengthValidator:len 进行长度比较
  • UserAttributeSimilarityValidator: 与需要对比的用户属性(如:username, email等)进行相似度检查, 使用的python的标准库 Difflib来做文本相似度检查。

三方包 django-password-validators

  • PasswordCharacterValidator
    指定至少包含的数字、字母、大小写数量等,提高密码安全性
    Django 密码与安全
  • UniquePasswordsValidator
    验证用户是否曾经使用过密码, 不能设置成前面设置过的密码n次(n>=0)

自定义密码校验器

需实现以下方法:

1.AUTH_PASSWORD_VALIDATORS 添加校验器Name(导入路径), OPTIONS (__init__方法参数)

2.类实现validate、get_help_text 方法

3.可以添加 password_changed 方法,会在密码修改成功后调用
上一篇:python3爬虫进阶JS逆向学习(十一)


下一篇:sha1和md5的区别?