关于 VibeSec-Skill
面向 AI 助手的 Web 应用安全编码指南,涵盖客户端与服务端常见漏洞及防护要点。适合在实现或审查 Web 代码时作为检查参考。
主要功能
- 01访问控制与权限检查
- 02XSS 与 CSRF 防护
- 03敏感数据与密钥保护
- 04开放重定向防护
- 05密码存储建议
- 06SSRF 防护策略
适用场景
- 01检查资源访问授权逻辑
- 02审查表单及页面的 XSS 风险
- 03核对状态变更请求的 CSRF 防护
- 04检查重定向与 URL 请求处理
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ behisecc/ vibesec-skill --skill vibesec-skill安装后在 Claude Code 中输入/vibesec-skill确认已加载。
附带文件README.mdLICENSE
详细介绍
Web 应用安全编码指南
概述
本指南全面介绍了 Web 应用的安全编码实践。作为 AI 助手,你的职责是以漏洞猎人的视角审视代码,在不破坏功能的前提下,让应用尽可能安全。
核心原则:
- 纵深防御:绝不依赖单一安全控制措施
- 安全失败:发生故障时应默认拒绝访问
- 最小权限:仅授予必要的最低权限
- 输入验证:绝不信任用户输入,在服务器端验证所有内容
- 输出编码:根据数据呈现的上下文对其进行适当编码
访问控制问题
当用户能够访问超出其预期权限的资源或执行超出其权限的操作时,就会出现访问控制漏洞。
核心要求
对于每个需要身份验证的数据项和操作:
-
用户级授权
- 每位用户只能访问或修改自己的数据
- 任何用户都不应访问其他用户或组织的数据
- 始终在数据层验证所有权,而不只是检查路由级别
-
使用 UUID 而非连续 ID
- 使用 UUIDv4 或类似的不可猜测标识符
- 例外:只有用户明确要求时才使用连续 ID
-
账户生命周期处理
- 用户从组织中移除时:立即撤销其所有访问令牌和会话
- 账户被删除或停用时:使所有活动会话和 API 密钥失效
- 实现令牌撤销列表,或使用带刷新机制的短期令牌
授权检查清单
- 每次请求都验证用户是否拥有该资源(不要信任客户端数据)
- 对多租户应用检查组织成员资格
- 对基于角色的操作验证角色权限
- 权限变更后重新验证权限
- 检查父资源的所有权(例如,访问评论时,验证用户是否拥有其所属的帖子)
需要避免的常见陷阱
- IDOR(不安全的直接对象引用):始终验证请求用户是否有权访问所请求的资源 ID
- 权限提升:在服务器端验证角色变更;绝不信任来自客户端的角色信息
- 水平越权:用户 A 以相同权限级别访问用户 B 的资源
- 垂直越权:普通用户访问管理员功能
- 批量赋值:筛选用户可更新的字段;不要盲目接受请求正文中的所有字段
实现模式
# Pseudocode for secure resource access
function getResource(resourceId, currentUser):
resource = database.find(resourceId)
if resource is null:
return 404 # Don't reveal if resource exists
if resource.ownerId != currentUser.id:
if not currentUser.hasOrgAccess(resource.orgId):
return 404 # Return 404, not 403, to prevent enumeration
return resource
客户端漏洞
跨站脚本(XSS)
所有可由用户直接或间接控制的输入都必须经过处理,以防范 XSS。
需要防护的输入来源
直接输入:
- 表单字段(电子邮件、姓名、个人简介、评论等)
- 搜索查询
- 上传时使用的文件名
- 富文本编辑器 / 所见即所得内容
间接输入:
- URL 参数和查询字符串
- URL 片段(哈希值)
- 应用中使用的 HTTP 标头(显示 Referer、User-Agent 时)
- 向用户展示的第三方 API 数据
- WebSocket 消息
- 来自 iframe 的 postMessage 数据
- 被渲染的 LocalStorage/SessionStorage 值
常被忽略的输入:
- 反映用户输入的错误消息
- 接受 HTML 的 PDF / 文档生成器
- 包含用户数据的电子邮件模板
- 管理面板中的日志查看器
- 被渲染为 HTML 的 JSON 响应
- SVG 文件上传(可能包含 JavaScript)
- Markdown 渲染(允许 HTML 时)
防护策略
-
输出编码(特定上下文)
- HTML 上下文:进行 HTML 实体编码(
<→<) - JavaScript 上下文:进行 JavaScript 转义
- URL 上下文:进行 URL 编码
- CSS 上下文:进行 CSS 转义
- 使用框架内置的转义功能(React 的 JSX、Vue 的 {{ }} 等)
- HTML 上下文:进行 HTML 实体编码(
-
内容安全策略(CSP)
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.yourdomain.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self';- 脚本应避免使用
'unsafe-inline'和'unsafe-eval' - 必要时,为内联脚本使用 nonce 或哈希
- 报告违规情况:
report-uri /csp-report
- 脚本应避免使用
-
输入清理
- 使用成熟的库(HTML 可使用 DOMPurify)
- 为富文本设置允许标签和属性的白名单
- 移除或编码危险模式
-
其他标头
X-Content-Type-Options: nosniffX-Frame-Options: DENY(或使用 CSP frame-ancestors)
跨站请求伪造(CSRF)
每个会更改状态的端点都必须防范 CSRF 攻击。
需要 CSRF 防护的端点
已认证操作:
- 所有 POST、PUT、PATCH、DELETE 请求
- 任何会更改状态的 GET 请求(应修正为使用适当的 HTTP 方法)
- 文件上传
- 设置变更
- 支付/交易端点
认证前操作:
- 登录端点(防止登录 CSRF)
- 注册端点
- 密码重置请求端点
- 密码更改端点
- 邮箱/手机验证端点
- OAuth 回调端点
防护机制
-
CSRF 令牌
- 生成在密码学上安全的随机令牌
- 将令牌与用户会话绑定
- 在每个会更改状态的请求中进行验证
- 登录后重新生成(防止会话固定组合攻击)
-
SameSite Cookie
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnlyStrict:Cookie 绝不会跨站发送(安全性最高)Lax:Cookie 会在顶级导航时发送(平衡性较好)- 始终与 CSRF 令牌结合使用,构建纵深防御
-
双重提交 Cookie 模式
- 在 Cookie 和请求正文/标头中同时发送 CSRF 令牌
- 由服务端验证两者是否匹配
边缘情况和常见错误
- 令牌存在性检查:CSRF 验证绝不能取决于令牌是否存在,必须始终要求提供令牌
- 每个表单使用一个令牌:对于敏感操作,可考虑为每个表单使用唯一令牌
- JSON API:不要认为 JSON 内容类型就能防止 CSRF;应验证 Origin/Referer 标头并使用令牌
- CORS 配置错误:过于宽松的 CORS 可能绕过 SameSite Cookie
- 子域名:CSRF 令牌应设置作用域,因为子域名接管可能导致 CSRF
- Flash/PDF 上传:旧版浏览器插件可能绕过 SameSite
- 带副作用的 GET 请求:绝不要在 GET 请求中更改状态
- 令牌泄露:不要在 URL 中包含 CSRF 令牌
- URL 中的令牌与标头中的令牌:优先使用自定义标头(X-CSRF-Token),而非 URL 参数
验证清单
- 令牌在密码学上安全且随机(使用安全的随机数生成器)
- 令牌与用户会话绑定
- 服务端会验证所有会更改状态的请求中的令牌
- 缺少令牌 = 拒绝请求
- 认证状态变更时会重新生成令牌
- 已设置 SameSite Cookie 属性
- 会话 Cookie 已设置 Secure 和 HttpOnly 标志
密钥和敏感数据泄露
客户端代码不应访问任何密钥或敏感信息。
绝不要在客户端代码中暴露
API 密钥和机密:
- 第三方 API 密钥(Stripe、AWS 等)
- 数据库连接字符串
- JWT 签名密钥
- 加密密钥
- OAuth 客户端机密
- 内部服务 URL/凭据
敏感用户数据:
- 完整信用卡号
- 社会安全号码
- 密码(即使经过哈希处理)
- 安全问题/答案
- 完整电话号码(应隐藏部分号码:--1234)
- 显示时并不需要的敏感个人身份信息(PII)
基础设施详情:
- 内部 IP 地址
- 数据库架构
- 调试信息
- 生产环境中的堆栈跟踪
- 服务器软件版本
密钥藏在哪里(请检查以下位置!)
- JavaScript 包(包括源映射)
- HTML 注释
- 隐藏表单字段
- 数据属性
- LocalStorage/SessionStorage
- SSR 应用中的初始状态/水合数据
- 通过构建工具暴露的环境变量(NEXT_PUBLIC_、REACT_APP_)
最佳实践
- 环境变量:将密钥存储在
.env文件中 - 仅限服务端:需要使用密钥的 API 调用只能从后端发起
开放重定向
任何接受 URL 并据此进行重定向的端点,都必须防范开放重定向攻击。
防护策略
-
允许列表验证
allowed_domains = ['yourdomain.com', 'app.yourdomain.com'] function isValidRedirect(url): parsed = parseUrl(url) return parsed.hostname in allowed_domains -
仅允许相对 URL
- 只接受路径(例如
/dashboard),不接受完整 URL - 验证路径以
/开头且不包含//
- 只接受路径(例如
-
间接引用
- 使用映射而不是原始 URL:
?redirect=dashboard→ 查找对应的/dashboard
- 使用映射而不是原始 URL:
需要阻止的绕过技术
| 技术 | 示例 | 原理 |
|---|---|---|
| @ 符号 | https://[email protected] | 浏览器会以 legit.com 为用户名,跳转到 evil.com |
| 子域名滥用 | https://legit.com.evil.com | evil.com 拥有该子域名 |
| 协议技巧 | javascript:alert(1) | 通过重定向实施 XSS |
| URL 双重编码 | %252f%252fevil.com | 双重解码后变为 //evil.com |
| 反斜杠 | https://legit.com\@evil.com | 某些解析器会将 \ 规范化为 / |
| 空字节 | https://legit.com%00.evil.com | 某些解析器会在空字节处截断 |
| 制表符/换行符 | https://legit.com%09.evil.com | 利用空白字符造成解析混淆 |
| Unicode 规范化 | https://legіt.com(西里尔字母 і) | IDN 同形异义字符攻击 |
| Data URL | data:text/html,<script>... | 直接执行载荷 |
| 协议相对 URL | //evil.com | 使用当前页面的协议 |
| 片段滥用 | https://legit.com#@evil.com | 不同库的解析结果不同 |
IDN 同形异义字符攻击防护
- 验证前将 URL 转换为 Punycode
- 对于敏感重定向,可考虑完全阻止非 ASCII 域名
密码安全
密码要求
- 至少 8 个字符(建议 12 个或更多)
- 不设最大长度(或设置较高上限,例如 128 个字符)
- 允许所有字符,包括特殊字符
- 不强制要求特定字符类型(让用户自行选择强密码)
存储
- 使用 Argon2id、bcrypt 或 scrypt
- 绝不要使用 MD5、SHA1 或普通 SHA256
服务端漏洞
服务端请求伪造(SSRF)
任何服务器会向用户提供或影响的 URL 发起请求的功能,都必须受到保护。
可能存在漏洞的功能
- Webhook(用户提供回调 URL)
- URL 预览
- 根据 URL 生成 PDF
- 根据 URL 获取图像/文件
- 从 URL 导入的功能
- RSS/Feed 阅读器
- 使用用户提供端点的 API 集成
- 代理功能
- HTML 转 PDF/图像转换器
防护策略
-
允许列表方式(首选)
- 仅允许向预先批准的域名发起请求
- 为集成维护严格的允许列表
-
网络分段
- 在隔离网络中运行 URL 获取服务
- 阻止访问内部网络和云元数据
需要拦截的 IP 和 DNS 绕过技术
| 技术 | 示例 | 描述 |
|---|---|---|
| 十进制 IP | http://2130706433 | 127.0.0.1 的十进制表示 |
| 八进制 IP | http://0177.0.0.1 | 八进制表示 |
| 十六进制 IP | http://0x7f.0x0.0x0.0x1 | 十六进制表示 |
| IPv6 本地主机 | http://[::1] | IPv6 回环地址 |
| IPv4 映射 IPv6 | http://[::ffff:127.0.0.1] | 映射 IPv4 的 IPv6 地址 |
| 简写 IPv6 | http://[::] | 全零地址 |
| DNS 重绑定 | 攻击者的 DNS 返回内部 IP | 第一次请求解析到外部 IP,第二次解析到内部 IP |
| 指向内部地址的 CNAME | 攻击者的域名将 CNAME 指向内部地址 | DNS 指向内部主机名 |
| URL 解析器混淆 | http://attacker.com#@internal | 不同的解析行为 |
| 重定向链 | 外部 URL 重定向到内部地址 | 谨慎处理重定向 |
| IPv6 区域 ID | http://[fe80::1%25eth0] | 接口范围内的 IPv6 地址 |
| 少见的 IP 格式 | http://127.1 | 缩写 IP 表示法 |
防止 DNS 重绑定
- 发起请求前解析 DNS
- 验证解析出的 IP 不是内部地址
- 为该请求固定解析出的 IP(不要重新解析)
- 或者:间隔一段时间解析两次,确保两次都解析到相同的外部 IP
云元数据保护
阻止访问云元数据端点:
- AWS:
169.254.169.254 - GCP:
metadata.google.internal、169.254.169.254、http://metadata - Azure:
169.254.169.254 - DigitalOcean:
169.254.169.254
实施检查清单
- 验证 URL scheme 仅为 HTTP/HTTPS
- 解析 DNS 并验证 IP 不是私有或内部地址
- 明确拦截云元数据 IP
- 限制或禁用重定向跟随
- 如果跟随重定向,验证每一跳
- 为请求设置超时时间
- 限制响应大小
- 尽可能使用网络隔离
不安全的文件上传
文件上传必须验证类型、内容和大小,以防止各种攻击。
验证要求
1. 文件类型验证
- 根据允许列表检查文件扩展名
- 验证魔数/文件签名是否与预期类型匹配
- 绝不能只依赖单项检查
2. 文件内容验证
- 读取并验证魔数
- 对于图像:尝试使用图像库处理(以检测格式错误的文件)
- 对于文档:扫描宏和嵌入对象
- 检查多态文件(可被识别为多种类型的文件)
3. 文件大小限制
- 在服务端设置最大文件大小
- 同时配置 Web 服务器/代理限制
- 考虑按文件类型设置限制(图像的限制应小于视频)
常见绕过方式和攻击
| 攻击 | 描述 | 防护措施 |
|---|---|---|
| 扩展名绕过 | shell.php.jpg | 检查完整扩展名,使用允许列表 |
| 空字节 | shell.php%00.jpg | 清理文件名,检查空字节 |
| 双重扩展名 | shell.jpg.php | 仅允许单个扩展名 |
| MIME 类型伪造 | 将 Content-Type 设置为 image/jpeg | 验证魔数 |
| 魔数字节注入 | 在恶意文件前添加有效的魔数字节 | 检查整个文件结构,而不只是文件头 |
| 多态文件 | 同时作为 JPEG 和 JavaScript 有效的文件 | 按预期类型解析文件,无效时拒绝 |
| 含 JavaScript 的 SVG | <svg onload="alert(1)"> | 清理 SVG 或完全禁止 |
| 通过文件上传进行 XXE | 恶意 DOCX、XLSX(它们基于 XML) | 在解析器中禁用外部实体 |
| ZIP 路径穿越 | 压缩包中的 ../../../etc/passwd | 验证解压后的路径 |
| ImageMagick 漏洞利用 | 特制图像 | 保持 ImageMagick 更新,使用 policy.xml |
| 文件名注入 | 文件名中包含 ; rm -rf / | 清理文件名,使用随机名称 |
| Content-Type 混淆 | 浏览器 MIME 类型嗅探 | 设置 X-Content-Type-Options: nosniff |
魔数字节参考
| 类型 | 魔数字节(十六进制) |
|---|---|
| JPEG | FF D8 FF |
| PNG | 89 50 4E 47 0D 0A 1A 0A |
| GIF | 47 49 46 38 |
25 50 44 46 | |
| ZIP | 50 4B 03 04 |
| DOCX/XLSX | 50 4B 03 04(基于 ZIP) |
安全处理上传文件
- 重命名文件:使用随机 UUID 名称,丢弃原文件名
- 存储在 Web 根目录之外:或为上传文件使用单独的域名
- 使用正确的响应头:
Content-Disposition: attachment(强制下载)X-Content-Type-Options: nosniffContent-Type与实际文件类型一致
- 使用 CDN/单独的域名:将上传内容与主应用隔离
- 设置严格的权限:上传的文件不应具有可执行权限
SQL 注入
当用户输入未经妥善处理便被纳入 SQL 查询时,就会发生 SQL 注入。
预防方法
1. 参数化查询(预处理语句) — 首要防御手段
-- VULNERABLE
query = "SELECT * FROM users WHERE id = " + userId
-- SECURE
query = "SELECT * FROM users WHERE id = ?"
execute(query, [userId])
2. 使用 ORM
- 使用会自动进行参数化的 ORM 方法
- 谨慎使用 ORM 中的原始查询方法
- 注意 ORM 特有的注入点
3. 输入验证
- 验证数据类型(整数应为整数)
- 在适用的情况下,对允许的值使用白名单
- 这是纵深防御手段,而非首要防御手段
需要注意的注入点
- WHERE 子句
- ORDER BY 子句(常被忽略——不能使用参数,必须使用白名单)
- LIMIT/OFFSET 的值
- 表名和列名(不能参数化——必须使用白名单)
- INSERT 的值
- UPDATE SET 的值
- 使用动态列表的 IN 子句
- LIKE 模式(还要对通配符进行转义:%、_)
其他防御措施
- 最小权限原则:数据库用户应仅拥有所需的最低权限
- 禁用危险函数:例如 SQL Server 中的
xp_cmdshell - 错误处理:绝不要向用户暴露 SQL 错误
XML 外部实体(XXE)
当 XML 解析器处理用户提供的 XML 中的外部实体引用时,就会产生 XXE 漏洞。
易受攻击的场景
直接输入 XML:
- SOAP API
- XML-RPC
- XML 文件上传
- 配置文件解析
- RSS/Atom Feed 处理
间接输入 XML:
- 在服务端将 JSON/其他格式转换为 XML
- Office 文档(DOCX、XLSX、PPTX 是包含 XML 的 ZIP 文件)
- SVG 文件(基于 XML)
- SAML 断言
- 带有 XFA 表单的 PDF
按语言/解析器进行防护
Java:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setExpandEntityReferences(false);
Python(lxml):
from lxml import etree
parser = etree.XMLParser(resolve_entities=False, no_network=True)
# Or use defusedxml library
PHP:
libxml_disable_entity_loader(true);
// Or use XMLReader with proper settings
Node.js:
// Use libraries that disable DTD processing by default
// If using libxmljs, set { noent: false, dtdload: false }
.NET:
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.XmlResolver = null;
XXE 防护检查清单
- 尽可能完全禁用 DTD 处理
- 禁用外部实体解析
- 禁用外部 DTD 加载
- 禁用 XInclude 处理
- 使用已应用最新补丁的 XML 解析器版本
- 如果需要 DTD,在解析前验证/清理 XML
- 在可行的情况下,考虑使用 JSON 替代 XML
路径遍历
当用户输入控制文件路径,从而允许访问预期目录之外的文件时,就会产生路径遍历漏洞。
易受攻击的模式
# VULNERABLE
file_path = "/uploads/" + user_input
file_path = base_dir + request.params['file']
template = "templates/" + user_provided_template
防护策略
1. 避免在路径中使用用户输入
# Instead of using user input directly
# Use indirect references
files = {'report': '/reports/q1.pdf', 'invoice': '/invoices/2024.pdf'}
file_path = files.get(user_input) # Returns None if invalid
2. 规范化与验证
import os
def safe_join(base_directory, user_path):
# Ensure base is absolute and normalized
base = os.path.abspath(os.path.realpath(base_directory))
# Join and then resolve the result
target = os.path.abspath(os.path.realpath(os.path.join(base, user_path)))
# Ensure the commonpath is the base directory
if os.path.commonpath([base, target]) != base:
raise ValueError("Error!")
return target
3. 输入清理
- 移除或拒绝
..序列 - 移除或拒绝绝对路径标识符(
/、C:) - 将允许的字符列入白名单(字母数字、连字符、下划线)
- 在适用的情况下验证文件扩展名
路径遍历检查清单
- 绝不要直接在文件路径中使用用户输入
- 规范化路径,并验证其是否位于基准目录内
- 在适用的情况下限制文件扩展名
- 使用各种编码和绕过技术进行测试
安全响应头检查清单
在所有响应中包含以下响应头:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: [see XSS section]
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Cache-Control: no-store (for sensitive pages)
JWT 安全
JWT 配置错误可能导致身份验证被完全绕过以及令牌伪造。
漏洞
| 漏洞 | 防护措施 |
|---|---|
alg: none 攻击 | 始终在服务端验证算法,拒绝 none |
| 算法混淆 | 明确指定预期算法,绝不根据令牌推导算法 |
| HMAC 密钥强度不足 | 使用 256 位以上的密码学安全随机密钥 |
| 缺少过期时间 | 始终设置 exp 声明 |
| 令牌存储在 localStorage 中 | 使用 httpOnly、Secure、SameSite=Strict Cookie 存储,绝不存储在 localStorage 中 |
安全实现
// 1. SIGNING
// Always use environment variables for secrets
const secret = process.env.JWT_SECRET;
const token = jwt.sign({
sub: userId,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (15 * 60), // 15 mins (Short-lived)
jti: crypto.randomUUID() // Unique ID for revocation/blacklisting
}, secret, {
algorithm: 'HS256'
});
// 2. SENDING (Cookie Best Practices)
// Protect against XSS and CSRF
res.cookie('token', token, {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
// 3. VERIFYING
// CRITICAL: Whitelist the allowed algorithm
jwt.verify(token, secret, { algorithms: ['HS256'] }, (err, decoded) => {
if (err) {
// Handle invalid token
}
// Trust the payload
});
JWT 检查清单
- 验证时明确指定算法(绝不信任令牌头)
- 拒绝
alg: none - 密钥是 256 位以上的随机数据(不是密码或短语)
- 始终设置并验证
exp声明 - 将令牌存储在 httpOnly Cookie 中(而非 localStorage/sessionStorage)
- 实现刷新令牌轮换(旧刷新令牌在使用后失效)
API 安全
批量赋值
接受未经筛选的请求正文可能导致权限提升。
// VULNERABLE — user can set { role: "admin" } in request body
User.update(req.body)
// SECURE — whitelist allowed fields
const allowed = ['name', 'email', 'avatar']
const updates = pick(req.body, allowed)
User.update(updates)
这适用于任何 ORM/框架——始终明确指定请求可以修改哪些字段。
GraphQL
| 漏洞 | 防护措施 |
|---|---|
| 在生产环境中启用内省 | 在生产环境中禁用内省。 |
| 查询深度攻击 | 限制查询深度(例如,最多 10 层)。 |
| 查询复杂度攻击 | 计算并严格限制查询开销。 |
| 批处理攻击 | 限制单个请求允许的操作数量。 |
const server = new ApolloServer({
introspection: process.env.NODE_ENV !== 'production',
validationRules: [
depthLimit(10),
costAnalysis({ maximumCost: 1000 })
]
})
通用安全原则
生成代码时,务必:
- 在服务端验证所有输入——绝不只依赖客户端验证
- 使用参数化查询——绝不将用户输入拼接到查询中
- 根据上下文对输出进行编码——HTML、JS、URL、CSS 上下文需要不同的编码方式
- 执行身份验证检查——检查每个端点,而不只是路由
- 执行授权检查——验证用户是否有权访问特定资源
- 使用安全的默认设置
- 安全地处理错误——不要向用户泄露堆栈跟踪或内部详细信息
- 及时更新依赖项——使用工具跟踪存在漏洞的依赖项
如有疑问,请选择限制更严格、更安全的选项,并在注释中记录相关安全考量。