一、源码分析
Django 发布的 1.4 版本中包含了一些安全方面的重要提升。其中一个是使用 PBKDF2 密码加密算法代替了 SHA1 。另外一个特性是你可以添加自己的密码加密方法。
Django 会使用你提供的第一个密码加密方法(在你的 setting.py 文件里要至少有一个方法)
1
2
3
4
5
6
7
|
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加密方式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
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中加入自定义的加密算法:
1
2
3
4
5
6
7
8
|
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是加盐的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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、修改认证方式
1
2
3
4
5
|
AUTHENTICATION_BACKENDS = ( 'framework.mybackend.MyBackend' , #新加 'django.contrib.auth.backends.ModelBackend' , 'guardian.backends.ObjectPermissionBackend' , ) |
4、再来看自定义的认证方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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自带的降低很多,但是需求就是这样的,必须满足。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/bocai_xiaodaidai/article/details/103872716