跳到正文
>_ITDITDWeb 安全平台

按框架

Laravel 安全 — 生产环境加固参考手册

一份 Laravel 生产环境加固参考:按优先级排序的清单、危险的默认设置,以及从密钥、配置到授权、依赖 CVE 的分领域指南,外加一份自查清单。以防御视角讲解,不含攻击步骤。

发布于 2026-07-02 更新于 2026-07-02 4 分钟阅读

适用对象:任何在生产环境运行 Laravel 的人。这里不讲攻击步骤——这是一份可直接照做的加固参考:按优先级排序的清单、危险的默认设置、分领域指南,以及自查。关于跨框架的整体图景,参见 按框架的安全防护入口

按优先级排序的加固清单

从上到下照做这张表。P0 是其余一切的前提,P1 是最频繁的事故来源,P2 是持续的运营卫生。

P0 ── 前提(先做)

生产环境关调试 / 密钥以权限 600 远离公开面 / 管理 APP_KEY

P1 ── 首要事故来源

授权(Policy/Gate)/ Mass Assignment 控制 / 依赖 CVE / 生产环境缓存

P2 ── 运营卫生

会话/CSRF/Cookie / 上传校验 / HTTPS、响应头、限流

从地基往上加固:P0(前提)→ P1(首要事故来源)→ P2(运营卫生)。
优先级控制项具体做法(Laravel)
P0关闭生产环境调试APP_DEBUG=false / APP_ENV=production,用 config:cache 固定。别在错误页上泄露内部信息
P0密钥远离公开面.env、备份、密钥放在 public/ 之外,权限 600。storage/logs 不公开
P0妥善管理 APP_KEY是加密、签名 Cookie、会话的基础。从环境变量注入;泄露时轮换
P1显式授权Policy / Gate + authorize() / can 中间件,按所有者/权限划定范围
P1控制 Mass Assignment声明 $fillable;避免批量赋值 $request->all(),改用 validated()
P1监控 Composer CVEcomposer audit / osv-scanner;按运行中的版本判断,快速打补丁
P1生产环境缓存config:cache route:cache view:cache,让设置可靠生效并提速
P2会话/Cookie 安全设置 secure http_only same_site;登录时重新生成会话
P2上传校验校验类型/大小,存放在 public/ 之外,无执行权限
P2HTTPS/响应头/限流强制 HTTPS、HSTS,在登录/API 上加 throttle

1. 密钥与 APP_KEY(P0)

Laravel 默认把 .env 放在文档根之外(在项目根目录)。事故大多来自把密钥放到了它们不该在的地方。

  • 绝不要把 .env、数据库导出、备份或密钥文件放进 public/。密钥要放在应用根之外,权限 600(仅所有者可读)。
  • 别暴露 storage/storage/logs/(日志里可能含密钥或个人数据)。别把 .env 提交到仓库。
  • APP_KEY 是加密、签名 URL、加密 Cookie 和会话的基础。从环境变量注入它,并在泄露时立即轮换(注意这会使既有的加密数据/会话失效)。

关于通用原则,参见 不把密钥放进公开目录;关于一个真实的全暴露案例,参见 一个 .env 全暴露的案例

2. 生产配置:DEBUG、环境、缓存(P0)

1

APP_DEBUG=false / APP_ENV=production

在生产环境关闭调试。开着时,异常页面会泄露环境变量和连接信息,可通过故意触发错误被抽取。
2

用缓存固定配置

php artisan config:cache(+ route:cache view:cache)让设置可靠生效并加速应用。注意:config:cache 之后,config/ 之外的 env() 会返回 null,所以在应用中要通过 config('...') 引用值。
3

别在生产环境暴露诊断工具

在生产环境禁用 Telescope / Horizon / Debugbar 或对其做访问限制。让详细错误和堆栈跟踪远离公开面。

3. 授权:Broken Access Control(P1 — 首要来源)

生产环境最常见的事故是“已认证但未授权”。能登录并不意味着被允许执行该操作。

常见(危险)

  • 没有授权——“登录了=能看/能改”
  • route-model 绑定取到了别的用户的 ID
  • Model::create($request->all()) 接受每一个字段
  • is_admin 这样的权限字段由用户输入赋值

