开发安全红线
以下规则违反会导致安全漏洞。你在编写任何代码时都必须遵守。
SQL 注入防护
使用 #{} 参数化查询
xml
<!-- 正确:#{} 预编译参数 -->
<select id="selectByName">
SELECT * FROM sys_user WHERE username = #{username}
</select>
<!-- 禁止:${} 字符串拼接,SQL 注入风险 -->
<select id="selectByName">
SELECT * FROM sys_user WHERE username = '${username}'
</select>${} 仅允许用于动态表名、动态排序字段等不可参数化的场景,且必须做白名单校验:
java
// 校验排序字段白名单
private static final Set<String> ALLOWED_SORT = Set.of("create_time", "update_time", "id");
if (!ALLOWED_SORT.contains(sortField)) {
throw new BusinessException("非法排序字段");
}XSS 过滤
- 用户输入内容存储前不做转义,输出到 HTML 时转义
- Vue 模板默认转义
,禁止使用v-html渲染用户输入 - 富文本内容必须经过白名单过滤后存储
vue
<!-- 安全:自动转义 -->
<span>{{ user.nickname }}</span>
<!-- 危险:v-html 渲染用户输入 -->
<div v-html="user.description"></div>密码与密钥安全
| 规则 | 说明 |
|---|---|
| 密码存储 | 必须使用 BCrypt 加密,禁止明文或 MD5 |
| 密钥管理 | 禁止硬编码 AK/SK、数据库密码、API Key |
| 配置文件 | 密钥使用环境变量注入,不提交到代码 |
| 前端脱敏 | API Key/Secret 返回前端必须脱敏(前4后4,中间 ****) |
java
// 正确:BCrypt 加密
passwordEncoder.encode(rawPassword);
// 禁止:明文存储
user.setPassword(rawPassword);
// 脱敏
String masked = apiKey.substring(0, 4) + "****" + apiKey.substring(apiKey.length() - 4);日志安全
| 禁止打印 | 示例 |
|---|---|
| 手机号 | 13800138000 |
| 身份证号 | 110101199001011234 |
| 银行卡号 | 6222021234567890 |
| 密码 | 任何形式的密码 |
| Token | Bearer eyJ... |
java
// 正确:脱敏后打印
log.info("用户手机号: {}****{}", phone.substring(0, 3), phone.substring(7));
// 禁止:完整打印
log.info("用户手机号: {}", phone);接口安全
- 所有业务接口必须经过认证(
SaTokenInterceptor) - 敏感接口使用
@ApiEncrypt/@ApiDecrypt加密传输 - 文件上传必须校验文件类型和大小
- 批量操作接口限制单次最大数量(如 100 条)
涉及资金与权限
涉及资金流转、状态变更、权限变更的操作,必须在 Spec 中标注并经人工审查:
java
// 资金操作:必须记录操作日志
@OperationLog(value = "订单退款", detail = "订单号: #{#orderNo}")
@PostMapping("/refund")
@SaCheckPermission("biz:order:refund")
public RespInfo refund(@RequestBody RefundDTO dto) {
return RespInfo.success(orderService.refund(dto));
}