需求
- 校验原密码与数据库密码是否一致
- 新密码强度校验
- 密码复杂度: 至少包含大小写字母、至少包含数字、至少包含特殊字符(如 !@#$%^&*)、至少8个字符长度
- 不能与最近10个密码相同
- 不能与最近10个密码相似度超过25%
注意❗️ 所有涉及密码的敏感操作(如验证原密码、历史密码比对)都应由后端完成。前端仅能做 辅助性预校验,如复杂度、相似度校验,不能替代后端安全逻辑。
需求1校验原密码是否正确
因为前端无法访问数据库中的加密密码,如果后端返回明文或可逆加密的历史密码给前端用于比较,这是 严重的安全漏洞 ,所以应该由 用户输入旧密码 → 发送到后端 → 后端验证是否一致 如果不一致 → 返回错误码
需求2-1密码复杂度校验
javascript
function validatePasswordStrength(password) {
const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$/;
return regex.test(password);
}
if (!validatePasswordStrength(newPassword)) {
return 'PASSWD_SIMPLE=密码至少包含大小写字母、数字和特殊符号,至少8个字。';
}
需求2-2不能与最近10个密码相同
实际开发中应由后端实现。如果前端实现,需后端提供历史密码,且是加密后的,前端可以做一些简单比较。
javascript
function isNewPassEqualOld(newPass, historyPasswords) {
return historyPasswords.includes(newPass); // 或者 hash 比较
}
需求2-31不能与最近10个密码相似度超过25%
一、什么是密码相似度?
密码相似度 是指两个字符串之间在内容和结构上的相似程度。通常用一个百分比值来表示,0% 表示完全不同,100% 表示完全相同。
二、应用场景:
- 防止用户设置的新密码与最近使用的旧密码太像。
- 提高密码安全性,避免用户只是轻微修改旧密码(如
abc123
→abc124
)。 - 在修改密码时,系统要求"新密码不能与最近设置的10个密码相似度超过25%"。
三、判断密码相似度?
✅ 1. Levenshtein 编辑距离(适合短密码)
原理:
- 计算将一个字符串转换为另一个字符串所需的最少单字符编辑操作(插入、删除、替换)的数量。
- 距离越小,相似度越高。
ini
function levenshtein(s, t) {
const m = s.length;
const n = t.length;
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
for (let i = 0; i <= m; i++) dp[i][0] = i;
for (let j = 0; j <= n; j++) dp[0][j] = j;
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (s[i - 1] === t[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(
dp[i - 1][j] + 1, // 删除
dp[i][j - 1] + 1, // 插入
dp[i - 1][j - 1] + 1 // 替换
);
}
}
}
return dp[m][n];
}
// 相似度百分比(0~1)
function similarityPercentage(s1, s2) {
const longer = s1.length > s2.length ? s1 : s2;
const shorter = s1.length <= s2.length ? s1 : s2;
const distance = levenshtein(longer, shorter);
return 1 - distance / longer.length;
}
arduino
console.log(similarityPercentage("abc123", "abc124")); // 输出:0.833
✅ 2. Jaro-Winkler 相似度算法
原理:
- 主要用于比较姓名等短字符串。
- 注重字符顺序的匹配。
- 对于前缀相同的字符串,会给予额外加分。
使用第三方库 (推荐使用)
c
npm install string-similarity
javascript
import { compareTwoStrings } from 'string-similarity';
const similarity = compareTwoStrings("abc123", "abc124"); // 返回 0~1 的相似度
console.log(similarity); // 输出约 0.9167
总结
密码检查项分工,但为了安全起见:
- 与历史密码是否一致,应由后端处理
- 与历史密码相似度是否过高,推荐后端做
- 密码强度检查,前后端都做