正确

  • Policy / Gate + authorize() / can 中间件,每次都按所有者/权限划定范围
  • 读取也按所有者划定范围(例如 where('user_id', $me)
  • $request->validated()(FormRequest)限制输入
  • 声明 $fillable 以拦截 Mass Assignment

参见 IDOR 是什么。关键是在每一条读取/更新/删除路径上都做所有者检查。

4. 注入与输出

Laravel 的 Eloquent/查询构造器用占位符绑定值,Blade 默认对输出转义。规则是别自己把这份安全性关掉。

  • SQL:别通过字符串拼接把用户输入混进 whereRaw / DB::raw。即便确实需要原生 SQL,也要用绑定(→ SQL 注入是什么)。
  • XSS:Blade {{ }} 会转义;{!! !!}原始输出。别把用户输入传给 {!! !!}。若必须输出 HTML,只在净化之后(→ XSS 是什么)。
  • 校验:在使用前用 FormRequest / validate() 校验类型/范围/允许值。

5. 会话、CSRF、Cookie(P2)

  • CSRF:别全局禁用 web 中间件的 CSRF 保护。表单里用 @csrf,SPA 用恰当的令牌处理(→ CSRF 是什么)。
  • Cookie/会话:在 config/session.php 里设置 secure(HTTPS)、http_onlysame_site登录时重新生成会话以防固定攻击(Laravel 的认证会重新生成)。
  • 暴力破解:对登录施加 throttle / 登录尝试次数限制。

6. 文件上传与公开文件(P2)

  • 校验 mime 类型、扩展名和大小,并且别信任客户端提供的文件名
  • 存放在 public/ 之外(例如 storage/),且无执行权限。只对确实需要公开的内容,通过受控路径提供。
  • 交付时也做授权,这样连续的直链就无法取到别的用户的文件。

7. HTTPS、安全响应头、限流(P2)

  • 强制 HTTPSURL::forceScheme('https') 等)+ HSTS。在负载均衡器后面,用 TrustProxies 以正确识别协议。
  • 安全响应头(X-Content-Type-Options 等;围绕你的资源设置来设计 CSP)。用 安全响应头检查器 检查你自己的站点。
  • 限流:对登录、API 和密码重置施加 throttle

8. 依赖与版本(P1)

  • composer audit 或 osv-scanner 监控 Composer 依赖 CVE按运行中的版本判断,并快速打补丁(→ 监控依赖 CVE · 漏洞应对实务手册)。
  • Laravel 和 PHP 保持在受支持的版本。别把 EOL 版本留着(无法修复的漏洞会累积)。

验证:你的 Laravel 真的加固了吗?

搭好并不是终点——只有在你检查过之后才算完成。这些是针对你自己的站点/环境的防御性自查。

1

密钥无法通过 URL 取得

在你自己的域名上,访问 /.env/storage/logs/laravel.log,确认它们返回 404(若能取得,立即修复并轮换密钥)。
2

生产环境无调试暴露

触发一个错误(例如一个不存在的路由),确认显示的是通用错误页——没有环境变量或堆栈跟踪。
3

授权成立

在测试环境中,请求别的用户的资源 ID,确认它被拒绝(在读取、更新和删除路径上都要)。
4

Cookie/会话与依赖

确认会话 Cookie 带有 Secure/HttpOnly/SameSite,并且 composer audit干净的

本站的视角:即便默认值强,授权与依赖也得靠你自己

Laravel 有许多好的默认值,但授权——谁可以做什么——以及依赖是否保持更新是应用与运营特有的,因此没有任何框架能自动替你守护。我们反复看到的事故,与其说是精巧的攻击,不如说是配置/运营的套路:“已认证,却没有所有者检查”、“生产环境开着调试”、“一个密钥被暴露”。所以重心在于从上到下照做上面那张表,并做那件不起眼的事——让每一次读取/更新都按所有者划定范围,并监控依赖的 CVE。

接下来读

FAQ

Q要保护 Laravel,我该先做什么?
A

三个 P0 项:(1) 确保生产环境 APP_DEBUG=false,并用 config:cache 把配置固定下来;(2) 让 .env 和密钥文件远离公开目录,并保持严格权限;(3) 妥善管理 APP_KEY(它是加密、签名 Cookie 和会话的基础,泄露时要轮换)。这些是其他一切的前提。接着再转向授权(Policy/Gate)和 Composer 依赖 CVE 监控。

Q带着 APP_DEBUG=true 上线有什么危险?
A

开着调试时,异常页面不仅会显示堆栈跟踪,还会显示配置值、环境变量、连接信息等内部信息。攻击者可以故意触发错误来把它们提取出来。在生产环境要设 APP_DEBUG=false 和 APP_ENV=production,并用 config:cache 让它固定生效。也不要在生产环境暴露 Telescope、Debugbar 等诊断工具。

Q为什么 config:cache 之后 env() 返回 null?
A

config:cache 会把配置编译成单个文件以提速,之后在配置文件之外调用的 env() 会返回 null(只读取缓存时刻的 .env)。解决办法是只在 config/ 内部使用 env(),在应用中通过 config('...') 引用值。在生产环境,缓存 config/route/view 是惯例——它让设置可靠生效并加速应用。

Q如何避免『登录了就等于被允许』?
A

认证(登录)与授权(该操作是否被允许)是两回事。在 Laravel 里,用 Policy/Gate 实现,并用 authorize() 或 can 中间件按所有者或权限对每一次读取/更新/删除划定范围。同时通过声明 $fillable 控制 Mass Assignment,避免批量赋值 $request->all()。没有这些,只要换掉 URL 里的 ID 就能触及别的用户的数据(IDOR)。

Q如何管理 Composer 依赖漏洞?
A

用 composer audit 或 osv-scanner 对已知 CVE 做机器监控,按运行中的版本判断,并快速打补丁(依据实际安装的东西来决策,而不是 composer.json 的声明)。同时让 Laravel 和 PHP 保持在受支持的版本,别把 EOL 版本留着不管。在事故中,依赖是否保持更新是比精巧攻击更现实的因素。