如何防止表单提交的HTML数据被当作脚本执行?
兄弟,你这碰到的是**存储型跨站脚本攻击(XSS)**的典型场景——用户提交的恶意脚本被存在服务器里,等你把这条记录展示到页面时,浏览器直接把它当成可执行代码跑了,自然就弹出alert了。要解决这个问题,核心原则只有一个:永远不要信任用户输入的任何内容,必须对用户提交的内容做HTML转义处理,把那些能被浏览器解析成HTML/JS的特殊字符,转换成纯文本形式的实体字符。
下面给你具体的解决步骤,从核心到额外防护都给你列清楚:
1. 后端做HTML转义(最关键,必须优先做)
不管你用什么后端语言,在把用户输入存入数据库之前,或者从数据库取出来渲染到页面之前,一定要把HTML特殊字符转成对应的实体:
<→<>→>"→"'→'&→&
给你几个常用语言的例子,直接抄就行:
- Python:用标准库的
html.escape(),不用装额外包import html user_submitted_content = "<script>alert('hello world')</script>" safe_content = html.escape(user_submitted_content) # 转义后结果: <script>alert('hello world')</script> - Node.js:可以用
he这个库(先npm安装),或者用框架自带的方法const he = require('he'); const userInput = "<script>alert('hello world')</script>"; const safeContent = he.encode(userInput); - PHP:直接用内置的
htmlspecialchars()函数,记得加参数$user_input = "<script>alert('hello world')</script>"; $safe_content = htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
转义之后的内容,浏览器就会把它当成普通文本显示,再也不会解析成脚本执行了。
2. 前端渲染时用安全的方式
如果你的前端用的是Vue、React这类框架,那恭喜你,框架默认就会帮你转义!比如Vue的{{ content }}、React的{content},都是自动把内容当成纯文本渲染的,不用额外操作。
但如果你用原生JS直接操作DOM,千万别用innerHTML!这玩意儿会直接解析HTML/JS,改用textContent或者innerText,它们只会把内容当成纯文本插入:
// 危险!会执行脚本 document.getElementById('record-content').innerHTML = userInput; // 安全!纯文本展示 document.getElementById('record-content').textContent = userInput;
要是你需要允许用户提交部分富文本(比如加粗、换行),那也不能直接用innerHTML,得用DOM净化库,比如DOMPurify,它会过滤掉所有恶意的脚本标签和属性,只保留安全的HTML:
import DOMPurify from 'dompurify'; const cleanContent = DOMPurify.sanitize(userSubmittedRichText); document.getElementById('rich-content').innerHTML = cleanContent;
3. 额外加一层防护:配置内容安全策略(CSP)
就算前面的防护都做了,也可以再加一层保险——通过HTTP响应头配置内容安全策略(CSP),限制浏览器只能执行哪些来源的脚本,比如只允许加载你自己域名下的脚本,禁止内联脚本执行。
比如在你的后端响应头里加这么一行:
Content-Security-Policy: default-src 'self'; script-src 'self'
这样就算有漏网的恶意脚本,浏览器也会直接阻止它运行,相当于给页面加了个安全防火墙。
总结一下:最核心的是后端对用户输入做HTML转义,再配合前端安全渲染和CSP配置,就能彻底解决这个问题,让用户提交的脚本只能以纯文本形式展示,再也不会被执行了。
内容的提问来源于stack exchange,提问作者bhpsh

