根本修复是强制设置强 cookievalidationkey,需用 bin/yii security/generate-key 生成并配置到所有环境;同时在控制器 init() 中启用 csrf 校验、非 get 接口手动验证、表单嵌入隐藏域、关闭调试与敏感信息泄露。

Yii 2.0.38 存在已知的 CSRF 绕过风险(CVE-2021-29337),核心问题是:当 enableCsrfValidation 开启但 cookieValidationKey 为空或使用弱密钥时,攻击者可预测并伪造 CSRF token,导致防护失效。修复不依赖升级版本,关键在配置加固和代码补位。
强制设置强 cookieValidationKey
这是最根本的修复动作。该密钥用于签名生成 CSRF token,若为空、为默认值(如 'test')、或长度不足32字符,token 就可被暴力穷举或重放。
- 检查
config/web.php或生产环境专用配置(如environments/prod/frontend/config/main-local.php)中'request'组件是否包含'cookieValidationKey' - 若缺失或值为
null/''/'some-simple-key',立即替换为高强度随机字符串(建议用bin/yii security/generate-key命令生成) - 确保该配置在所有运行环境中生效,尤其是部署后未覆盖的线上配置文件
显式启用并验证 CSRF(不止靠配置)
仅在配置里设 'enableCsrfValidation' => true 不够——控制器或 action 层可能被覆盖,且 AJAX 接口容易遗漏校验。
- 在基类控制器(如
controllers/Controller.php)的init()方法开头加:Yii::$app->request->enableCsrfValidation = true; - 对所有非 GET 的接口(特别是
POST/PUT/DELETE),在 action 中手动校验:if (!Yii::$app->request->validateCsrfToken()) { throw new BadRequestHttpException('Invalid CSRF token.'); } - 前端 AJAX 请求必须携带 token:在请求头加
X-CSRF-Token: = Yii::$app->request->getCsrfToken() ?>,或在数据体中传_csrf字段
表单与输出层双重兜底
绕过常发生在开发者手动拼接表单、跳过 ActiveForm 或误用 Html::beginForm() 时。
- 所有 HTML 表单必须包含
= Html::csrfInput() ?>—— 它生成隐藏域<input name="_csrf" value="xxx">,不能手写或省略 - 禁用任何直接输出用户输入的场景;富文本内容务必经
HtmlPurifier过滤后再渲染 - 检查模板中是否存在
<form method="post"></form>但无 CSRF 隐藏域的情况,尤其老代码或第三方插件引入的表单
关闭调试与敏感信息泄露
CSRF token 泄露常伴随调试模式开启:错误页显示完整堆栈、日志输出 token 原值、响应头暴露内部路径等,为攻击者提供分析线索。
- 确认
index.php中无defined('YII_DEBUG') or define('YII_DEBUG', true);,应为false或完全删除 - 生产环境
php.ini设置display_errors = Off,Web 服务器(Nginx/Apache)禁止直接访问runtime/、vendor/、config/ - 日志级别设为
warning或error,禁用trace和info,防止 token 出现在日志文件中











