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="{{ $url }}">→ 若$url含" onclick=...,直接触发 JS -
<script>var name = "{{ $name }}";</script>→$name中的"或\会破坏字符串结构 -
<script>var data = {{ $json }};</script>→ 必须确保$json是合法 JSON 字符串,且已做双重编码
按上下文选对编码方式,不是靠一个函数打天下
不同 HTML/JS/CSS/URL 场景需匹配对应的安全输出方式:
-
HTML 文本内容(如 <p>、<div>):继续用
{{ $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=...> 等绕过手法。
正确做法是引入白名单过滤库:
- Laravel 10.x 推荐使用
spatie/laravel-html-sanitizer,配置允许的标签与属性(如只允<p><strong><ul><li>) - 初始化后,在模型访问器或控制器中统一处理:
$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(可自定义命令)扫描调试配置残留


















