Laravel 13 安全增强详解

摘要

Laravel 13 增强了请求伪造保护中间件,引入了 PreventRequestForgery 中间件,提供来源感知的请求验证。本文将深入讲解 Laravel 13 的安全增强,包括:

  • PreventRequestForgery 中间件原理
  • 来源感知请求验证
  • 与 CSRF 保护配合
  • 安全配置最佳实践
  • API 安全策略
  • 实战案例:构建安全应用

本文适合关注应用安全的 Laravel 开发者。

1. 请求伪造保护概述

1.1 什么是请求伪造

请求伪造攻击包括:

  • CSRF(跨站请求伪造)
  • SSRF(服务器端请求伪造)
  • 开放重定向
  • 点击劫持

1.2 Laravel 13 的改进

1
2
// 新增 PreventRequestForgery 中间件
// 提供来源感知的请求验证

2. PreventRequestForgery 中间件

2.1 基本配置

1
2
3
4
5
// app/Http/Kernel.php
protected $middleware = [
// ...
\Illuminate\Foundation\Http\Middleware\PreventRequestForgery::class,
];

2.2 配置选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// config/security.php
return [
'request_forgery' => [
'enabled' => true,

'allowed_origins' => [
env('APP_URL'),
'https://trusted-domain.com',
],

'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],

'strict_mode' => true,
],
];

2.3 来源验证

1
2
3
4
5
6
7
8
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;

class Kernel extends HttpKernel
{
protected $middleware = [
PreventRequestForgery::class,
];
}

3. 与 CSRF 保护配合

3.1 双重保护

1
2
3
4
5
// CSRF 保护(表单提交)
@include('csrf')

// PreventRequestForgery(来源验证)
// 自动验证请求来源

3.2 排除路由

1
2
3
4
5
6
7
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'api/*',
'webhooks/*',
]);
})

3.3 API 豁免

1
2
3
4
5
// API 路由通常豁免 CSRF
Route::prefix('api')->group(function () {
// 这些路由不检查 CSRF
// 但仍然检查来源
});

4. 安全配置

4.1 CORS 配置

1
2
3
4
5
6
7
8
9
10
11
// config/cors.php
return [
'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => [env('APP_URL')],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];

4.2 安全头

1
2
3
4
5
6
7
8
9
10
11
12
13
// app/Http/Middleware/SecurityHeaders.php
public function handle($request, Closure $next)
{
$response = $next($request);

$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('X-Frame-Options', 'DENY');
$response->headers->set('X-XSS-Protection', '1; mode=block');
$response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
$response->headers->set('Content-Security-Policy', "default-src 'self'");

return $response;
}

4.3 HTTPS 强制

1
2
3
4
5
6
7
// app/Providers/AppServiceProvider.php
public function boot()
{
if (app()->environment('production')) {
URL::forceScheme('https');
}
}

5. API 安全

5.1 Sanctum 认证

1
2
3
4
5
// 安装 Sanctum
composer require laravel/sanctum

// 配置
php artisan sanctum:install
1
2
3
4
5
6
// 路由保护
Route::middleware('auth:sanctum')->group(function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
});

5.2 Token 能力

1
2
3
4
5
6
7
// 创建带能力的 Token
$token = $user->createToken('api-token', ['read', 'write']);

// 检查能力
if ($request->user()->tokenCan('write')) {
// 允许写入
}

5.3 速率限制

1
2
3
4
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->throttleApi('60,1');
})

6. 输入验证

6.1 请求验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}

public function rules(): array
{
return [
'title' => 'required|string|max:255',
'content' => 'required|string',
'status' => 'required|in:draft,published',
];
}
}

6.2 输入清理

1
2
3
4
5
6
7
8
// 自动清理输入
public function prepareForValidation()
{
$this->merge([
'title' => strip_tags($this->title),
'content' => Purifier::clean($this->content),
]);
}

7. 文件上传安全

7.1 验证文件

1
2
3
4
5
6
7
public function rules(): array
{
return [
'avatar' => 'required|image|max:1024|mimes:jpeg,png,gif',
'document' => 'required|file|max:10240|mimes:pdf,doc,docx',
];
}

7.2 安全存储

1
2
3
4
5
// 安全文件名
$filename = Str::random(40) . '.' . $file->extension();

// 私有存储
$path = $file->storeAs('private/uploads', $filename, 's3-private');

7.3 病毒扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use App\Services\VirusScanner;

class SecureFileUpload
{
public function upload(UploadedFile $file): string
{
// 扫描病毒
if (app(VirusScanner::class)->scan($file)) {
throw new InfectedFileException();
}

return $file->store('uploads');
}
}

8. SQL 注入防护

8.1 使用 Eloquent

1
2
3
4
5
6
7
8
// 安全:Eloquent 自动参数化
User::where('email', $email)->first();

// 不安全:原始查询
DB::select("SELECT * FROM users WHERE email = '{$email}'");

// 安全:参数化查询
DB::select('SELECT * FROM users WHERE email = ?', [$email]);

8.2 验证输入

1
2
3
4
5
// 验证 ID 为整数
$request->validate(['id' => 'required|integer']);

// 验证枚举值
$request->validate(['status' => 'required|in:active,inactive']);

9. XSS 防护

9.1 Blade 自动转义

1
2
3
4
5
{{-- 自动转义 --}}
{{ $userInput }}

{{-- 不转义(谨慎使用) --}}
{!! $trustedHtml !!}

9.2 内容清理

1
2
3
4
5
6
7
8
9
10
use HTMLPurifier;

class ContentSanitizer
{
public function sanitize(string $html): string
{
$purifier = new HTMLPurifier();
return $purifier->purify($html);
}
}

10. 实战案例

10.1 安全中间件堆栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
\Illuminate\Foundation\Http\Middleware\PreventRequestForgery::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class,
\App\Http\Middleware\SecurityHeaders::class,
],

'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\SecurityHeaders::class,
],
];

10.2 审计日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

namespace App\Services;

use Illuminate\Support\Facades\Log;

class SecurityAuditService
{
public function logSuspiciousActivity(string $type, array $context = []): void
{
Log::channel('security')->warning("Suspicious activity: {$type}", array_merge([
'ip' => request()->ip(),
'user_agent' => request()->userAgent(),
'user_id' => auth()->id(),
'url' => request()->fullUrl(),
'timestamp' => now()->toIso8601String(),
], $context));
}
}

11. 最佳实践

11.1 最小权限原则

1
2
// 只授予必要的能力
$token = $user->createToken('read-only', ['read']);

11.2 定期审计

1
2
// 定期清理过期 Token
$schedule->command('sanctum:prune-expired --hours=24')->daily();

11.3 安全响应

1
2
3
4
5
6
7
8
9
// 不暴露敏感信息
return response()->json([
'message' => 'Authentication failed',
], 401);

// 而不是
return response()->json([
'message' => 'User not found', // 暴露用户存在性
], 401);

12. 总结

Laravel 13 的安全增强为应用提供了更全面的保护:

  1. 请求伪造保护:来源感知的请求验证
  2. 双重保护:CSRF + 来源验证
  3. API 安全:Sanctum + 速率限制
  4. 输入验证:严格的请求验证
  5. 安全头:全面的安全头配置

通过本指南,您已经掌握了 Laravel 13 的安全增强功能,可以构建更安全的应用了。

参考资料