fix: harden cloud storage security
This commit is contained in:
@@ -292,8 +292,8 @@
|
||||
<div class="form-group">
|
||||
<label class="form-label">新密码</label>
|
||||
<input type="password" id="password" class="form-input"
|
||||
placeholder="请输入新密码" required minlength="6">
|
||||
<div class="password-hint">密码长度至少6位</div>
|
||||
placeholder="请输入新密码" required minlength="8" maxlength="128">
|
||||
<div class="password-hint">密码长度8-128位,且包含字母、数字、特殊字符中的至少两种</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@@ -347,6 +347,28 @@
|
||||
return url.searchParams.get(name);
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
const prefix = `${name}=`;
|
||||
const row = document.cookie
|
||||
.split('; ')
|
||||
.find(item => item.startsWith(prefix));
|
||||
return row ? decodeURIComponent(row.substring(prefix.length)) : '';
|
||||
}
|
||||
|
||||
async function ensureCsrfToken() {
|
||||
let token = getCookie('csrf_token');
|
||||
if (token) return token;
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/csrf-token', { credentials: 'include' });
|
||||
const data = await res.json().catch(() => ({}));
|
||||
token = data.csrfToken || data.token || getCookie('csrf_token');
|
||||
} catch (error) {
|
||||
console.warn('[CSRF] 获取 token 失败:', error.message);
|
||||
}
|
||||
return token || getCookie('csrf_token');
|
||||
}
|
||||
|
||||
// 显示指定区块
|
||||
function showSection(id) {
|
||||
['loading', 'error', 'form', 'success'].forEach(s => {
|
||||
@@ -363,6 +385,35 @@
|
||||
alert.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function validateAccountPassword(password) {
|
||||
const value = String(password || '');
|
||||
if (value.length < 8) {
|
||||
return { valid: false, message: '密码至少8个字符' };
|
||||
}
|
||||
if (value.length > 128) {
|
||||
return { valid: false, message: '密码不能超过128个字符' };
|
||||
}
|
||||
|
||||
const typeCount = [
|
||||
/[a-zA-Z]/.test(value),
|
||||
/[0-9]/.test(value),
|
||||
/[!@#$%^&*(),.?":{}|<>_\-+=\[\]\\\/`~]/.test(value)
|
||||
].filter(Boolean).length;
|
||||
if (typeCount < 2) {
|
||||
return { valid: false, message: '密码必须包含字母、数字、特殊字符中的至少两种' };
|
||||
}
|
||||
|
||||
const weakPasswords = [
|
||||
'password', '12345678', '123456789', 'qwerty123', 'admin123',
|
||||
'letmein', 'welcome', 'monkey', 'dragon', 'master'
|
||||
];
|
||||
if (weakPasswords.includes(value.toLowerCase())) {
|
||||
return { valid: false, message: '密码过于简单,请使用更复杂的密码' };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
// 验证token
|
||||
async function validateToken() {
|
||||
resetToken = getParam('resetToken') || getParam('token');
|
||||
@@ -373,6 +424,11 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const cleanUrl = new URL(window.location.href);
|
||||
cleanUrl.searchParams.delete('resetToken');
|
||||
cleanUrl.searchParams.delete('token');
|
||||
window.history.replaceState({}, document.title, cleanUrl.pathname + cleanUrl.search + cleanUrl.hash);
|
||||
|
||||
// Token存在,显示表单
|
||||
showSection('form');
|
||||
}
|
||||
@@ -386,8 +442,9 @@
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
|
||||
// 验证
|
||||
if (password.length < 6) {
|
||||
showFormAlert('error', '密码长度至少6位');
|
||||
const passwordCheck = validateAccountPassword(password);
|
||||
if (!passwordCheck.valid) {
|
||||
showFormAlert('error', passwordCheck.message);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -401,9 +458,14 @@
|
||||
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 处理中...';
|
||||
|
||||
try {
|
||||
const csrfToken = await ensureCsrfToken();
|
||||
const res = await fetch('/api/password/reset', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(csrfToken ? { 'X-CSRF-Token': csrfToken } : {})
|
||||
},
|
||||
body: JSON.stringify({
|
||||
token: resetToken,
|
||||
new_password: password
|
||||
|
||||
Reference in New Issue
Block a user