从“代码能跑”到“代码安全”:使用华为云 CodeArts Agent 审查 Spring Boot 接口越权风险
从“代码能跑”到“代码安全”:使用华为云 CodeArts Agent 审查 Spring Boot 接口越权风险
关键词:华为云码道、CodeArts Agent、代码审查、Spring Boot、IDOR、BOLA、Java、Git
说明:本文以模拟的订单查询接口为例演示审查流程,代码与测试均为教学示例,不代表已在真实生产项目中执行扫描或验证。
一、为什么代码审查不能只看功能是否正常?
在 Java Web 项目中,一个接口返回 200 OK,只能说明它完成了当前请求,并不能证明业务权限正确。
假设订单详情接口为:
GET /api/orders/1001
Authorization: Bearer <token>
开发人员通常会优先检查参数是否正确、订单是否存在、数据库查询是否正常,却容易忽略一个问题:当前登录用户是否有权访问这笔订单?
如果后端只根据订单 ID 查询,攻击者就可能通过修改路径参数访问其他用户的订单。这类问题通常被称为 IDOR(不安全的直接对象引用),也可归入 API 场景中的 BOLA(对象级授权失效)。
相比单纯生成代码,AI 的另一个值得尝试的用法,是让它作为代码审查助手,帮助团队定位这类容易遗漏的授权边界。
二、CodeArts Agent 能承担哪些审查工作?
根据华为云官方文档,码道 Agent Space 提供代码审查功能。在 Git 仓库中,可以切换到 AgentTeam 模式,并通过包含 code-reviewer 关键字的提示词触发审查。
它支持针对当前工作目录的代码变更,或指定提交(commit)的变更进行分析。当前官方文档列出的可审查语言包括 Java、Python、JavaScript/TypeScript、C/C++ 和 Go;JSON、Markdown、CSS 等非代码文件不属于该功能的审查范围。
需要注意两个边界:
- **内置
code-reviewer的审查对象主要是 Git 变更。**如果要检查尚未修改的历史代码,可以在普通智能体对话中显式添加相关文件及调用链,要求其辅助分析;不要把这两种工作方式混为一谈。 - **AI 审查结果属于风险线索,不是安全证明。**是否真的存在漏洞,仍需要结合身份认证方式、业务规则及测试结果判断。
三、实战案例:一个存在越权风险的订单接口
下面是一个刻意简化的 Spring Boot + Spring Data JPA 示例:
@RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@GetMapping("/{orderId}")
public OrderDTO detail(@PathVariable Long orderId) {
return orderService.getOrder(orderId);
}
}
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
public OrderDTO getOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new ResponseStatusException(
HttpStatus.NOT_FOUND, "订单不存在"));
return OrderDTO.from(order);
}
}
从功能角度看,这段代码没有明显的问题:传入存在的订单 ID,就可以获取订单详情。但是,findById(orderId) 完全没有验证请求者是否为订单所有者。
风险点不在于 SQL 能否执行,而在于查询条件缺少用户授权约束。
如果某个系统还依赖前端传入的 userId 判断归属,同样存在风险,因为请求参数可以被客户端篡改。
四、让 CodeArts Agent 先给证据,再给建议
在使用前,建议先切换到独立 Git 分支,并通过 git status 检查本地变更,避免混入无关文件。
1. 审查当前代码变更
在 CodeArts Agent Space 的 AgentTeam 模式中输入:
使用 code-reviewer 检视当前代码修改。
重点关注 Spring Boot 接口的对象级授权(BOLA/IDOR)、
身份信息来源、SQL 注入风险和敏感字段返回。
请列出涉及的文件与方法,说明攻击成立的前提,
区分“已确认的问题”与“需要进一步验证的风险”。
先给出报告,不要直接修改代码。
如果需要审查一个指定提交,可按官方文档采用“使用 code-reviewer 检视 <commitId> 对应的代码修改”的表达,其中 <commitId> 替换成实际 Git 提交 SHA。
完成后,可以到项目的 .codeartsdoer/review/ 目录查看本次审查生成的文件夹。其 report/review.json 可用来复核审查结果;报告格式以实际安装版本为准。
2. 要求进一步追踪权限调用链
对疑似越权问题,还可以添加 Controller、Service、Repository 及认证相关代码文件,在对话中补充:
请沿 Controller -> Service -> Repository 追踪订单详情接口。
明确回答:
1. 当前用户身份从哪里获取?是否来自已验证的认证上下文?
2. 查询是否限定订单归属?
3. 普通用户能否查询其他人的订单?
4. 应该在哪一层增加对象级授权?
5. 需要增加哪些允许/拒绝访问的测试?
请引用具体方法,并说明你无法从现有代码确认的前提。
这里最重要的一句是:“说明你无法确认的前提。” 它能减少 AI 在上下文不足时直接给出确定结论的情况。
五、修复思路:身份由服务端确定,查询绑定归属
订单详情接口不应该把客户端传入的用户 ID 当成授权依据。正确思路是从服务端已校验的认证上下文获取当前用户身份,再把订单 ID 与归属用户 ID 一起传入查询条件。
以下示例假设项目已配置 Spring Security,且认证主体对象有可访问的 id 属性;具体项目需根据实际 Principal 类型调整。
@RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@GetMapping("/{orderId}")
public OrderDTO detail(
@PathVariable Long orderId,
@AuthenticationPrincipal(expression = "id") Long currentUserId) {
return orderService.getOrder(orderId, currentUserId);
}
}
public interface OrderRepository extends JpaRepository<Order, Long> {
Optional<Order> findByIdAndOwnerId(Long id, Long ownerId);
}
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
public OrderDTO getOrder(Long orderId, Long currentUserId) {
Order order = orderRepository
.findByIdAndOwnerId(orderId, currentUserId)
.orElseThrow(() -> new ResponseStatusException(
HttpStatus.NOT_FOUND, "订单不存在"));
return OrderDTO.from(order);
}
}
这样,即使用户猜到了其他人的订单 ID,也无法仅凭 ID 读取该订单。
这里统一返回 404 Not Found 是一种减少对象是否存在信息泄漏的设计选择,但并非所有业务都必须如此。管理员、客服代查、跨租户权限等场景,需要额外定义明确的业务规则;不能简单地把“当前用户 = 订单所有者”当作所有系统的完整授权模型。
此外,订单实体中的 ownerId 字段、认证主体映射以及接口认证要求,都需要在真实工程中正确实现。上面只展示与权限检查直接相关的部分。
六、不要只让 AI 写修复代码,还要让它补反例测试
很多代码审查任务只进行到“AI 已经把代码改好了”就结束了。但对于越权风险,拒绝路径比正常路径更能证明修复有效。
可以继续向 CodeArts Agent 输入:
请为订单详情查询补充 JUnit 5 + Mockito 测试:
- 订单属于当前用户:允许查询;
- 订单属于其他用户:无法查询;
- 订单不存在:返回 404;
- 不要使用过于宽泛的断言;
- 不要修改生产逻辑来迎合测试;
- 先列出测试场景,再生成代码。
其中一个示例测试如下:
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Mock
private OrderRepository orderRepository;
@InjectMocks
private OrderService orderService;
@Test
void shouldNotReadAnotherUsersOrder() {
Long orderId = 1001L;
Long currentUserId = 7L;
when(orderRepository.findByIdAndOwnerId(orderId, currentUserId))
.thenReturn(Optional.empty());
ResponseStatusException ex = assertThrows(
ResponseStatusException.class,
() -> orderService.getOrder(orderId, currentUserId)
);
assertEquals(HttpStatus.NOT_FOUND, ex.getStatusCode());
verify(orderRepository).findByIdAndOwnerId(orderId, currentUserId);
}
}
这个单元测试可以确认 Service 使用了含用户条件的查询,并在没有匹配记录时拒绝返回,但不能单独证明整个接口不存在越权。完整验收还应通过带不同用户凭证的集成测试,确认认证主体被正确解析、SQL 确实包含归属条件,且所有绕过路径被覆盖。
七、可以沉淀为团队统一的代码审查规范
华为云文档还支持使用 Rule(规则)约束智能体行为,以及通过 Skill(技能)封装可复用的任务流程。对于团队开发,可以把审查规范从一次性提示词转成项目级约定。
例如,团队可以规定:
| 审查维度 | 必查问题 | 验收证据 |
|---|---|---|
| 身份认证 | 是否存在匿名访问或从请求参数伪造身份 | 安全配置、认证测试 |
| 对象授权 | 是否校验资源归属、租户范围和角色权限 | 数据查询条件、拒绝访问测试 |
| SQL 安全 | 是否拼接用户输入构造 SQL | 参数绑定方式、静态扫描 |
| 敏感信息 | DTO 是否泄露内部字段 | 响应结构审查、接口测试 |
| 变更质量 | 是否引入无关修改或破坏兼容性 | Git Diff、回归测试 |
此外,提交到仓库的 Rule / Skill 应像普通代码一样接受评审和版本管理。AI 工具可以帮助发现问题,但最终是否合并仍应由开发人员负责判断。
八、总结
这次案例最值得强调的,不是“AI 能发现一个越权漏洞”,而是把代码审查拆成一条可以反复执行的工程流程:
准备 Git 变更 → 调用 CodeArts Agent 审查 → 追踪权限调用链 → 小范围修复 → 编写拒绝路径测试 → 人工复核与回归。
对于 Java 后端项目,建议从权限边界明确、风险相对集中的接口开始,例如订单详情、文件下载、用户资料和租户数据查询,再逐步推广到其他模块。
CodeArts Agent 可以降低审查的启动成本,帮助开发者更快地形成检查清单。但真正决定系统安全性的,仍是明确的授权模型、可信的身份来源和可复现的测试证据。
- 点赞
- 收藏
- 关注作者
评论(0)