基于Python实现一个专业的密码强度检测器
作者:零日失眠者
这篇文章主要为大家详细介绍了基于Python实现一个专业的密码强度检测器,可以用于评估密码的安全性和强度,感兴趣的小伙伴可以跟随小编一起学习一下
功能介绍
这是一个专业的密码强度检测工具,用于评估密码的安全性和强度。该工具具备以下核心功能:
多维度强度评估:
- 长度检测(密码长度要求)
- 字符类型检测(大小写字母、数字、特殊字符)
- 字典攻击防护(常见密码和弱密码检测)
- 模式识别(键盘序列、重复字符等)
- 熵值计算(密码随机性评估)
详细评分系统:
- 综合评分机制(0-100分制)
- 分项评分展示(长度、复杂度、模式等)
- 强度等级划分(弱、中、强、 very strong)
- 改进建议提供
自定义策略支持:
- 可配置的密码策略
- 自定义评分权重
- 特定行业标准支持(如NIST、PCI DSS等)
- 黑名单词汇库
批量检测功能:
- 支持批量密码检测
- 密码文件批量分析
- 检测结果统计报告
- 弱密码列表导出
安全防护机制:
- 内存安全处理(避免密码明文存储)
- 输入安全验证
- 防止暴力 破解保护
- 安全日志记录
场景应用
1. 系统管理员使用
- 检查用户账户密码强度
- 定期审计系统密码安全性
- 识别弱密码账户并强制更换
- 制定和执行密码策略
2. 开发者集成
- 集成到用户注册和密码修改流程
- 实时密码强度提示
- 密码策略验证
- 用户体验优化
3. 安全审计
- 企业密码安全评估
- 合规性检查(等保、ISO 27001等)
- 渗透测试中的密码分析
- 安全培训和意识提升
4. 个人用户
- 检查个人账户密码安全性
- 创建更强的密码
- 密码管理器集成
- 安全意识教育
报错处理
1. 输入验证异常
try:
password = input("请输入密码: ")
if not password:
raise PasswordValidationError("密码不能为空")
if len(password) > MAX_PASSWORD_LENGTH:
raise PasswordValidationError(f"密码长度不能超过 {MAX_PASSWORD_LENGTH} 个字符")
except PasswordValidationError as e:
logger.error(f"密码输入验证失败: {str(e)}")
raise PasswordSecurityError(f"输入错误: {str(e)}")
2. 文件操作异常
try:
with open(password_file, 'r', encoding='utf-8') as f:
passwords = f.readlines()
except FileNotFoundError:
logger.error(f"密码文件不存在: {password_file}")
raise PasswordSecurityError(f"文件未找到: {password_file}")
except PermissionError:
logger.error(f"无权限访问密码文件: {password_file}")
raise PasswordSecurityError(f"文件访问权限不足: {password_file}")
3. 内存安全异常
try:
# 安全清除密码变量
password = None
del password
except Exception as e:
logger.warning(f"内存清理失败: {str(e)}")
4. 配置文件异常
try:
with open(config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
except json.JSONDecodeError as e:
logger.error(f"配置文件格式错误: {str(e)}")
raise PasswordSecurityError(f"配置文件无效: {str(e)}")
except FileNotFoundError:
logger.warning("配置文件不存在,使用默认配置")
config = DEFAULT_CONFIG
代码实现
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
密码强度检测器
功能:评估密码的安全性和强度
作者:Cline
版本:1.0
"""
import argparse
import sys
import json
import logging
import os
import re
import math
from datetime import datetime
from typing import Dict, List, Tuple, Optional
import hashlib
import secrets
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('password_checker.log'),
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger(__name__)
class PasswordSecurityError(Exception):
"""密码安全异常类"""
pass
class PasswordValidationError(Exception):
"""密码验证异常类"""
pass
class PasswordStrengthChecker:
def __init__(self, config: Dict[str, any] = None):
# 默认配置
self.default_config = {
"min_length": 8,
"max_length": 128,
"require_uppercase": True,
"require_lowercase": True,
"require_digits": True,
"require_special_chars": True,
"min_special_chars": 1,
"blacklist_words": [
"password", "123456", "qwerty", "admin", "welcome",
"login", "root", "guest", "user", "test"
],
"keyboard_patterns": [
"qwerty", "asdf", "zxcv", "1234", "abcd"
],
"scoring_weights": {
"length": 0.3,
"complexity": 0.4,
"patterns": 0.2,
"entropy": 0.1
}
}
# 合并配置
self.config = {**self.default_config, **(config or {})}
# 特殊字符集合
self.special_chars = "!@#$%^&*()_+-=[]{}|;:,.<>?"
# 检测结果统计
self.stats = {
"total_checked": 0,
"strong_passwords": 0,
"medium_passwords": 0,
"weak_passwords": 0,
"very_weak_passwords": 0
}
def calculate_entropy(self, password: str) -> float:
"""计算密码熵值"""
if not password:
return 0.0
# 计算字符集大小
charset_size = 0
if re.search(r'[a-z]', password):
charset_size += 26
if re.search(r'[A-Z]', password):
charset_size += 26
if re.search(r'[0-9]', password):
charset_size += 10
if re.search(r'[^a-zA-Z0-9]', password):
charset_size += len(self.special_chars)
# 计算熵值
if charset_size > 0:
entropy = len(password) * math.log2(charset_size)
return min(entropy, 100.0) # 限制最大值
return 0.0
def check_length(self, password: str) -> Tuple[int, str]:
"""检查密码长度"""
length = len(password)
min_len = self.config["min_length"]
max_len = self.config["max_length"]
if length < min_len:
return 0, f"密码长度不足,至少需要 {min_len} 个字符"
elif length > max_len:
return 0, f"密码长度过长,最多允许 {max_len} 个字符"
else:
# 长度评分(线性增长)
score = min(100, (length / max_len) * 100)
return int(score), f"密码长度合适 ({length} 个字符)"
def check_complexity(self, password: str) -> Tuple[int, str]:
"""检查密码复杂度"""
score = 0
feedback = []
# 检查小写字母
if re.search(r'[a-z]', password):
score += 25
elif self.config["require_lowercase"]:
feedback.append("缺少小写字母")
# 检查大写字母
if re.search(r'[A-Z]', password):
score += 25
elif self.config["require_uppercase"]:
feedback.append("缺少大写字母")
# 检查数字
if re.search(r'[0-9]', password):
score += 25
elif self.config["require_digits"]:
feedback.append("缺少数字")
# 检查特殊字符
special_count = len(re.findall(r'[^a-zA-Z0-9]', password))
if special_count >= self.config["min_special_chars"]:
score += 25
elif self.config["require_special_chars"]:
feedback.append(f"特殊字符不足,至少需要 {self.config['min_special_chars']} 个")
if not feedback:
feedback_msg = "字符类型齐全"
else:
feedback_msg = "、".join(feedback)
return score, feedback_msg
def check_patterns(self, password: str) -> Tuple[int, str]:
"""检查密码模式"""
score = 100
feedback = []
# 检查黑名单词汇
password_lower = password.lower()
for word in self.config["blacklist_words"]:
if word in password_lower:
score -= 30
feedback.append(f"包含常见弱密码词汇: {word}")
# 检查键盘序列
for pattern in self.config["keyboard_patterns"]:
if pattern in password_lower or pattern[::-1] in password_lower:
score -= 20
feedback.append(f"包含键盘序列: {pattern}")
# 检查重复字符
if re.search(r'(.)\1{2,}', password):
score -= 15
feedback.append("包含过多重复字符")
# 检查连续字符
consecutive_count = 0
for i in range(len(password) - 2):
if ord(password[i+1]) == ord(password[i]) + 1 and ord(password[i+2]) == ord(password[i]) + 2:
consecutive_count += 1
if consecutive_count > 0:
score -= 10 * consecutive_count
feedback.append(f"包含 {consecutive_count} 组连续字符")
# 确保分数不低于0
score = max(0, score)
if not feedback:
feedback_msg = "未发现明显模式问题"
else:
feedback_msg = "、".join(feedback)
return score, feedback_msg
def evaluate_password_strength(self, password: str) -> Dict[str, any]:
"""评估密码强度"""
if not password:
raise PasswordValidationError("密码不能为空")
# 基本验证
if len(password) > self.config["max_length"]:
raise PasswordValidationError(f"密码长度不能超过 {self.config['max_length']} 个字符")
# 各项检测
length_score, length_feedback = self.check_length(password)
complexity_score, complexity_feedback = self.check_complexity(password)
patterns_score, patterns_feedback = self.check_patterns(password)
entropy_score = self.calculate_entropy(password)
# 计算综合得分
weights = self.config["scoring_weights"]
total_score = (
length_score * weights["length"] +
complexity_score * weights["complexity"] +
patterns_score * weights["patterns"] +
entropy_score * weights["entropy"]
)
# 确定强度等级
if total_score >= 80:
strength_level = "very_strong"
strength_desc = "非常强"
elif total_score >= 60:
strength_level = "strong"
strength_desc = "强"
elif total_score >= 40:
strength_level = "medium"
strength_desc = "中等"
else:
strength_level = "weak"
strength_desc = "弱"
# 更新统计
self.stats["total_checked"] += 1
if strength_level == "very_strong":
self.stats["strong_passwords"] += 1
elif strength_level == "strong":
self.stats["strong_passwords"] += 1
elif strength_level == "medium":
self.stats["medium_passwords"] += 1
else:
self.stats["weak_passwords"] += 1
result = {
"password": self.mask_password(password),
"score": round(total_score, 2),
"strength_level": strength_level,
"strength_description": strength_desc,
"details": {
"length": {
"score": length_score,
"feedback": length_feedback
},
"complexity": {
"score": complexity_score,
"feedback": complexity_feedback
},
"patterns": {
"score": patterns_score,
"feedback": patterns_feedback
},
"entropy": {
"score": round(entropy_score, 2),
"bits": round(math.log2(len(password) or 1), 2) if password else 0
}
},
"recommendations": self.generate_recommendations(
length_score, complexity_score, patterns_score
),
"timestamp": datetime.now().isoformat()
}
return result
def mask_password(self, password: str) -> str:
"""掩码密码显示"""
if len(password) <= 4:
return "*" * len(password)
else:
return password[:2] + "*" * (len(password) - 4) + password[-2:]
def generate_recommendations(self, length_score: int, complexity_score: int, patterns_score: int) -> List[str]:
"""生成改进建议"""
recommendations = []
if length_score < 80:
recommendations.append("增加密码长度,建议至少12个字符")
if complexity_score < 80:
recommendations.append("使用更多类型的字符(大小写字母、数字、特殊符号)")
if patterns_score < 80:
recommendations.append("避免使用常见词汇、键盘序列和重复字符")
if not recommendations:
recommendations.append("密码强度良好,继续保持")
return recommendations
def check_password_list(self, passwords: List[str]) -> List[Dict[str, any]]:
"""批量检查密码列表"""
results = []
for i, password in enumerate(passwords):
try:
result = self.evaluate_password_strength(password.strip())
results.append(result)
logger.info(f"已检查第 {i+1} 个密码")
except Exception as e:
logger.error(f"检查第 {i+1} 个密码时出错: {str(e)}")
results.append({
"password": self.mask_password(password.strip()),
"error": str(e),
"timestamp": datetime.now().isoformat()
})
return results
def load_passwords_from_file(self, file_path: str) -> List[str]:
"""从文件加载密码列表"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
passwords = [line.strip() for line in f if line.strip()]
logger.info(f"从文件加载了 {len(passwords)} 个密码")
return passwords
except FileNotFoundError:
logger.error(f"密码文件不存在: {file_path}")
raise PasswordSecurityError(f"文件未找到: {file_path}")
except Exception as e:
logger.error(f"加载密码文件时出错: {str(e)}")
raise PasswordSecurityError(f"文件加载失败: {str(e)}")
def save_results(self, results: List[Dict[str, any]], output_file: str):
"""保存检测结果"""
try:
# 确保输出目录存在
output_dir = os.path.dirname(output_file) if os.path.dirname(output_file) else '.'
os.makedirs(output_dir, exist_ok=True)
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(results, f, indent=2, ensure_ascii=False)
logger.info(f"检测结果已保存到 {output_file}")
except Exception as e:
logger.error(f"保存检测结果时出错: {str(e)}")
raise PasswordSecurityError(f"结果保存失败: {str(e)}")
def generate_report(self, results: List[Dict[str, any]]) -> Dict[str, any]:
"""生成检测报告"""
weak_passwords = [r for r in results if r.get("strength_level") in ["weak", "very_weak"]]
medium_passwords = [r for r in results if r.get("strength_level") == "medium"]
strong_passwords = [r for r in results if r.get("strength_level") in ["strong", "very_strong"]]
report = {
"summary": {
"total_passwords": len(results),
"very_strong": len([r for r in results if r.get("strength_level") == "very_strong"]),
"strong": len([r for r in results if r.get("strength_level") == "strong"]),
"medium": len(medium_passwords),
"weak": len([r for r in results if r.get("strength_level") == "weak"]),
"very_weak": len([r for r in results if r.get("strength_level") == "very_weak"])
},
"statistics": self.stats,
"weak_passwords": weak_passwords[:10], # 只显示前10个弱密码
"recommendations": [
"定期更换密码",
"使用密码管理器生成和存储复杂密码",
"启用多因素认证",
"避免在多个账户使用相同密码"
],
"timestamp": datetime.now().isoformat()
}
return report
def print_result(self, result: Dict[str, any]):
"""打印检测结果"""
print("\n" + "="*60)
print("密码强度检测结果")
print("="*60)
print(f"密码: {result['password']}")
print(f"综合得分: {result['score']}/100")
print(f"强度等级: {result['strength_description']}")
print("-"*60)
print("详细分析:")
print(f" 长度检测: {result['details']['length']['score']}/100 - {result['details']['length']['feedback']}")
print(f" 复杂度检测: {result['details']['complexity']['score']}/100 - {result['details']['complexity']['feedback']}")
print(f" 模式检测: {result['details']['patterns']['score']}/100 - {result['details']['patterns']['feedback']}")
print(f" 熵值检测: {result['details']['entropy']['score']}/100 ({result['details']['entropy']['bits']} bits)")
print("-"*60)
print("改进建议:")
for i, rec in enumerate(result['recommendations'], 1):
print(f" {i}. {rec}")
print("="*60)
def print_report(self, report: Dict[str, any]):
"""打印检测报告"""
print("\n" + "="*60)
print("密码强度检测报告")
print("="*60)
print(f"检测时间: {report['timestamp']}")
print("-"*60)
print("统计摘要:")
print(f" 总密码数: {report['summary']['total_passwords']}")
print(f" 非常强: {report['summary']['very_strong']}")
print(f" 强: {report['summary']['strong']}")
print(f" 中等: {report['summary']['medium']}")
print(f" 弱: {report['summary']['weak']}")
print(f" 非常弱: {report['summary']['very_weak']}")
print("-"*60)
print("安全建议:")
for i, rec in enumerate(report['recommendations'], 1):
print(f" {i}. {rec}")
print("="*60)
def create_sample_config():
"""创建示例配置文件"""
sample_config = {
"min_length": 8,
"max_length": 128,
"require_uppercase": True,
"require_lowercase": True,
"require_digits": True,
"require_special_chars": True,
"min_special_chars": 1,
"blacklist_words": [
"password", "123456", "qwerty", "admin", "welcome",
"login", "root", "guest", "user", "test", "abc123"
],
"keyboard_patterns": [
"qwerty", "asdf", "zxcv", "1234", "abcd", "qwer"
],
"scoring_weights": {
"length": 0.3,
"complexity": 0.4,
"patterns": 0.2,
"entropy": 0.1
}
}
with open('password_checker_config.json', 'w', encoding='utf-8') as f:
json.dump(sample_config, f, indent=2, ensure_ascii=False)
logger.info("示例配置文件已创建: password_checker_config.json")
def generate_strong_password(length: int = 16) -> str:
"""生成强密码"""
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()"
password = ''.join(secrets.choice(alphabet) for _ in range(length))
return password
def main():
parser = argparse.ArgumentParser(description='密码强度检测器')
parser.add_argument('password', nargs='?', help='要检测的密码')
parser.add_argument('-f', '--file', help='包含密码列表的文件路径')
parser.add_argument('-o', '--output', help='输出结果文件路径')
parser.add_argument('-c', '--config', help='配置文件路径')
parser.add_argument('--generate', type=int, nargs='?', const=16, help='生成指定长度的强密码')
parser.add_argument('--sample-config', action='store_true', help='创建示例配置文件')
parser.add_argument('--interactive', action='store_true', help='交互式检测模式')
args = parser.parse_args()
if args.sample_config:
create_sample_config()
return
if args.generate:
password = generate_strong_password(args.generate)
print(f"生成的强密码: {password}")
return
# 加载配置
config = {}
if args.config and os.path.exists(args.config):
try:
with open(args.config, 'r', encoding='utf-8') as f:
config = json.load(f)
except Exception as e:
logger.error(f"加载配置文件失败: {str(e)}")
# 创建检测器实例
checker = PasswordStrengthChecker(config)
try:
if args.interactive:
# 交互式模式
while True:
try:
password = input("\n请输入要检测的密码 (输入 'quit' 退出): ")
if password.lower() == 'quit':
break
if not password:
continue
result = checker.evaluate_password_strength(password)
checker.print_result(result)
except KeyboardInterrupt:
print("\n退出交互模式")
break
except Exception as e:
logger.error(f"密码检测出错: {str(e)}")
elif args.file:
# 文件批量检测模式
passwords = checker.load_passwords_from_file(args.file)
results = checker.check_password_list(passwords)
# 保存结果
output_file = args.output or f"password_check_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
checker.save_results(results, output_file)
# 生成报告
report = checker.generate_report(results)
report_file = f"{output_file}.report.json"
with open(report_file, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=False)
logger.info(f"检测报告已保存到 {report_file}")
# 打印报告
checker.print_report(report)
elif args.password:
# 单密码检测模式
result = checker.evaluate_password_strength(args.password)
checker.print_result(result)
# 保存结果
if args.output:
checker.save_results([result], args.output)
else:
# 显示帮助信息
parser.print_help()
except KeyboardInterrupt:
logger.info("密码检测被用户中断")
sys.exit(1)
except PasswordSecurityError as e:
logger.error(f"密码安全错误: {str(e)}")
sys.exit(1)
except Exception as e:
logger.error(f"密码检测过程中发生未知错误: {str(e)}")
sys.exit(1)
if __name__ == '__main__':
main()
使用说明
1. 基本使用
# 检测单个密码 python password_checker.py "MyPassword123!" # 交互式检测模式 python password_checker.py --interactive # 生成强密码 python password_checker.py --generate python password_checker.py --generate 20 # 指定长度
2. 批量检测
# 从文件批量检测密码 python password_checker.py -f passwords.txt # 指定输出文件 python password_checker.py -f passwords.txt -o results.json
3. 配置文件使用
# 使用自定义配置文件 python password_checker.py "MyPassword123!" -c config.json # 创建示例配置文件 python password_checker.py --sample-config
配置文件示例
创建一个名为 config.json 的配置文件:
{
"min_length": 12,
"max_length": 128,
"require_uppercase": true,
"require_lowercase": true,
"require_digits": true,
"require_special_chars": true,
"min_special_chars": 2,
"blacklist_words": [
"password", "123456", "qwerty", "admin", "welcome",
"login", "root", "guest", "user", "test", "abc123",
"password123", "admin123"
],
"keyboard_patterns": [
"qwerty", "asdf", "zxcv", "1234", "abcd", "qwer",
"qazwsx", "plmokn"
],
"scoring_weights": {
"length": 0.25,
"complexity": 0.35,
"patterns": 0.25,
"entropy": 0.15
}
}
密码文件格式
创建一个名为 passwords.txt 的密码文件:
MyPassword123!
weakpassword
Admin123
qwerty123
StrongPass!@#456
testuser
SecurePassword2023$
password
12345678
MySecurePass99!
高级特性
1. 集成到应用程序
from password_checker import PasswordStrengthChecker
# 创建检测器实例
checker = PasswordStrengthChecker()
# 在用户注册时检查密码强度
def register_user(username, password):
try:
result = checker.evaluate_password_strength(password)
if result['strength_level'] in ['weak', 'very_weak']:
return False, "密码强度不足,请使用更强的密码"
return True, "密码强度合格"
except Exception as e:
return False, str(e)
2. 定期安全审计
# 每周日凌晨2点执行密码安全审计
0 2 * * 0 /usr/bin/python3 /path/to/password_checker.py -f /path/to/user_passwords.txt -o /var/log/password_audit.json
3. 企业级部署
# 企业级密码策略配置
enterprise_config = {
"min_length": 16,
"require_uppercase": True,
"require_lowercase": True,
"require_digits": True,
"require_special_chars": True,
"min_special_chars": 3,
"blacklist_words": ["companyname", "productname"], # 企业特定词汇
"scoring_weights": {
"length": 0.2,
"complexity": 0.4,
"patterns": 0.3,
"entropy": 0.1
}
}
checker = PasswordStrengthChecker(enterprise_config)
性能优化
1. 内存管理
- 安全清除密码变量避免内存残留
- 批量处理时分批加载避免内存溢出
- 使用生成器处理大数据集
2. 检测速度优化
- 预编译正则表达式提高匹配速度
- 缓存常见计算结果
- 并行处理多个密码检测
3. 错误处理优化
- 实现优雅的错误恢复机制
- 记录详细的检测日志便于问题追踪
- 提供友好的错误提示信息
安全考虑
1. 数据安全
- 密码在内存中安全处理,避免明文存储
- 输出结果中密码被适当掩码
- 配置文件权限合理设置
2. 系统安全
- 限制处理密码的数量和大小
- 实现处理超时机制
- 记录所有操作日志便于审计
3. 隐私保护
- 不收集用户密码信息
- 本地处理不上传任何数据
- 符合隐私保护法规要求
这个密码强度检测器是一个功能强大、安全可靠的安全工具,能够帮助用户和企业评估密码的安全性,提升整体网络安全水平。
以上就是基于Python实现一个专业的密码强度检测器的详细内容,更多关于Python密码强度检测器的资料请关注脚本之家其它相关文章!
