htmlspecialchars() 是防御 XSS 最直接有效的方法,关键在输出到 HTML 时转义,需指定 ENT_QUOTES 和 UTF-8 编码;JSON 输出到 script 标签需用 json_encode 配合 HEX 标志。

用 htmlspecialchars() 转义输出内容是最直接有效的防线
XSS 的核心是「浏览器把用户输入当代码执行」,所以关键不在输入时拦住什么,而在输出到 HTML 时确保它被当成纯文本。只要在 最终拼入 HTML 的地方 使用 htmlspecialchars(),就能切断绝大多数反射型和存储型 XSS。
常见错误是只在入库前过滤一次,或用正则删标签——这既不彻底(绕过方式太多),又可能破坏正常内容(比如用户想发 )。echo "hello"
- 必须指定
ENT_QUOTES和字符编码,例如:htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, 'UTF-8') - 不要省略第三个参数(编码),PHP 7.4+ 默认用
ini_get('default_charset'),但显式声明更可靠 - 对 JSON 输出到内联
的场景,不能只靠htmlspecialchars(),需配合json_encode($data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT)
哪些地方必须加转义?别漏掉这些输出点
很多人只记得 ,但 XSS 可发生在任何 HTML 上下文里,不同位置需要不同处理方式:
- HTML 文本内容(如
)→ 用htmlspecialchars() - HTML 属性值(如
)→ 同样用htmlspecialchars(),且属性必须用双引号包裹 - JavaScript 字符串(如
)→ 必须用json_encode(),不是addslashes()或htmlspecialchars() - CSS 内联样式(如 )→ 不建议动态插值;若必须,先校验是否为合法颜色值(如匹配
/^#([0-9A-F]{3}){1,2}$/i),再输出过滤输入不如校验上下文,
filter_var()适合特定字段对邮箱、URL、整数等有明确格式的字段,输入时用
filter_var()做白名单校验比模糊过滤更安全:立即学习“PHP免费学习笔记(深入)”;
-
filter_var($email, FILTER_VALIDATE_EMAIL)→ 验证后可放心用于mailto:链接 -
filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED)→ 防止javascript:伪协议 -
filter_var($id, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]])→ 确保是正整数,避免 SQL 注入或路径遍历连带风险
但注意:
filter_var($html, FILTER_SANITIZE_STRING)在 PHP 8.1+ 已被移除,且历史版本也不推荐——它会删标签但不清空属性中的 JS 事件(如onerror),反而造成假安全感。模板引擎和框架自带防护容易被绕过
Laravel Blade、Twig、Smarty 默认开启自动转义,但开发者常因「显示不了富文本」而随手加
|raw或{{!! $content !!}},这就等于主动打开 XSS 大门。如果真要渲染可信 HTML(如 CMS 后台编辑器内容),必须:
- 使用专用库如
HTMLPurifier,配置严格白名单(只允许p,strong,a[href]等) - 禁止所有事件属性(
onclick,onload)、style属性、javascript:协议 - 绝对不要把用户输入拼进
或标签内部
最易被忽略的是:JSON 数据嵌入 HTML 的方式。写成
看似安全,但如果$arr里含未转义的 HTML 实体或换行,仍可能闭合标签或注入语句——务必用JSON_HEX_*标志位。 -











