Laravel 安全最佳实践¶
保护 Laravel 应用免受常见漏洞侵害的全面安全指南。
何时启用¶
- 添加认证或授权时
- 处理用户输入和文件上传时
- 构建新的 API 端点时
- 管理机密与环境配置时
- 加固生产环境部署时
工作原理¶
- 中间件提供基础保护(CSRF 通过
VerifyCsrfToken,安全标头通过SecurityHeaders) - 守卫(Guard)与策略(Policy)实施访问控制(
auth:sanctum、$this->authorize、策略中间件) - 表单请求(FormRequest)在输入到达服务之前对其进行验证和格式化(如
UploadInvoiceRequest) - 速率限制与认证控制并行,提供滥用保护(
RateLimiter::for('login')) - 数据安全性来自加密转换(cast)、批量赋值保护、签名路由(
URL::temporarySignedRoute+signed中间件)
核心安全配置¶
- 在生产环境中设置
APP_DEBUG=false - 设置
APP_KEY,一旦泄露必须轮换 - 设置
SESSION_SECURE_COOKIE=true和SESSION_SAME_SITE=lax(或对敏感应用设置为strict) - 配置可信代理,以确保正确的 HTTPS 检测
会话与 Cookie 加固¶
- 设置
SESSION_HTTP_ONLY=true以防止 JavaScript 访问 - 对高风险流程使用
SESSION_SAME_SITE=strict - 在登录与权限变更时重新生成会话
认证与令牌¶
- 使用 Laravel Sanctum 或 Passport 进行 API 认证
- 对敏感数据,优先使用短时效令牌与刷新流程
- 在注销与账户被入侵时使令牌失效
路由保护示例:
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/me', function (Request $request) {
return $request->user();
});
密码安全¶
- 使用
Hash::make()对密码进行哈希,切勿明文存储 - 对密码重置流程使用 Laravel 的密码代理(password broker)
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;
$validated = $request->validate([
'password' => ['required', 'string', Password::min(12)->letters()->mixedCase()->numbers()->symbols()],
]);
$user->update(['password' => Hash::make($validated['password'])]);
授权:策略与 Gate¶
- 对模型级授权使用策略(Policy)
- 在控制器与服务中强制执行授权
在路由级别使用策略中间件强制执行:
use Illuminate\Support\Facades\Route;
Route::put('/projects/{project}', [ProjectController::class, 'update'])
->middleware(['auth:sanctum', 'can:update,project']);
验证与数据清理¶
- 始终通过表单请求(FormRequest)验证用户输入
- 使用严格的验证规则与类型检查
- 不要信任请求负载中的派生字段
批量赋值保护¶
- 使用
$fillable或$guarded,避免使用Model::unguard() - 优先使用 DTO 或显式属性映射
SQL 注入防护¶
- 使用 Eloquent 或查询构建器的参数绑定
- 除非确有必要,否则避免原生 SQL
XSS 防护¶
- Blade 默认转义输出(
{{ }}) - 仅对可信、已清理的 HTML 使用
{!! !!} - 使用专用库清理富文本
CSRF 保护¶
- 保持
VerifyCsrfToken中间件处于启用状态 - 在表单中包含
@csrf,并在 SPA 请求中发送 XSRF 令牌
对于 SPA 认证(Sanctum),请确保已配置有状态(stateful)请求:
文件上传安全¶
- 验证文件大小、MIME 类型和扩展名
- 尽可能将上传文件存储在公开路径之外
- 必要时对文件进行恶意软件扫描
final class UploadInvoiceRequest extends FormRequest
{
public function authorize(): bool
{
return (bool) $this->user()?->can('upload-invoice');
}
public function rules(): array
{
return [
'invoice' => ['required', 'file', 'mimes:pdf', 'max:5120'],
];
}
}
$path = $request->file('invoice')->store(
'invoices',
config('filesystems.private_disk', 'local') // set this to a non-public disk
);
速率限制¶
- 对认证与写入端点应用
throttle中间件 - 对登录、密码重置、OTP 使用更严格的限制
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('login', function (Request $request) {
return [
Limit::perMinute(5)->by($request->ip()),
Limit::perMinute(5)->by(strtolower((string) $request->input('email'))),
];
});
机密与凭据¶
- 不要将机密提交到源代码控制
- 使用环境变量与机密管理器
- 公开后轮换密钥并使会话失效
加密属性¶
对存储中的机密列使用加密转换(cast)。
安全标头¶
- 根据需要添加 CSP、HSTS、框架保护
- 使用可信代理配置以强制 HTTPS 重定向
用于设置标头的中间件示例:
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
final class SecurityHeaders
{
public function handle(Request $request, \Closure $next): Response
{
$response = $next($request);
$response->headers->add([
'Content-Security-Policy' => "default-src 'self'",
'Strict-Transport-Security' => 'max-age=31536000', // add includeSubDomains/preload only when all subdomains are HTTPS
'X-Frame-Options' => 'DENY',
'X-Content-Type-Options' => 'nosniff',
'Referrer-Policy' => 'no-referrer',
]);
return $response;
}
}
CORS 与 API 暴露¶
- 在
config/cors.php中限制允许的来源(origin) - 避免在已认证路由上使用通配符来源
// config/cors.php
return [
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
'allowed_origins' => ['https://app.example.com'],
'allowed_headers' => [
'Content-Type',
'Authorization',
'X-Requested-With',
'X-XSRF-TOKEN',
'X-CSRF-TOKEN',
],
'supports_credentials' => true,
];
日志与个人信息¶
- 不要将密码、令牌、完整卡数据写入日志
- 在结构化日志中屏蔽敏感字段
use Illuminate\Support\Facades\Log;
Log::info('User updated profile', [
'user_id' => $user->id,
'email' => '[REDACTED]',
'token' => '[REDACTED]',
]);
依赖安全¶
- 定期运行
composer audit - 谨慎固定依赖,出现 CVE 时迅速更新
签名 URL¶
对临时防篡改链接使用签名路由。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC