laravel-security
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLaravel Security Best Practices
Laravel安全最佳实践
Comprehensive security guidance for Laravel applications to protect against common vulnerabilities.
为Laravel应用提供全面的安全指导,防范常见漏洞。
When to Activate
适用场景
- Adding authentication or authorization
- Handling user input and file uploads
- Building new API endpoints
- Managing secrets and environment settings
- Hardening production deployments
- 添加身份验证或授权功能时
- 处理用户输入与文件上传时
- 构建新的API端点时
- 管理密钥与环境配置时
- 加固生产环境部署时
How It Works
实现机制
- Middleware provides baseline protections (CSRF via , security headers via
VerifyCsrfToken).SecurityHeaders - Guards and policies enforce access control (,
auth:sanctum, policy middleware).$this->authorize - Form Requests validate and shape input () before it reaches services.
UploadInvoiceRequest - Rate limiting adds abuse protection () alongside auth controls.
RateLimiter::for('login') - Data safety comes from encrypted casts, mass-assignment guards, and signed routes (+
URL::temporarySignedRoutemiddleware).signed
- 中间件提供基础防护(通过实现CSRF防护,通过
VerifyCsrfToken设置安全头)。SecurityHeaders - 守卫(Guards)与策略(Policies)强制执行访问控制(、
auth:sanctum、策略中间件)。$this->authorize - 表单请求(Form Requests)在输入到达服务层前进行验证与格式化(如)。
UploadInvoiceRequest - 速率限制与身份验证控制配合,防止滥用(如)。
RateLimiter::for('login') - 数据安全通过加密类型转换、批量赋值防护和签名路由(+
URL::temporarySignedRoute中间件)保障。signed
Core Security Settings
核心安全配置
- in production
APP_DEBUG=false - must be set and rotated on compromise
APP_KEY - Set and
SESSION_SECURE_COOKIE=true(orSESSION_SAME_SITE=laxfor sensitive apps)strict - Configure trusted proxies for correct HTTPS detection
- 生产环境中设置
APP_DEBUG=false - 必须设置,且在密钥泄露后进行轮换
APP_KEY - 设置和
SESSION_SECURE_COOKIE=true(敏感应用可设为SESSION_SAME_SITE=lax)strict - 配置可信代理以确保HTTPS检测正确
Session and Cookie Hardening
会话与Cookie加固
- Set to prevent JavaScript access
SESSION_HTTP_ONLY=true - Use for high-risk flows
SESSION_SAME_SITE=strict - Regenerate sessions on login and privilege changes
- 设置以阻止JavaScript访问
SESSION_HTTP_ONLY=true - 高风险流程使用
SESSION_SAME_SITE=strict - 登录和权限变更时重新生成会话
Authentication and Tokens
身份验证与令牌
- Use Laravel Sanctum or Passport for API auth
- Prefer short-lived tokens with refresh flows for sensitive data
- Revoke tokens on logout and compromised accounts
Example route protection:
php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/me', function (Request $request) {
return $request->user();
});- 使用Laravel Sanctum或Passport进行API身份验证
- 敏感数据场景优先使用带刷新流程的短期令牌
- 登出和账户泄露时吊销令牌
示例路由防护:
php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/me', function (Request $request) {
return $request->user();
});Password Security
密码安全
- Hash passwords with and never store plaintext
Hash::make() - Use Laravel's password broker for reset flows
php
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'])]);- 使用哈希密码,绝不存储明文密码
Hash::make() - 使用Laravel的密码代理处理重置流程
php
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'])]);Authorization: Policies and Gates
授权:策略与门(Gates)
- Use policies for model-level authorization
- Enforce authorization in controllers and services
php
$this->authorize('update', $project);Use policy middleware for route-level enforcement:
php
use Illuminate\Support\Facades\Route;
Route::put('/projects/{project}', [ProjectController::class, 'update'])
->middleware(['auth:sanctum', 'can:update,project']);- 使用策略实现模型级授权
- 在控制器和服务层中强制执行授权
php
$this->authorize('update', $project);使用策略中间件实现路由级授权:
php
use Illuminate\Support\Facades\Route;
Route::put('/projects/{project}', [ProjectController::class, 'update'])
->middleware(['auth:sanctum', 'can:update,project']);Validation and Data Sanitization
输入验证与数据清理
- Always validate inputs with Form Requests
- Use strict validation rules and type checks
- Never trust request payloads for derived fields
- 始终使用表单请求验证输入
- 使用严格的验证规则和类型检查
- 绝不信任请求负载中的派生字段
Mass Assignment Protection
批量赋值防护
- Use or
$fillableand avoid$guardedModel::unguard() - Prefer DTOs or explicit attribute mapping
- 使用或
$fillable,避免使用$guardedModel::unguard() - 优先使用DTO或显式属性映射
SQL Injection Prevention
SQL注入防护
- Use Eloquent or query builder parameter binding
- Avoid raw SQL unless strictly necessary
php
DB::select('select * from users where email = ?', [$email]);- 使用Eloquent或查询构建器的参数绑定
- 除非必要,避免使用原生SQL
php
DB::select('select * from users where email = ?', [$email]);XSS Prevention
XSS防护
- Blade escapes output by default ()
{{ }} - Use only for trusted, sanitized HTML
{!! !!} - Sanitize rich text with a dedicated library
- Blade默认会转义输出()
{{ }} - 仅对可信的、经过清理的HTML使用
{!! !!} - 使用专用库清理富文本内容
CSRF Protection
CSRF防护
- Keep middleware enabled
VerifyCsrfToken - Include in forms and send XSRF tokens for SPA requests
@csrf
For SPA authentication with Sanctum, ensure stateful requests are configured:
php
// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost')),- 保持中间件启用状态
VerifyCsrfToken - 在表单中包含,并为SPA请求发送XSRF令牌
@csrf
使用Sanctum进行SPA身份验证时,确保配置了有状态请求:
php
// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost')),File Upload Safety
文件上传安全
- Validate file size, MIME type, and extension
- Store uploads outside the public path when possible
- Scan files for malware if required
php
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'],
];
}
}php
$path = $request->file('invoice')->store(
'invoices',
config('filesystems.private_disk', 'local') // set this to a non-public disk
);- 验证文件大小、MIME类型和扩展名
- 尽可能将上传文件存储在公共目录外
- 必要时扫描文件是否包含恶意软件
php
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'],
];
}
}php
$path = $request->file('invoice')->store(
'invoices',
config('filesystems.private_disk', 'local') // set this to a non-public disk
);Rate Limiting
速率限制
- Apply middleware on auth and write endpoints
throttle - Use stricter limits for login, password reset, and OTP
php
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'))),
];
});- 在身份验证和写入端点上应用中间件
throttle - 对登录、密码重置和OTP使用更严格的限制
php
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'))),
];
});Secrets and Credentials
密钥与凭证
- Never commit secrets to source control
- Use environment variables and secret managers
- Rotate keys after exposure and invalidate sessions
- 绝不要将密钥提交到版本控制系统
- 使用环境变量和密钥管理器
- 密钥泄露后进行轮换并使会话失效
Encrypted Attributes
加密属性
Use encrypted casts for sensitive columns at rest.
php
protected $casts = [
'api_token' => 'encrypted',
];对静态存储的敏感列使用加密类型转换。
php
protected $casts = [
'api_token' => 'encrypted',
];Security Headers
安全头
- Add CSP, HSTS, and frame protection where appropriate
- Use trusted proxy configuration to enforce HTTPS redirects
Example middleware to set headers:
php
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;
}
}- 酌情添加CSP、HSTS和点击劫持防护
- 配置可信代理以强制HTTPS重定向
设置安全头的中间件示例:
php
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 and API Exposure
CORS与API暴露
- Restrict origins in
config/cors.php - Avoid wildcard origins for authenticated routes
php
// 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,
];- 在中限制来源
config/cors.php - 身份验证路由避免使用通配符来源
php
// 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,
];Logging and PII
日志与个人身份信息(PII)
- Never log passwords, tokens, or full card data
- Redact sensitive fields in structured logs
php
use Illuminate\Support\Facades\Log;
Log::info('User updated profile', [
'user_id' => $user->id,
'email' => '[REDACTED]',
'token' => '[REDACTED]',
]);- 绝不记录密码、令牌或完整银行卡数据
- 在结构化日志中编辑敏感字段
php
use Illuminate\Support\Facades\Log;
Log::info('User updated profile', [
'user_id' => $user->id,
'email' => '[REDACTED]',
'token' => '[REDACTED]',
]);Dependency Security
依赖安全
- Run regularly
composer audit - Pin dependencies with care and update promptly on CVEs
- 定期运行
composer audit - 谨慎固定依赖版本,在出现CVE时及时更新
Signed URLs
签名URL
Use signed routes for temporary, tamper-proof links.
php
use Illuminate\Support\Facades\URL;
$url = URL::temporarySignedRoute(
'downloads.invoice',
now()->addMinutes(15),
['invoice' => $invoice->id]
);php
use Illuminate\Support\Facades\Route;
Route::get('/invoices/{invoice}/download', [InvoiceController::class, 'download'])
->name('downloads.invoice')
->middleware('signed');使用签名路由生成临时、防篡改的链接。
php
use Illuminate\Support\Facades\URL;
$url = URL::temporarySignedRoute(
'downloads.invoice',
now()->addMinutes(15),
['invoice' => $invoice->id]
);php
use Illuminate\Support\Facades\Route;
Route::get('/invoices/{invoice}/download', [InvoiceController::class, 'download'])
->name('downloads.invoice')
->middleware('signed');