必须用htmlspecialchars($input, ENT_QUOTES, 'UTF-8')转义用户输入后再输出。它将、&、"、'转为HTML实体,防止XSS攻击,且ENT_QUOTES确保单双引号均被转义,UTF-8避免多字节截断漏洞。

直接输出用户输入的内容到 HTML 页面,不加处理,就是 XSS 漏洞的温床。最可靠、最轻量、最通用的做法是:在 echo 前用 htmlspecialchars() 转义,且必须指定 ENT_QUOTES 和 UTF-8 参数。
什么时候必须用 htmlspecialchars()
只要变量内容会直接插入 HTML 文本流(比如 <div><?php echo $user_input; ?></div>),就必须过一遍 htmlspecialchars()。这包括:
- 输出
$_GET、$_POST、$_COOKIE中的任意值 - 从数据库读出后直接渲染到页面的字段(如用户昵称、评论内容)
- 拼接进 HTML 属性值时(
<a href="...<?php%20echo%20%24url;%20?>"></a>)
别信“我只显示纯文字”,攻击者可以提交 <img src="x" onerror="alert(1)" alt="PHP怎样防止跨站脚本攻击_PHP防止跨站脚本攻击方法【安全】" > 这类 payload,浏览器照样解析执行。
htmlspecialchars() 的三个关键参数不能省
默认调用 htmlspecialchars($str) 是危险的——它不处理单引号,也不声明编码,容易被绕过。必须显式传参:
立即学习“PHP免费学习笔记(深入)”;
-
ENT_QUOTES:同时转义双引号和单引号,防止闭合属性(如title="<?php echo $x; ?>") -
UTF-8:明确指定编码,避免多字节截断漏洞(尤其对中文等非 ASCII 字符) - 第三个参数(字符集)必须写,不能依赖默认值;PHP 8.1+ 默认是
UTF-8,但老版本不是
正确写法:htmlspecialchars($input, ENT_QUOTES, 'UTF-8')。漏掉任一参数,都可能让绕过变得简单。
不要用 strip_tags() 替代转义
strip_tags() 只删标签,不处理属性里的 JS 事件(如 <div onclick="alert(1)">),也不防 <code><svg onload="alert(1)"></svg> 这类 SVG 向量 XSS。更糟的是,它可能留下危险的属性值,比如 javascript:alert(1) 在 href 中。
还有人用正则自己“过滤 script 标签”——这种黑盒清洗不可靠,已知有数十种绕过方式。XSS 防御不是删除恶意字符串,而是确保输出上下文安全。HTML 输出就用 htmlspecialchars(),JS 上下文就用 JSON 编码 + json_encode($val, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS)。
模板引擎里也得手动转义?
Twig、Blade 等现代模板引擎默认开启自动转义,但有两个坑:
- 显式标记
{{ value|raw }}或{!! $value !!}会跳过转义——除非你 100% 确认该变量不含用户输入,否则禁用 - 变量插进 JS 字符串或 CSS 属性时(如
var name = "{{ $name }}";),模板引擎的 HTML 转义无效,必须额外用json_encode()包一层
哪怕用了模板引擎,也要检查每个动态插入点的实际输出上下文。HTML、JS、CSS、URL、XML,各自有各自的编码规则,混用等于开门揖盗。
真正难的不是记住函数名,而是养成「所有动态内容输出前必问上下文」的习惯。一次漏判,整个页面就可能沦为 XSS 攻击的跳板。



















