安全指南
本文介绍 CarefreeCMS 的安全最佳实践和配置建议。
身份验证
JWT 认证
CarefreeCMS 使用 JWT(JSON Web Token)进行用户认证。
配置 JWT 密钥
编辑 .env 文件:
JWT_SECRET=your-secret-key-here
JWT_EXPIRE=7200
建议:
- 使用强随机字符串作为密钥
- 定期更换密钥
- 不要在代码中硬编码密钥
Token 刷新
Token 过期后需要刷新:
const refreshToken = async () => {
const res = await axios.post('/api/auth/refresh', {
refresh_token: localStorage.getItem('refresh_token')
})
localStorage.setItem('token', res.data.token)
}
密码安全
密码策略
在 config/app.php 中配置:
'password' => [
'min_length' => 8,
'require_uppercase' => true,
'require_lowercase' => true,
'require_numbers' => true,
'require_special_chars' => true,
],
密码加密
使用 PHP 的 password_hash() 函数:
$password = password_hash($input_password, PASSWORD_BCRYPT);
权限控制
RBAC 权限系统
基于角色的访问控制(RBAC)。
角色定义
// 超级管理员
'admin' => [
'name' => '超级管理员',
'permissions' => ['*']
],
// 编辑
'editor' => [
'name' => '编辑',
'permissions' => [
'article.create',
'article.update',
'article.delete'
]
]
权限检查
// 检查权限
if (!hasPermission('article.delete')) {
throw new Exception('无权限');
}
// 中间件
Route::middleware(['auth', 'permission:article.create'])
->post('/api/articles', 'ArticleController@create');
数据安全
SQL 注入防护
使用参数化查询
// ✓ 安全
$articles = Db::query(
'SELECT * FROM articles WHERE id = ?',
[$id]
);
// ✗ 不安全
$articles = Db::query(
"SELECT * FROM articles WHERE id = {$id}"
);
使用 ORM
// ThinkPHP ORM 自动防注入
$article = Article::where('id', $id)->find();
XSS 防护
输出转义
// 自动转义
{{ $user_input }}
// 不转义(仅用于可信内容)
{!! $trusted_html !!}
内容安全策略(CSP)
在 .htaccess 或 nginx 配置中添加:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';";
CSRF 防护
启用 CSRF 保护
// config/middleware.php
'csrf' => \think\middleware\CheckRequestCache::class,
前端发送 Token
axios.post('/api/articles', data, {
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
}
})
文件上传安全
文件类型限制
'upload' => [
'allowed_types' => ['jpg', 'jpeg', 'png', 'gif', 'pdf'],
'max_size' => 10 * 1024 * 1024, // 10MB
],
文件名处理
// 重命名文件
$filename = md5(uniqid()) . '.' . $file->extension();
// 存储到安全目录
$file->move(runtime_path() . 'uploads/', $filename);
验证文件内容
// 检查 MIME 类型
$mimeType = $file->getMimeType();
if (!in_array($mimeType, ['image/jpeg', 'image/png'])) {
throw new Exception('不支持的文件类型');
}
// 检查文件头
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$realMimeType = finfo_file($finfo, $file->getPathname());
finfo_close($finfo);
API 安全
请求频率限制
// 中间件配置
'throttle' => [
'visit_rate' => '60/m', // 每分钟60次
'login_rate' => '5/m', // 登录每分钟5次
],
API 签名验证
function verifySignature($data, $timestamp, $signature) {
$secret = config('app.api_secret');
$string = $timestamp . json_encode($data) . $secret;
$expectedSignature = hash('sha256', $string);
return hash_equals($expectedSignature, $signature);
}
HTTPS 强制
在 nginx 配置中:
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
}
会话安全
Session 配置
'session' => [
'secure' => true, // 仅 HTTPS
'httponly' => true, // 防止 JavaScript 访问
'expire' => 1440, // 24小时
'domain' => '',
'path' => '/',
],
Cookie 安全
setcookie(
'user_token',
$token,
[
'expires' => time() + 86400,
'path' => '/',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]
);
日志与监控
安全日志
记录重要操作:
// 登录日志
Log::info('用户登录', [
'user_id' => $user->id,
'ip' => request()->ip(),
'user_agent' => request()->header('user-agent'),
]);
// 敏感操作日志
Log::warning('删除文章', [
'article_id' => $id,
'user_id' => $user->id,
]);
异常监控
// 捕获异常
try {
// 业务逻辑
} catch (\Exception $e) {
Log::error('操作失败', [
'message' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
// 发送通知
notify_admin($e);
}
数据库安全
连接安全
# 使用独立数据库账号
DB_USERNAME=cms_user
DB_PASSWORD=strong_password
# 限制权限(仅 SELECT, INSERT, UPDATE, DELETE)
备份策略
# 定时备份
0 2 * * * /usr/bin/mysqldump -u user -p dbname > /backup/db_$(date +\%Y\%m\%d).sql
敏感数据加密
// 加密
$encrypted = encrypt($sensitive_data);
// 解密
$decrypted = decrypt($encrypted);
服务器安全
目录权限
# 设置合适的文件权限
chmod 755 /var/www/cms
chmod 644 /var/www/cms/.env
chmod -R 755 /var/www/cms/runtime
隐藏敏感信息
隐藏 PHP 版本
; php.ini
expose_php = Off
隐藏服务器信息
# nginx.conf
server_tokens off;
防火墙配置
# UFW 示例
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
第三方服务安全
API Key 管理
# 不要在代码中硬编码
OPENAI_API_KEY=sk-xxxxx
QINIU_ACCESS_KEY=xxxxx
QINIU_SECRET_KEY=xxxxx
敏感配置加密
使用环境变量或密钥管理服务。
安全检查清单
部署前检查
- [ ] 修改默认管理员密码
- [ ] 配置 HTTPS
- [ ] 启用 CSRF 保护
- [ ] 配置文件上传限制
- [ ] 设置请求频率限制
- [ ] 配置安全的 Session
- [ ] 隐藏服务器版本信息
- [ ] 设置正确的文件权限
- [ ] 配置数据库备份
- [ ] 启用日志记录
定期检查
- [ ] 检查日志中的异常活动
- [ ] 更新依赖包
- [ ] 审查用户权限
- [ ] 检查备份完整性
- [ ] 扫描安全漏洞
- [ ] 更新 SSL 证书
应急响应
发现安全问题时
- 隔离受影响系统
- 分析日志确定影响范围
- 修复漏洞
- 通知受影响用户
- 总结并改进
数据泄露处理
- 立即停止泄露
- 评估泄露范围
- 重置受影响账号密码
- 通知用户
- 报告相关部门
