Laravel安全加固关键在堵缺口、守规矩:必须启用VerifyCsrfToken中间件并正确注册,Web表单强制@csrf,API供SPA调用时显式加web+auth:sanctum,CSP头需动态生成,.env和storage权限须严格限制,CSRF白名单最小化且仅限可信回调。

当你刚上线一个Laravel项目,发现API被爬虫高频调用、管理后台表单提交后出现419错误、用户注册邮箱被爆破、甚至.env文件能被直接下载——这不是框架有漏洞,而是默认配置没堵住常见缺口。Laravel本身安全基线足够高,但开发者跳过中间件注册、硬编码安全头、忽略storage权限,就会让整套防护形同虚设。
堵住CSRF与路由入口缺口
Web路由必须启用CSRF校验,否则任何带session的POST/PUT/PATCH/DELETE请求都可被伪造。
确认app/Http/Kernel.php中$middlewareGroups['web']数组包含\App\Http\Middleware\VerifyCsrfToken::class,且位置不在末尾——【它必须在TrimStrings和ConvertEmptyStringsToNull之后、所有自定义中间件之前】,否则后续中间件可能提前终止请求导致令牌未被校验。
所有Blade表单内必须写@csrf,哪怕你用了AJAX——Vue/React SPA调用本域API时,仍需携带X-XSRF-TOKEN头,该头由Laravel自动注入到document.cookie中。
API路由若供浏览器内SPA调用(如管理后台),不能简单归入api中间件组;应显式改用web中间件并加auth:sanctum:Route::post('/admin/update')->middleware(['web', 'auth:sanctum'])。
动态生成Content-Security-Policy头
硬编码CSP策略会导致JS/CSS加载失败、Google Fonts白屏、甚至整个页面无法渲染,因为真实资源路径会随环境、用户角色、路由名变化。
创建中间件app/Http/Middleware/InjectCspHeader.php,在handle()中拼接策略:
先取当前路由名:$routeName = $request->route()?->getName() ?: 'fallback';
再判断用户角色:$role = $request->user()?->role ?? 'guest';
最后组合策略字符串:$policy = "default-src 'self'; script-src 'self'".($role === 'admin' ? " 'unsafe-inline'" : " 'nonce-".base64_encode(random_bytes(16))."'")."; img-src 'self' https:;";
用$response->header('Content-Security-Policy', $policy)注入响应头,并将该中间件注册到app/Http/Kernel.php的web组末尾。
收紧.env与storage目录权限
本地开发时.env权限宽松无感,但部署到Linux服务器后,Nginx/Apache若以www-data用户运行且目录权限为755,.env会被直接HTTP返回——里面含数据库密码、APP_KEY等高危信息。
执行命令:chmod 644 .env && chown root:www-data .env,确保Web服务器进程只能读、不能写,且非root用户不可读。
storage/logs目录必须禁止Web访问:在Nginx配置中添加location /storage/logs { deny all; },Apache则需在.htaccess里写Deny from all。
storage/app若用于上传文件,需额外检查是否启用了php.ini中的disable_functions=exec,shell_exec,system,防止恶意文件被执行。
最小化CSRF白名单与API认证切换
第一步:打开app/Http/Middleware/VerifyCsrfToken.php,找到$except数组。
第二步:删掉所有“方便调试”加进去的路径,只保留真正无法携带token的场景——比如微信支付回调地址/api/wechat/notify、Stripe webhook端点/api/stripe/webhook。
第三步:确认这些白名单路径不涉及用户数据修改,且已通过签名验证(如hash_hmac('sha256', $payload, config('services.wechat.secret')))。
第四步:对所有需要身份校验的API,弃用auth:api(Laravel旧版Session认证),改用Sanctum Token认证:Route::middleware('auth:sanctum')->get('/api/user', function (Request $request) { return $request->user(); });
第五步:生成Token时明确作用域与有效期:$token = $user->createToken('mobile-app', ['read:posts', 'write:comments'], now()->addHours(2));,避免使用createToken('test')这种无约束方式。


















