laravel 10.x 默认 xss 防护仅覆盖 html 文本上下文,对属性值、js 字符串、json、url 及富文本等场景完全无效;必须按上下文选用 e()、json_encode()、urlencode() 或 htmlsanitizer,并禁用 app_debug。

Laravel 10.x 本身已内置基础 XSS 防护机制,但漏洞是否修复,不取决于框架版本新旧,而取决于开发者是否在每个输出上下文中做了正确处理。很多项目用着 Laravel 10.x,却因几处错误写法仍存在高危 XSS —— 尤其是绕过默认转义的场景。
Blade 默认转义只保 HTML 文本,别误以为“用了 {{ }} 就万事大吉”
Blade 对 {{ $var }} 自动调用 htmlspecialchars(),仅防护「插入到 HTML 文本内容」这一种情况。一旦变量出现在以下位置,默认转义完全失效:
-
<input value="{{ $userInput }}">→ 双引号闭合被绕过,可注入" onfocus=alert(1) autofocus -
<a href="%7B%7B%20%24url%20%7D%7D"></a>→ 若$url含" onclick=...,直接触发 JS -
<script>var name = "{{ $name }}";</script>→$name中的"或\会破坏字符串结构 -
<script>var data = {{ $json }};</script>→ 必须确保$json是合法 JSON 字符串,且已做双重编码
按上下文选对编码方式,不是靠一个函数打天下
不同 HTML/JS/CSS/URL 场景需匹配对应的安全输出方式:
- HTML 文本内容(如
、
):继续用{{ $var }}或{{ e($var) }}(二者等效)- HTML 属性值(如 value、href、class):必须手动
e($var),Blade 不自动二次转义属性内插值- JavaScript 字符串内:用
json_encode($var, JSON_UNESCAPED_UNICODE | JSON_HEX_APOS | JSON_HEX_QUOT),再包裹在单/双引号中- 内联 script 标签中传整个对象:推荐写法:
<script>var user = {!! json_encode($user, JSON_UNESCAPED_UNICODE | JSON_HEX_APOS | JSON_HEX_QUOT) !!};</script>- URL 查询参数:用
urlencode($param)或http_build_query(),而非e()富文本内容不能靠 strip_tags(),得用专业过滤器
用户提交的带格式内容(如后台编辑器、评论区)若需保留部分 HTML,绝对禁止用
{!! $html !!}+strip_tags()这类简单过滤。它无法防<img src="x" onerror="...">或<svg onload="..."></svg>等绕过手法。正确做法是引入白名单过滤库:
- Laravel 10.x 推荐使用
spatie/laravel-html-sanitizer,配置允许的标签与属性(如只允<p><strong><ul><li></ul></strong></p>) - 初始化后,在模型访问器或控制器中统一处理:
$cleanHtml = app(HtmlSanitizer::class)->sanitize($rawHtml); - 数据库存储前就净化,而不是渲染时才处理
别忽略调试模式这个“隐形炸弹”
Laravel 10.x 在
APP_DEBUG=true时,错误页面会暴露请求参数,并在 Blade 模板中使用未转义输出(如{!! $parameter !!})。攻击者可通过恶意 URL 触发 500 错误,让调试页执行脚本 —— 这类反射型 XSS 已在多个生产环境真实发生。务必做到:
- 生产环境
.env中强制设置APP_DEBUG=false - Nginx/Apache 配置禁止访问
.env和storage/logs/ - 上线前运行
php artisan env:debug-check(可自定义命令)扫描调试配置残留
- HTML 属性值(如 value、href、class):必须手动











