
HTML 表单本身不做过滤,必须靠 JavaScript 或后端
浏览器原生的 <form></form> 标签只是数据容器和提交通道,它不会自动清洗、转义或验证输入内容。所谓“过滤”,实际是开发者在提交前(前端)或接收后(后端)主动处理的过程。依赖 required、type="email" 这类属性只能做基础校验,不能替代过滤。
常见错误现象:onsubmit 里没 return false 或没调用 event.preventDefault(),导致表单绕过 JS 直接提交;或者只过滤了显示值(input.value),却忘了同步更新 textarea 的 innerHTML 或富文本编辑器的内容。
- 使用场景:用户昵称去空格和首尾不可见字符、评论内容移除 script 标签、搜索关键词截断超长字符串
- 参数差异:
String.prototype.trim()只去首尾空白;replace(/\s+/g, ' ')合并中间多余空格;replace(/]*>/g, '')简单删 HTML 标签(但不安全,仅作预处理) - 性能影响:对长文本做正则全局替换(如
replace(/<.>/g, '')</.>)可能卡顿,建议限制输入长度或分块处理
用 addEventListener 拦截 submit 事件再过滤最可靠
比直接写 onsubmit="return filter()" 更可控,也方便复用逻辑。关键是必须在事件处理函数里调用 event.preventDefault(),否则过滤完照样提交原始数据。
示例:
document.querySelector('form').addEventListener('submit', function(event) {
const input = document.getElementById('user-input');
// 过滤:去首尾空格 + 移除控制字符
input.value = input.value.trim().replace(/[\u0000-\u001f\u007f-\u009f]/g, '');
// 不加这句,上面的赋值就白做了
event.preventDefault();
this.submit(); // 提交干净后的数据
});
- 容易踩的坑:
input.value修改后,如果表单有其他监听input或change的逻辑,可能触发重复处理 - 兼容性影响:IE9+ 支持
addEventListener,旧项目需注意;submit事件在<button type="submit"></button>点击时也会触发,无需额外绑定 - 不要在过滤中直接修改
event.target.elements的引用,应操作 DOM 节点的value或textContent
后端才是过滤的最终防线,前端只是体验优化
任何前端过滤都能被绕过——禁用 JS、抓包重放、用 curl 提交原始数据。所以 req.body(Node.js)、$_POST(PHP)、request.form(Python Flask)拿到的永远要重新过滤。
【极品模板】出品的一款功能强大、安全性高、调用简单、扩展灵活的响应式多语言企业网站管理系统。 产品主要功能如下: 01、支持多语言扩展(独立内容表,可一键复制中文版数据) 02、支持一键修改后台路径; 03、杜绝常见弱口令,内置多种参数过滤、有效防范常见XSS; 04、支持文件分片上传功能,实现大文件轻松上传; 05、支持一键获取微信公众号文章(保存文章的图片到本地服务器); 06、支持一键
立即学习“前端免费学习笔记(深入)”;
使用场景:用户提交的 bio 字段含 <script></script>,前端已删,但攻击者用 Postman 发送原始 payload;或数据库字段长度限制为 50,前端没截断,后端必须兜底。
- 常见错误现象:后端只做
htmlspecialchars()就存库,但没限制长度、没检查编码(如 UTF-8 双字节截断漏洞) - 参数差异:PHP 的
filter_var($str, FILTER_SANITIZE_STRING)已废弃,应改用htmlspecialchars()+ 手动正则;Python 推荐用bleach.clean()处理富文本 - 性能影响:对每个字段都跑一遍复杂正则会拖慢请求,建议只对明确需要过滤的字段(如
content、nickname)处理,非敏感字段(如user_id)跳过
特殊输入控件要单独处理:textarea、contenteditable、富文本编辑器
<textarea></textarea> 的换行符是 \n,但提交时可能被服务端解析为 \r\n;contenteditable 元素的 innerHTML 可能含任意标签;而像 TinyMCE、Quill 这类编辑器返回的是 HTML 字符串,不是纯文本。
示例(Quill):
const quill = new Quill('#editor');
const html = quill.root.innerHTML; // 带标签
const text = quill.getText(); // 纯文本,适合摘要或搜索
// 过滤 HTML 必须用专门的 sanitizer,不能只靠 replace
- 容易踩的坑:把
innerHTML直接插进模板(XSS 风险);或对contenteditable元素只监听input事件,漏掉鼠标粘贴、右键菜单粘贴等路径 - 使用场景:论坛发帖支持格式但禁止 iframe;后台 CMS 编辑文章时自动清理 Word 粘贴残留样式
- 推荐方案:前端用
DOMPurify.sanitize(html),后端用bleach(Python)或jsdom+ 自定义规则(Node.js)
req.body 做的每一行清洗逻辑。很多人卡在“为什么前端明明过滤了,数据库里还是有 script 标签”,答案往往就藏在没拦住那个绕过页面的 curl 请求里。










