You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复Spring Boot中CodeQL检测到的RestTemplate SSRF漏洞

修复Spring Boot中CodeQL检测出的SSRF问题

问题分析

你的代码中,UriComponentsBuilder基于getUserUrl()构造请求URL并传入用户可控的userId参数。CodeQL触发SSRF告警,核心原因是当前的UTILITY.isValidUrl()仅验证URL格式合法性,无法阻止攻击者通过篡改getUserUrl()或userId参数,诱导服务器请求恶意内部/外部地址。

具体修复方案

1. 实现域名/IP白名单验证

替换原有仅校验格式的逻辑,只允许请求预先定义的可信服务地址:

// 定义可信域名白名单(根据实际业务调整)
private static final Set<String> ALLOWED_DOMAINS = Set.of("trusted-user-service.com", "internal-user-api.company.com");

public boolean isTrustedUrl(String url) {
    try {
        URI uri = new URI(url);
        String host = uri.getHost();
        // 检查域名是否在白名单内,同时禁止访问私有IP段
        return ALLOWED_DOMAINS.contains(host) && !isPrivateIp(host);
    } catch (URISyntaxException e) {
        return false;
    }
}

// 辅助方法:判断是否为私有IP地址
private boolean isPrivateIp(String host) {
    try {
        InetAddress address = InetAddress.getByName(host);
        return address.isSiteLocalAddress() || address.isLoopbackAddress() || address.isLinkLocalAddress();
    } catch (UnknownHostException e) {
        return false;
    }
}

在业务代码中替换原验证逻辑:

boolean isValid = isTrustedUrl(builder.toUriString());

2. 严格转义用户输入参数

对userId进行URL编码,防止攻击者通过注入特殊字符(如@、/、%2F)篡改URL结构:

// 对userId进行URL编码,避免注入风险
String encodedUserId = UriUtils.encode(userId, StandardCharsets.UTF_8.name());
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(getUserUrl())
        .queryParam("userId", encodedUserId);

3. 配置RestTemplate的安全限制

禁止RestTemplate自动跟随重定向,防止被诱导请求恶意地址;同时限制仅允许HTTP/HTTPS协议:

@Bean
public RestTemplate safeRestTemplate() {
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    // 禁止自动重定向
    factory.setFollowRedirects(false);
    
    RestTemplate restTemplate = new RestTemplate(factory);
    
    // 添加拦截器,二次校验请求地址的合法性
    restTemplate.getInterceptors().add((request, body, execution) -> {
        URI uri = request.getURI();
        if (!"http".equals(uri.getScheme()) && !"https".equals(uri.getScheme())) {
            throw new IllegalArgumentException("仅允许HTTP/HTTPS协议请求");
        }
        if (!isTrustedUrl(uri.toString())) {
            throw new IllegalArgumentException("请求地址不在可信范围内");
        }
        return execution.execute(request, body);
    });
    
    return restTemplate;
}

之后在业务代码中注入这个安全配置的RestTemplate,替代原有实例。

4. 确保getUserUrl()不可被用户控制

如果getUserUrl()的取值来自用户输入或外部配置,必须额外验证其合法性,禁止传入任意地址。建议将可信服务地址配置在环境变量或配置文件中,而非由用户传入。

最终修改后的代码示例

@RequestMapping(value = "/data", method = RequestMethod.GET)
public ResponseEntity<List<User>> getUserDetails(@Valid String userId) {
    // 转义用户输入参数
    String encodedUserId = UriUtils.encode(userId, StandardCharsets.UTF_8.name());
    UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(getUserUrl())
            .queryParam("userId", encodedUserId);
    
    // 验证请求地址是否可信
    boolean isValid = isTrustedUrl(builder.toUriString());
    ResponseEntity<String> result = null;
    
    if (isValid) {
        result = safeRestTemplate.exchange(builder.toUriString(), HttpMethod.GET, null, String.class);
    }
    
    // 后续业务转换逻辑...
    return ResponseEntity.ok(convertToUserList(result.getBody()));
}

内容的提问来源于stack exchange,提问作者Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:37:45