drupal-security by madsnorgaard/agent-resources
npx skills add https://github.com/madsnorgaard/agent-resources --skill drupal-security你能在代码编写过程中主动识别安全漏洞,而非事后补救。
切勿将用户输入拼接到查询语句中:
// 存在漏洞 - SQL 注入
$query = "SELECT * FROM users WHERE name = '" . $name . "'";
$result = $connection->query($query);
// 安全 - 参数化查询
$result = $connection->select('users', 'u')
->fields('u')
->condition('name', $name)
->execute();
// 安全 - 占位符
$result = $connection->query(
'SELECT * FROM {users} WHERE name = :name',
[':name' => $name]
);
始终对输出进行转义。信任渲染系统:
// 存在漏洞 - 原始 HTML 输出
return ['#markup' => $user_input];
return ['#markup' => '<div>' . $title . '</div>'];
// 安全 - 纯文本(自动转义)
return ['#plain_text' => $user_input];
// 安全 - 使用正确的渲染元素
return [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => $title, // 自动转义
];
// 安全 - Twig 自动转义
{{ variable }} // 已转义
{{ variable|raw }} // 危险 - 仅用于可信的 HTML
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
对于仅限管理员的内容:
use Drupal\Component\Utility\Xss;
// 过滤但允许安全的 HTML 标签
$safe = Xss::filterAdmin($user_html);
始终验证权限:
// 在 routing.yml 中
my_module.admin:
path: '/admin/my-module'
requirements:
_permission: 'administer my_module' # 必需!
// 在代码中
if (!$this->currentUser->hasPermission('administer my_module')) {
throw new AccessDeniedHttpException();
}
// 实体查询 - 检查访问权限!
$query = $this->entityTypeManager
->getStorage('node')
->getQuery()
->accessCheck(TRUE) // 关键 - 除非有意为之,否则切勿设为 FALSE
->condition('type', 'article');
表单会自动包含 CSRF 令牌。对于自定义 AJAX:
// 在 AJAX 请求中包含令牌
$build['#attached']['drupalSettings']['myModule']['token'] =
\Drupal::csrfToken()->get('my_module_action');
// 在控制器中验证
if (!$this->csrfToken->validate($token, 'my_module_action')) {
throw new AccessDeniedHttpException('Invalid token');
}
$validators = [
'file_validate_extensions' => ['pdf doc docx'], // 白名单扩展名
'file_validate_size' => [25600000], // 25MB 限制
'FileSecurity' => [], // Drupal 10.2+ - 阻止危险文件
];
// 切勿仅信任文件扩展名 - 检查 MIME 类型
$file_mime = $file->getMimeType();
$allowed_mimes = ['application/pdf', 'application/msword'];
if (!in_array($file_mime, $allowed_mimes)) {
// 拒绝文件
}
// 切勿记录敏感数据
$this->logger->info('User @user logged in', ['@user' => $username]);
// 错误示例:$this->logger->info('Login: ' . $username . ':' . $password);
// 切勿在错误消息中暴露
throw new \Exception('Database error'); // 通用消息
// 错误示例:throw new \Exception('Query failed: ' . $query);
// 对密钥使用环境变量
$api_key = getenv('MY_API_KEY');
// 错误示例:$api_key = 'hardcoded-secret-key';
当你看到以下模式时,立即发出警告:
| 模式 | 风险 | 修复方法 |
|---|---|---|
| SQL 中的字符串拼接 | SQL 注入 | 使用查询构建器 |
带有变量的 #markup | XSS | 使用 #plain_text |
accessCheck(FALSE) | 访问绕过 | 使用 accessCheck(TRUE) |
路由中缺少 _permission | 未授权访问 | 添加权限 |
| Twig 中的 `{{ var | raw }}` | XSS |
| 硬编码的密码/密钥 | 凭证泄露 | 使用环境变量 |
eval() 或 exec() | 代码注入 | 完全避免 |
对用户数据使用 unserialize() | 对象注入 | 使用 JSON |
审查代码时,始终要问:
在提交任何代码之前:
accessCheck(TRUE)每周安装量
168
代码仓库
GitHub Stars
34
首次出现
2026年1月25日
安全审计
安装于
github-copilot155
opencode122
codex119
gemini-cli115
amp112
kimi-cli111
You proactively identify security vulnerabilities while code is being written, not after.
NEVER concatenate user input into queries:
// VULNERABLE - SQL injection
$query = "SELECT * FROM users WHERE name = '" . $name . "'";
$result = $connection->query($query);
// SAFE - parameterized query
$result = $connection->select('users', 'u')
->fields('u')
->condition('name', $name)
->execute();
// SAFE - placeholder
$result = $connection->query(
'SELECT * FROM {users} WHERE name = :name',
[':name' => $name]
);
Always escape output. Trust the render system:
// VULNERABLE - raw HTML output
return ['#markup' => $user_input];
return ['#markup' => '<div>' . $title . '</div>'];
// SAFE - plain text (auto-escaped)
return ['#plain_text' => $user_input];
// SAFE - use proper render elements
return [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => $title, // Escaped automatically
];
// SAFE - Twig auto-escapes
{{ variable }} // Escaped
{{ variable|raw }} // DANGEROUS - only for trusted HTML
For admin-only content:
use Drupal\Component\Utility\Xss;
// Filter but allow safe HTML tags
$safe = Xss::filterAdmin($user_html);
Always verify permissions:
// In routing.yml
my_module.admin:
path: '/admin/my-module'
requirements:
_permission: 'administer my_module' # Required!
// In code
if (!$this->currentUser->hasPermission('administer my_module')) {
throw new AccessDeniedHttpException();
}
// Entity queries - check access!
$query = $this->entityTypeManager
->getStorage('node')
->getQuery()
->accessCheck(TRUE) // CRITICAL - never FALSE unless intentional
->condition('type', 'article');
Forms automatically include CSRF tokens. For custom AJAX:
// Include token in AJAX requests
$build['#attached']['drupalSettings']['myModule']['token'] =
\Drupal::csrfToken()->get('my_module_action');
// Validate in controller
if (!$this->csrfToken->validate($token, 'my_module_action')) {
throw new AccessDeniedHttpException('Invalid token');
}
$validators = [
'file_validate_extensions' => ['pdf doc docx'], // Whitelist extensions
'file_validate_size' => [25600000], // 25MB limit
'FileSecurity' => [], // Drupal 10.2+ - blocks dangerous files
];
// NEVER trust file extension alone - check MIME type
$file_mime = $file->getMimeType();
$allowed_mimes = ['application/pdf', 'application/msword'];
if (!in_array($file_mime, $allowed_mimes)) {
// Reject file
}
// NEVER log sensitive data
$this->logger->info('User @user logged in', ['@user' => $username]);
// NOT: $this->logger->info('Login: ' . $username . ':' . $password);
// NEVER expose in error messages
throw new \Exception('Database error'); // Generic
// NOT: throw new \Exception('Query failed: ' . $query);
// Use environment variables for secrets
$api_key = getenv('MY_API_KEY');
// NOT: $api_key = 'hardcoded-secret-key';
When you see these patterns, immediately warn :
| Pattern | Risk | Fix |
|---|---|---|
| String concatenation in SQL | SQL injection | Use query builder |
#markup with variables | XSS | Use #plain_text |
accessCheck(FALSE) | Access bypass | Use accessCheck(TRUE) |
Missing _permission in routes | Unauthorized access | Add permission |
| `{{ var | raw }}` in Twig |
When reviewing code, always ask:
Before any code is committed:
accessCheck(TRUE)Weekly Installs
168
Repository
GitHub Stars
34
First Seen
Jan 25, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
github-copilot155
opencode122
codex119
gemini-cli115
amp112
kimi-cli111
Azure PostgreSQL 无密码身份验证配置指南:Entra ID 迁移与访问管理
34,800 周安装
Git Commit 自动化工具:智能分析代码变更,生成规范提交信息,提升开发效率
105 周安装
PostgreSQL/MySQL数据库模式设计指南:规范化、约束与最佳实践
105 周安装
Helius Solana开发指南:RPC API、实时数据流与区块链工具集成
105 周安装
LLM评估指南:自动化指标、人工评估与A/B测试全面解析
105 周安装
Minecraft Bukkit Pro 插件开发指南:精通Bukkit/Spigot/Paper API与性能优化
105 周安装
Rust异步编程模式指南:基于Tokio的任务、通道、流与错误处理最佳实践
105 周安装
| XSS |
| Hardcoded passwords/keys | Credential exposure | Use env vars |
eval() or exec() | Code injection | Avoid entirely |
unserialize() on user data | Object injection | Use JSON |