关于 drupal-security
面向 Drupal 开发者的安全编码参考,聚焦常见漏洞模式及其防护方式。内容涉及数据库查询、输出转义、权限、CSRF、文件上传和敏感数据处理。
主要功能
- 01防范 SQL 注入与 XSS
- 02检查访问权限与 CSRF
- 03验证上传文件
- 04避免泄露敏感数据
- 05识别常见危险代码模式
适用场景
- 01审查 Drupal 模块代码
- 02实现安全的自定义端点
- 03检查文件上传处理逻辑
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ edutrul/ drupal-ai --skill drupal-security安装后在 Claude Code 中输入/drupal-security确认已加载。
附带文件README.md
详细介绍
Drupal 安全
关键安全模式
防止 SQL 注入
绝不要将用户输入拼接到查询中:
// 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]
);
防止 XSS
始终转义输出。信任渲染系统:
// 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
对于仅限管理员的内容:
use Drupal\Component\Utility\Xss;
// Filter but allow safe HTML tags
$safe = Xss::filterAdmin($user_html);
注意:绝不要将不可信的用户输入传入 #markup。优先使用 #plain_text、Twig 自动转义或安全的渲染元素。
访问控制
始终验证权限:
// 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');
CSRF 防护
表单会自动包含 CSRF 令牌。对于自定义 AJAX:
// Include token in AJAX requests
$build['#attached']['drupalSettings']['myModule']['token'] =
\Drupal::csrfToken()->get('my_module_action');
注意:在类中优先使用依赖注入,而不是直接调用 \Drupal::service() 或 \Drupal::。
// 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';
需要留意的危险信号
遇到以下模式时,立即发出警告:
| 模式 | 风险 | 修复方法 |
|---|---|---|
| 在 SQL 中拼接字符串 | SQL 注入 | 使用查询构建器 |
#markup 中包含变量 | XSS | 使用 #plain_text |
accessCheck(FALSE) | 绕过访问控制 | 使用 accessCheck(TRUE) |
路由中缺少 _permission | 未经授权的访问 | 添加权限 |
| 自定义控制器没有访问检查 | 未经授权的访问 | 添加路由权限或访问回调 |
Twig 中使用 {{ var|raw }} | XSS | 移除 |raw |
| 硬编码的密码/密钥 | 凭据泄露 | 使用环境变量 |
eval() 或 exec() | 代码注入 | 完全避免使用 |
对用户数据调用 unserialize() | 对象注入 | 使用 JSON |
| 自定义端点中缺少 CSRF 验证 | CSRF 攻击 | 使用 csrf_token 服务验证令牌 |
| 文件上传时未进行验证 | 恶意文件上传 | 验证扩展名、大小和 MIME 类型 |
在类中直接使用 \Drupal:: | 难以测试/不良实践 | 使用依赖注入 |
| 记录敏感数据 | 信息泄露 | 对敏感字段脱敏或避免记录 |
评论
支持 Markdown