防XSS关键在输出时上下文敏感转义,HTML中用htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8'),JS中用json_encode(),富文本须用DOMDocument或HTMLPurifier白名单净化。

PHP 表单本身不防 XSS,关键在输出时是否对用户输入做了上下文敏感的转义——输入过滤(如 strip_tags() 或正则替换)不能替代输出转义,反而可能破坏数据或留漏洞。
所有用户输入都必须在输出时做 htmlspecialchars()
这是防反射型 XSS 最有效、最轻量的方式。它只在 HTML 上下文中起作用,且必须指定正确的参数:
-
htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8')是推荐写法,ENT_QUOTES确保单双引号都被转义,ENT_HTML5适配现代 HTML 解析器 - 绝对不要省略第三个参数(字符编码),否则在非 UTF-8 页面中可能被绕过
- 不要用
htmlentities()替代——它会过度编码中文等字符,且默认编码行为不明确 - 如果输出到 JavaScript 字符串内(比如
),htmlspecialchars()不够,需用json_encode($input, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG)并包裹单引号
别用 filter_var($input, FILTER_SANITIZE_STRING)
这个函数在 PHP 8.1 中已被移除,且历史上行为不稳定:它依赖 default_filter 配置,不处理属性上下文,还可能删掉合法 HTML 标签内容。常见误用场景:
-
表单提交后直接
filter_var($_POST['name'], FILTER_SANITIZE_STRING)再存库 → 实际没解决输出 XSS,还让数据失真 - 以为“过滤一次就安全了”,结果在 JS 或 CSS 上下文中直接拼接,照样触发 XSS
- 用它处理富文本输入(如允许部分
)→ 它无法做白名单过滤,只会粗暴删标签
需要保留格式?用 HTML 白名单 + DOMDocument 或专用库
如果业务真要支持有限 HTML(如后台编辑器),必须走解析-重建路线,不能靠正则或简单替换:
立即学习“PHP免费学习笔记(深入)”;
- 用
DOMDocument加载 HTML,遍历节点,只保留whitelist中的标签(如['b','i','p','br'])和属性(如class),其余全删 - 更稳妥选
HTMLPurifier库——它内置大量上下文规则(如href中过滤javascript:)、支持自定义策略,但体积大、性能略低 - 绝对不要用
strip_tags($input, $allowed)做净化——它不解析嵌套结构,这类变形可绕过ipt>alert(1)
XSS 防御的核心不是“怎么过滤输入”,而是“在哪、以什么方式输出”。同一个字符串,在 HTML 文本、HTML 属性、JS 字符串、CSS 值、URL 参数里,转义方式完全不同。漏掉任一上下文,前面所有过滤都白做。











