很多网站在用户注册账号的时候为了保证账户的安全,都会自动检测用户密码的强度并给出提醒让用户设置一个相对安全的密码,你是不是很好奇这个密码强度检测是怎么开发的,原理又是怎样的,来吧,这个项目就教大家如何使用python实现一个简单的检测密码强度的库,只需要不到100行的代码即可实现,非常简单。
效果图
效果图从效果图可以看出,该检测器可以检测不同的密码强度并给出提示信息。
评测规则
说到密码强度,不用想也知道肯定是越长越复杂的密码强度越高,也就越安全。我们的任务就是把密码复杂度与强度
量化,然后用计算机语言表达出来。
密码复杂度很好定义,长度,大写字母,小写字母,数字和特殊符号,密码包含的特征越多也就越,强度也就越高。我们设置个等级来评测密码强度,分别是:terrible, simple, medium, strong。
不同的应用可能对密码强度的要求一样,我们引入最小长度(min_length)和最小特征数(mim_types)变成可配置选项。这样我们就可以检测密码包含的特征,特征与密码与密码之间的关系可以简单定义为:
特征数 | 强度 |
---|---|
小于最小长度 | terrible |
常用密码或有规则的密码 | simple |
没有达到最小特征数 | midum |
达到或超过最小特征数 | strong |
那么问题来了,如何定义常用密码呢? 万能的 Github 上已经有人建立了常用密码表:
下载该文件,即可待用。
代码实现
如何检查特征呢?很容易想到的就是正则表达式:
NUMBER = re.compile(r'[0-9]')
LOWER_CASE = re.compile(r'[a-z]')
UPPER_CASE = re.compile(r'[A-Z]')
OTHERS = re.compile(r'[^0-9a-zA-Z]')
为了方便重用,我们先使用 re 模块的 compile 方法编译了这些特征。我们要检查密码是否包含一个特征调用 re 的 search 方法就可以了。
我们定义一个类,管理密码强度相关的东西:
class Strength:
def __init__(self, valid, strength, message):
self.valid = valid
self.strength = strength
self.message = message
我们定义了关于强度的三个属性,是否是有效的密码(valid),强度(strength),友好的提示信息(message)。
检测密码是否是常用密码,我们只需检查密码是否在之前下载的10000个常用密码文件中:
def load_common_password():
words = []
with open('10k_most_common.txt', 'rb') as f:
for word in f.readlines():
words.append(word.strip())
return words
COMMON_WORDS = load_common_password()
有规则的密码可能是在按照键盘顺序随便敲的一行,如 adfghjkl, 又或者按照 ASCII 码顺序:
def is_regular(input):
reverse = input[::-1]
regular = ''.join(['qwertyuio', 'asdfghjkl', 'zxcvbnm'])
return input in regular or reverse in regular
def is_by_step(input):
delta = ord(input[1]) - ord(input[0])
for i in range(2, len(input)):
if ord(input[i]) - ord(input[i-1]) != delta:
return False
return True
接下来就是这个程序的核心了,检测密码的特殊,返回相应的强度:
class Password:
TERRIBLE = 0
SIMPLE = 1
MEDIUM = 2
STRONG = 3
@staticmethod
def is_regular(input):
reverse = input[::-1]
regular = ''.join(['qwertyuio', 'asdfghjkl', 'zxcvbnm'])
return input in regular or reverse in regular
@staticmethod
def is_by_step(input):
delta = ord(input[1]) - ord(input[0])
for i in range(2, len(input)):
if ord(input[i]) - ord(input[i-1]) != delta:
return False
return True
@staticmethod
def is_common(input):
return input in COMMON_WORDS
def __call__(self, input, min_length=6, min_types=3, level=STRONG):
if len(input) < min_length:
return Strength(False, 'terrible', '密码太短了')
if self.is_regular(input) or self.is_by_step(input):
return Strength(False, 'simple', '密码有规则')
if self.is_common(input):
return Strength(False, 'simple', '密码很常见')
types = 0
if NUMBER.search(input):
types += 1
if LOWER_CASE.search(input):
types += 1
if UPPER_CASE.search(input):
types += 1
if OTHERS.search(input):
types += 1
if types < 2:
return Strength(level <= self.SIMPLE, 'simple', '密码太简单了')
if types < min_types:
return Strength(level <= self.MEDIUM, 'medium', '密码不错,但还不够强')
return Strength(True, 'strong', '完美的密码')
password = Password()
这里我们使用了一个 Password 类打包了与密码检测相关的东西,并使用用了一个 Python 的魔法方法 call, 这样我们就可以像函数一样调用 Password 的实例 password 了。
完整代码 以及测试
关于该项目实现的完整代码以及测试代码,点击用100行代码写个密码强度检测器即可在线查看了。
当然至于为什么要写测试?很多时候你可能觉得你的程序没有测试也工作的好好的!这很大程度上是因为你的程序功能点太少,基本你可以通过手动测试它们。试想一下,如果你的程序有一千多个功能点,而很多功能之间又相互关联,也就是说你修改了程序个一个地方,很可能其它地方也跟着出错。如果你没有写测试,你得手动把程序跑一遍,多累啊!
所以需要些测试啊。
网友评论