password_security_service.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. """
  2. 密码安全服务
  3. 提供密码强度检测和弱口令验证功能
  4. """
  5. import re
  6. from typing import List, Dict, Tuple
  7. from enum import Enum
  8. class PasswordStrength(Enum):
  9. """密码强度枚举"""
  10. WEAK = "weak"
  11. MEDIUM = "medium"
  12. STRONG = "strong"
  13. VERY_STRONG = "very_strong"
  14. class PasswordSecurityService:
  15. """密码安全服务类"""
  16. WEAK_PASSWORDS = [
  17. "123456", "12345678", "123456789", "1234567890",
  18. "password", "password123", "admin", "root", "user",
  19. "qwerty", "abc123", "letmein", "welcome", "monkey",
  20. "dragon", "baseball", "football", "soccer", "trustno1",
  21. "master", "hello", "login", "admin123", "password1",
  22. "123123", "111111", "888888", "000000", "qwerty123",
  23. "admin123", "user123", "pass123", "login123", "welcome1",
  24. "admin@123", "root@123", "user@123", "pass@123", "login@123",
  25. "123qwe", "qwe123", "abc123", "111222", "333444",
  26. "666777", "999888", "123321", "654321", "987654",
  27. "123abc", "abc123", "12345a", "a12345", "678901"
  28. ]
  29. # 常见密码模式
  30. COMMON_PATTERNS = [
  31. r'^\d{6,}$', # 纯数字,6位以上
  32. r'^[a-z]{6,}$', # 纯小写字母,6位以上
  33. r'^[A-Z]{6,}$', # 纯大写字母,6位以上
  34. r'^[a-zA-Z]{6,}$', # 纯字母,6位以上
  35. r'^[a-zA-Z0-9]{6,}$', # 字母+数字,6位以上
  36. r'^.{8,}$', # 任意字符,8位以上
  37. ]
  38. @staticmethod
  39. def check_password_strength(password: str) -> Tuple[PasswordStrength, List[str]]:
  40. """
  41. 检测密码强度
  42. Args:
  43. password: 要检测的密码
  44. Returns:
  45. Tuple[密码强度, 建议列表]
  46. """
  47. suggestions = []
  48. # 1. 检查密码长度
  49. if len(password) < 8:
  50. suggestions.append("密码长度至少8位")
  51. return PasswordStrength.WEAK, suggestions
  52. elif len(password) < 12:
  53. suggestions.append("建议密码长度至少12位")
  54. elif len(password) >= 16:
  55. suggestions.append("密码长度很好")
  56. # 2. 检查是否是弱口令
  57. if password.lower() in PasswordSecurityService.WEAK_PASSWORDS:
  58. suggestions.append("密码过于常见,容易被猜测")
  59. return PasswordStrength.WEAK, suggestions
  60. # 3. 检查常见模式
  61. has_common_pattern = False
  62. for pattern in PasswordSecurityService.COMMON_PATTERNS:
  63. if re.match(pattern, password):
  64. has_common_pattern = True
  65. break
  66. if has_common_pattern:
  67. suggestions.append("密码过于简单,建议使用更复杂的组合")
  68. # 4. 检查字符类型
  69. has_upper = any(c.isupper() for c in password)
  70. has_lower = any(c.islower() for c in password)
  71. has_digit = any(c.isdigit() for c in password)
  72. has_special = any(not c.isalnum() for c in password)
  73. type_count = sum([has_upper, has_lower, has_digit, has_special])
  74. if type_count < 3:
  75. suggestions.append("建议包含大小写字母、数字和特殊符号的组合")
  76. # 5. 检查连续字符
  77. if PasswordSecurityService._has_sequential_chars(password):
  78. suggestions.append("避免使用连续的字符序列")
  79. # 6. 检查重复字符
  80. if PasswordSecurityService._has_repeated_chars(password):
  81. suggestions.append("避免使用大量重复的字符")
  82. # 7. 综合评分
  83. score = 0
  84. # 长度评分
  85. if len(password) >= 16:
  86. score += 3
  87. elif len(password) >= 12:
  88. score += 2
  89. else:
  90. score += 1
  91. # 字符类型评分
  92. score += type_count
  93. # 特殊字符评分
  94. if has_special:
  95. score += 2
  96. # 综合判断强度
  97. if score >= 8:
  98. return PasswordStrength.VERY_STRONG, suggestions
  99. elif score >= 6:
  100. return PasswordStrength.STRONG, suggestions
  101. elif score >= 4:
  102. return PasswordStrength.MEDIUM, suggestions
  103. else:
  104. return PasswordStrength.WEAK, suggestions
  105. @staticmethod
  106. def is_password_weak(password: str) -> bool:
  107. """
  108. 检查密码是否为弱口令
  109. Args:
  110. password: 要检查的密码
  111. Returns:
  112. True 如果是弱口令,False 否则
  113. """
  114. strength, _ = PasswordSecurityService.check_password_strength(password)
  115. return strength == PasswordStrength.WEAK
  116. @staticmethod
  117. def validate_password_requirements(password: str) -> Tuple[bool, List[str]]:
  118. """
  119. 验证密码是否符合基本要求 (长度>=8,且包含大小写、数字、特殊符号中的至少两种)
  120. """
  121. errors = []
  122. # 1. 长度检查(保持至少 8 位的基础底线)
  123. if len(password) < 8:
  124. errors.append("密码长度至少8位")
  125. # 2. 统计密码包含的字符种类
  126. has_upper = any(c.isupper() for c in password)
  127. has_lower = any(c.islower() for c in password)
  128. has_digit = any(c.isdigit() for c in password)
  129. has_special = any(not c.isalnum() for c in password)
  130. # 算出包含了多少种类型 (True会当作1,False当作0)
  131. type_count = sum([has_upper, has_lower, has_digit, has_special])
  132. # 3. 核心修改:四大类中,只要满足 >= 2 种即可
  133. if type_count < 2:
  134. errors.append("密码必须包含大写字母、小写字母、数字、特殊符号中的至少两种组合")
  135. return len(errors) == 0, errors
  136. @staticmethod
  137. def _has_sequential_chars(password: str, min_length: int = 3) -> bool:
  138. """
  139. 检查是否包含连续字符
  140. Args:
  141. password: 密码
  142. min_length: 最小连续长度
  143. Returns:
  144. True 如果包含连续字符
  145. """
  146. for i in range(len(password) - min_length + 1):
  147. substring = password[i:i+min_length]
  148. # 检查数字连续
  149. if substring.isdigit():
  150. if all(ord(substring[j+1]) - ord(substring[j]) == 1 for j in range(len(substring)-1)):
  151. return True
  152. # 检查字母连续
  153. elif substring.isalpha():
  154. if all(ord(substring[j+1]) - ord(substring[j]) == 1 for j in range(len(substring)-1)):
  155. return True
  156. return False
  157. @staticmethod
  158. def _has_repeated_chars(password: str, max_repeats: int = 3) -> bool:
  159. """
  160. 检查是否包含重复字符
  161. Args:
  162. password: 密码
  163. max_repeats: 最大重复次数
  164. Returns:
  165. True 如果包含重复字符
  166. """
  167. for i in range(len(password)):
  168. if i + max_repeats <= len(password):
  169. char = password[i]
  170. if all(password[j] == char for j in range(i, i + max_repeats)):
  171. return True
  172. return False