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

如何合规Sanitize SOQL返回URL以消除Snyk的SSRF漏洞告警(无法硬编码)

APEX中Snyk SSRF告警的白名单解决方案(自定义元数据场景)

我有如下APEX代码:

MyType mdt = [
    SELECT Token_Endpoint__c 
    FROM Google_OAuth2__mdt 
    LIMIT 1
];
String tokenEndpoint = mdt.Token_Endpoint__c;

HttpRequest req = new HttpRequest();
req.setEndpoint(tokenEndpoint);

Snyk代码检测指出req.setEndpoint调用存在**服务器端请求伪造(SSRF)**漏洞,该检测结果合理,但我尝试的白名单方案都无法绕过告警:

Snyk告警内容:

Unsanitized input from a SOQL statement flows into setendpoint, where it is used as an URL to perform a request. This may result in a Server-Side Request Forgery vulnerability.

✗ [High] Server-Side Request Forgery (SSRF)

我试过两种白名单方式,均触发告警(注:原代码存在逻辑错误,校验时未使用元数据获取的tokenEndpoint,而是直接写死了白名单值,即使修复后仍无法绕过Snyk检测):

  1. 白名单Set校验:
String tokenEndpoint = mdt.Token_Endpoint__c;
Set<String> allowList = new Set<String>{'https://foo/...'};
if (!allowList.contains(tokenEndpoint)) {
    throw new IllegalArgumentException('Invalid endpoint');
}
HttpRequest req = new HttpRequest();
req.setEndpoint(tokenEndpoint);
  1. Map映射校验:
String tokenEndpoint = mdt.Token_Endpoint__c;
Map<String, String> allowList = new Map<String, String>{{'https://foo/...', 'https://foo/...'}};
if (!allowList.containsKey(tokenEndpoint)) {
    throw new IllegalArgumentException('Invalid endpoint');
}
HttpRequest req = new HttpRequest();
req.setEndpoint(allowList.get(tokenEndpoint));

目前只有硬编码URL能让Snyk认可安全性,但这不符合我通过自定义元数据管理配置的需求,需要可行的解决方案。


可行的解决方案

方案1:自定义元数据存标识,代码映射到硬编码URL

这种方式既保留配置灵活性(元数据控制启用哪个端点),又让Snyk识别到实际使用的是硬编码的安全URL:

MyType mdt = [
    SELECT Endpoint_Identifier__c 
    FROM Google_OAuth2__mdt 
    LIMIT 1
];

// 硬编码合法URL映射
Map<String, String> endpointMap = new Map<String, String>{
    'GOOGLE_TOKEN' => 'https://oauth2.googleapis.com/token',
    'FOO_SERVICE' => 'https://foo/...'
};

String validEndpoint = endpointMap.get(mdt.Endpoint_Identifier__c);
if (validEndpoint == null) {
    throw new IllegalArgumentException('Invalid endpoint identifier');
}

HttpRequest req = new HttpRequest();
req.setEndpoint(validEndpoint);

原理:Snyk会追踪到validEndpoint来自硬编码的Map,而非直接来自SOQL查询的用户可控输入,因此不会触发SSRF告警。

方案2:严格解析并校验URL的核心部分

通过URL类解析元数据中的URL,校验协议、域名等关键部分,然后重构安全的URL字符串:

MyType mdt = [
    SELECT Token_Endpoint__c 
    FROM Google_OAuth2__mdt 
    LIMIT 1
];

String rawEndpoint = mdt.Token_Endpoint__c;
URL parsedUrl;
try {
    parsedUrl = new URL(rawEndpoint);
} catch (MalformedURLException e) {
    throw new IllegalArgumentException('Invalid URL format');
}

// 白名单校验:仅允许HTTPS协议,且域名在合法列表内
Set<String> allowedDomains = new Set<String>{'oauth2.googleapis.com', 'foo.com'};
if (!parsedUrl.getProtocol().equals('https') || !allowedDomains.contains(parsedUrl.getHost())) {
    throw new IllegalArgumentException('Unauthorized endpoint');
}

// 使用解析后的安全部分重构URL(避免原字符串中的恶意参数)
String safeEndpoint = parsedUrl.getProtocol() + '://' + parsedUrl.getHost() + parsedUrl.getPath();

HttpRequest req = new HttpRequest();
req.setEndpoint(safeEndpoint);

原理:Snyk能识别到代码对URL做了严格的解析和校验,仅保留安全的协议、域名和路径,阻断了恶意输入的可能性。

方案3:使用枚举类管理合法端点

定义枚举类存储所有合法URL,元数据存储枚举值的名称,代码中转换为枚举对应的URL:

public enum ValidEndpoints {
    GOOGLE_TOKEN('https://oauth2.googleapis.com/token'),
    FOO_SERVICE('https://foo/...');

    public final String url;
    ValidEndpoints(String url) {
        this.url = url;
    }
}

// 获取元数据配置
MyType mdt = [
    SELECT Endpoint_Name__c 
    FROM Google_OAuth2__mdt 
    LIMIT 1
];

ValidEndpoints selectedEndpoint;
try {
    selectedEndpoint = ValidEndpoints.valueOf(mdt.Endpoint_Name__c);
} catch (IllegalArgumentException e) {
    throw new IllegalArgumentException('Invalid endpoint name');
}

HttpRequest req = new HttpRequest();
req.setEndpoint(selectedEndpoint.url);

原理:枚举类的URL是硬编码的,Snyk会认为这是安全的输入,同时元数据仅用于选择枚举值,不会引入可控风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 23:12:06