fix(static): 前端脚本识别 WAF 拦截响应并正确提示

- validation.js 新增 WafTip 公共检测:403 + 响应体含 blocked by WAF 双重特征,
  与 gateway 白名单拒绝的 403(JSON 错误消息)精确区分
- login/register/dnfs/view 各请求点在 JSON 解析前识别拦截,统一提示
  「请求被 WAF 安全规则拦截,请检查输入内容」
- 修复 dnfs getNode 被 WAF 拦截时落入 catch 误跳登录页的问题
- 验证码图片加载识别 403 拦截,alt 提示点击重试
- __view.html 补充引入 validation.js
This commit is contained in:
qing committed 2026-07-30 11:01:34 +08:00
1 parent 40175eddb5
commit 9765edac9b
6 files changed
+34 -1

No files matched your search

+1
View File
@@ -47,6 +47,7 @@
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">蜀ICP备2024107064号-2</a>
</footer>
<script src="js/validation.js"></script>
<script src="js/view.js"></script>
</body>
</html>
+10
View File
@@ -19,6 +19,11 @@ async function getNode(id) {
});
const responseText = await res.text();
// WAF 拦截:弹提示并中止,不能落入 catch(其会误跳登录页)
if (window.WafTip && WafTip.isBlocked(res, responseText)) {
alert(WafTip.MESSAGE);
return;
}
let result;
try {
@@ -78,6 +83,7 @@ async function addNode(pid, title, content) {
});
const responseText = await res.text();
if (window.WafTip && WafTip.isBlocked(res, responseText)) throw new Error(WafTip.MESSAGE);
let result;
try {
@@ -137,6 +143,7 @@ async function deleteNode(id) {
});
const responseText = await res.text();
if (window.WafTip && WafTip.isBlocked(res, responseText)) throw new Error(WafTip.MESSAGE);
let result;
try {
@@ -188,6 +195,7 @@ async function deleteChild(id) {
});
const responseText = await res.text();
if (window.WafTip && WafTip.isBlocked(res, responseText)) throw new Error(WafTip.MESSAGE);
let result;
try {
@@ -246,6 +254,7 @@ async function updateNode(id, pid, title, content) {
});
const responseText = await res.text();
if (window.WafTip && WafTip.isBlocked(res, responseText)) throw new Error(WafTip.MESSAGE);
let result;
try {
@@ -301,6 +310,7 @@ async function moveNode(id, pid, title, content) {
});
const responseText = await res.text();
if (window.WafTip && WafTip.isBlocked(res, responseText)) throw new Error(WafTip.MESSAGE);
let result;
try {
+6
View File
@@ -22,6 +22,11 @@ async function refreshCaptcha() {
captchaToken = '';
try {
const res = await fetch('/captcha/image', { cache: 'no-store' });
if (res.status === 403) { // WAF 拦截:body 非图片,提示后待用户点击重试
captchaImg.removeAttribute('src');
captchaImg.alt = '验证码加载被安全规则拦截,点击重试';
return;
}
if (!res.ok) throw new Error('captcha load failed');
captchaToken = res.headers.get('X-Captcha-Token') || '';
const blob = await res.blob();
@@ -126,6 +131,7 @@ form.addEventListener('submit', async function(e) {
body: jsonBody
});
const responseText = await res.text();
if (window.WafTip && WafTip.isBlocked(res, responseText)) throw new Error(WafTip.MESSAGE);
let result;
try { result = JSON.parse(responseText); } catch { throw new Error('服务器响应格式异常'); }
if (!res.ok) throw new Error(result.message || '登录失败');
+2
View File
@@ -143,6 +143,7 @@ getCodeButton.addEventListener('click', async function () {
});
httpStatus = res.status;
const responseText = await res.text();
if (window.WafTip && WafTip.isBlocked(res, responseText)) throw new Error(WafTip.MESSAGE);
let result;
try { result = JSON.parse(responseText); } catch { throw new Error('服务器响应格式异常'); }
if (!res.ok || !result.success) throw new Error(result.message || '验证码发送失败');
@@ -190,6 +191,7 @@ form.addEventListener('submit', async function (e) {
});
const responseText = await res.text();
if (window.WafTip && WafTip.isBlocked(res, responseText)) throw new Error(WafTip.MESSAGE);
let result;
try {
+12
View File
@@ -68,3 +68,15 @@
window.FormValidators = { username, password, email };
}());
/* WAF 拦截识别:waf 命中规则时返回 403 + 纯文本 "blocked by WAF"
* (见 waf/internal/proxy/proxy.go block());gateway 的 403(Target-Url
* 白名单拒绝)body 为 JSON 错误消息,不含此特征,不会误判。 */
window.WafTip = {
MESSAGE: '请求被 WAF 安全规则拦截,请检查输入内容',
isBlocked(res, responseText) {
return res.status === 403
&& typeof responseText === 'string'
&& responseText.indexOf('blocked by WAF') !== -1;
}
};
+3 -1
View File
@@ -138,7 +138,9 @@ async function loadData() {
try {
const url = `/api/filelist?path=${encodeURIComponent(currentPath)}`;
const res = await fetch(url);
const data = await res.json();
const responseText = await res.text();
if (window.WafTip && WafTip.isBlocked(res, responseText)) throw new Error(WafTip.MESSAGE);
const data = JSON.parse(responseText);
if (data.success) {
items = data.items || [];
render();