检测 OAuth 令牌失窃:Entra ID / Okta API 取证与 Token 重放检测实战指南
【免费下载链接】Anthropic-Cybersecurity-Skills817 structured cybersecurity skills for AI agents · Mapped to 6 frameworks: MITRE ATT&CK, NIST CSF 2.0, MITRE ATLAS, D3FEND, NIST AI RMF & MITRE F3 (Fight Fraud) · agentskills.io standard · Works with Claude Code, GitHub Copilot, Codex CLI, Cursor, Gemini CLI & 20+ platforms · 29 security domains · Apache 2.0项目地址: https://gitcode.com/GitHub_Trending/an/Anthropic-Cybersecurity-Skills
导读
本文是 Anthropic-Cybersecurity-Skills 仓库中detecting-oauth-token-theft技能(SKILL.md)配套的 API 实战参考指南,聚焦微软 Entra ID(Azure AD)与 Okta 两大身份平台下的 OAuth 令牌失窃检测。读完本文,你将掌握:如何通过 Microsoft Graph Sign-In Logs 与 Okta System Log API 检索登录事件、如何基于不可能旅行(Impossible Travel)、令牌重放、新设备与敏感 Scope 四类检测逻辑识别令牌窃取、如何对照高敏 OAuth Scope 评估风险,以及如何把相关检测结果映射到 MITRE ATT&CK 技术编号,形成可落地的取证与检测工作流。
攻击面:哪些令牌会被偷、怎么被偷
要检测令牌失窃,首先需要明确攻击目标。不同令牌类型的生命周期、窃取途径与影响范围差异巨大,SKILL.md 给出了清晰的对比:
| 令牌类型 | 生命周期 | 窃取途径 | 影响 |
|---|---|---|---|
| Access Token(访问令牌) | 60–90 分钟 | 内存转储、代理拦截 | 在令牌有效期内获得 API 访问 |
| Refresh Token(刷新令牌) | 最长 90 天 | 浏览器 Cookie 窃取、恶意软件 | 持久访问,可不断签发新访问令牌 |
| Primary Refresh Token(PRT) | 会话级 | Mimikatz、AADInternals、恶意软件 | 对全部 M365/Azure 应用实现完全 SSO |
| Session Cookie(会话 Cookie) | 不定 | XSS、浏览器漏洞、AitM 代理 | 完全会话劫持 |
| Device Code Token(设备码令牌) | 认证后 15 分钟 | 钓鱼(设备码流程滥用) | 攻击者通过社工获得刷新令牌 |
常见攻击手法包括:AitM 钓鱼(攻击者用 Evilginx2 之类的工具代理合法登录页,在受害者完成 MFA 后截获会话 Cookie 与令牌)、设备码钓鱼(攻击者生成设备码并通过邮件/Teams 发送给受害者,受害者认证后攻击者获取令牌)、PRT 提取(拥有设备本地管理员权限的攻击者使用 Mimikatzsekurlsa::cloudap或 AADInternals 提取主刷新令牌)、以及浏览器 Cookie 窃取(信息窃取类恶意软件外泄含会话令牌的浏览器 Cookie)。
数据源 API:获取登录事件的两种途径
Microsoft Graph Sign-In Logs
Entra ID 的登录日志可以通过 Microsoft Graph 的auditLogs/signIns端点检索。API 参考文档给出了基础查询方式:
# 查询登录日志 curl -H "Authorization: Bearer $MS_TOKEN" \ "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=createdDateTime ge 2025-01-01&\$top=100"注意这里使用了$filter按时间过滤,并用$top限制返回条数(最多 100 条/页,分页需处理@odata.nextLink)。$MS_TOKEN需要通过具有AuditLog.Read.All或Directory.Read.All权限的应用凭据换取。
返回的每个签名事件中,与令牌失窃检测直接相关的字段如下:
| 字段 | 说明 |
|---|---|
| userPrincipalName | 用户邮箱 / UPN |
| ipAddress | 来源 IP 地址 |
| location.city | 地理位置城市 |
| location.geoCoordinates | 经纬度坐标 |
| deviceDetail.deviceId | 设备标识符 |
| resourceDisplayName | 目标资源名称 |
| status.errorCode | 0 表示成功 |
| riskState | none、confirmedCompromised、remediated 等 |
Okta System Log API
对于使用 Okta 的组织,可通过 Okta 的 System Log API 检索身份事件流:
# 查询事件 curl -H "Authorization: SSWS $OKTA_TOKEN" \ "https://your-org.okta.com/api/v1/logs?filter=eventType eq \"user.session.start\"&since=2025-01-01"该 API 使用 SSWS(SSWS API Token)认证,filter参数按eventType过滤(例如会话启动事件user.session.start),since指定起始时间。Okta 的 System Log 还支持q、after(游标分页)等参数,可用于持续拉取增量事件,适配 SIEM 的定时同步场景。
检测逻辑:四类核心检测方法
API 参考文档将令牌失窃检测归纳为四类核心方法,这些检测逻辑正是仓库中 scripts/agent.py 的源码实现基础:
| 检测项 | 方法 |
|---|---|
| 不可能旅行(Impossible travel) | Haversine 距离 / 时间 > 900 km/h |
| 令牌重放(Token replay) | 同一用户在 5 分钟窗口内出现 3+ 个不同 IP |
| 新设备(New device) | 设备 ID 不在已知设备清单中 |
| 可疑 Scope(Suspicious scopes) | 请求了 2 个以上敏感 OAuth Scope |
不可能旅行:Haversine 公式源码实现
agent.py中的detect_impossible_travel函数是这一检测的完整实现。它按用户分组登录事件并按时间排序,对相邻两条事件计算大圆距离与时间差,得出“移动速度”并判定是否超过阈值:
EARTH_RADIUS_KM = 6371 def haversine(lat1, lon1, lat2, lon2): """计算两点之间的大圆距离(千米)""" lat1, lon1, lat2, lon2 = map(math.radians, [lat1, lon1, lat2, lon2]) dlat = lat2 - lat1 dlon = lon2 - lon1 a = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2 return 2 * EARTH_RADIUS_KM * math.asin(math.sqrt(a))检测主逻辑中,speed = dist / hours计算两点间的等效移动速度,当speed > max_speed_kmh and dist > 100(即速度超过阈值且距离超过 100 公里)时产生HIGH严重级别的impossible_travel告警。max_speed_kmh默认值 900 与 API 参考文档中“900 km/h”的判定阈值完全对应,也可以通过命令行参数--max-speed调整。
令牌重放:滑动时间窗口去重
detect_token_replay使用 5 分钟(300 秒)的滑动窗口,统计同一用户在该窗口内出现的不同 IP 数:
window = [e for e in window if (ts - datetime.datetime.fromisoformat( e["timestamp"].replace("Z", "+00:00"))).total_seconds() < 300] window.append(event) unique_ips = set(e.get("ip") for e in window if e.get("ip")) if len(unique_ips) >= 3: # 产生 CRITICAL 级别的 token_replay 告警当同一用户在 5 分钟内出现 3 个以上不同 IP 时,判定为令牌被复制到多个位置同时使用,产生CRITICAL严重级别告警——这与 API 参考文档“Same user, 3+ IPs within 5 min window”的规则逐字对应。
新设备与可疑 Scope
detect_new_device将事件中的device_id(缺省时回退到user_agent)与已知设备清单比对,出现未知设备即产生MEDIUM级别new_device告警,对应“Device ID not in known device inventory”。detect_suspicious_scopes内置敏感 Scope 集合,当单次 OAuth 请求同时请求 2 个以上敏感 Scope 时产生HIGH级别suspicious_scopes告警,对应“2+ sensitive OAuth scopes requested”。
agent.py支持--log-file指定 JSON 格式登录事件文件、-o/--output输出 JSON 报告;不指定--log-file时会以内置的演示数据运行(alice 用户在纽约与伦敦 30 分钟内登录、bob 用户请求了 3 个敏感 Scope),便于快速验证检测逻辑。
敏感 OAuth Scope 清单(微软)
评估令牌请求风险的核心依据是所请求的 Scope 权限。API 参考文档给出了微软生态中的高风险 Scope 及其风险含义:
| Scope | 风险 |
|---|---|
| Mail.ReadWrite | 邮箱读写访问 |
| Mail.Send | 以用户身份发送邮件(Send-as) |
| Files.ReadWrite.All | 全部文件访问 |
| Directory.ReadWrite.All | 修改 Active Directory |
| Application.ReadWrite.All | 应用注册管理 |
agent.py的detect_suspicious_scopes在上述基础上进一步扩展了User.ReadWrite.All与RoleManagement.ReadWrite.Directory,覆盖用户资料改写与角色管理等高权限范围。实战中应结合应用的真实业务需求审查 Scope:一个仅用于“发送待办提醒”的应用如果请求Directory.ReadWrite.All,就应触发告警。
从日志到告警的完整检测工作流
API 参考文档解决的是“拿到什么数据、看哪些字段、按什么规则判”,而 SKILL.md 提供了在 Entra ID 环境中的完整落地流程,二者配合使用:
- 启用 Entra ID 登录风险检测:在
Entra Admin Center > Protection > Identity Protection > Risk Detections中启用风险检测,重点关注 Anomalous Token、Token Issuer Anomaly、Unfamiliar Sign-in、Impossible Travel、Malicious IP Address、Suspicious Browser 等与令牌窃取直接相关的检测项;并配置基于风险的条件访问策略——“高风险登录阻断”“中风险登录要求 MFA + 改密”。 - 启用 Token Protection(预览):通过条件访问策略将会话令牌与设备绑定(Windows 平台 + 合规设备/混合 Azure AD 加入设备),访问令牌被密码学绑定到设备 TPM,攻击者在其他设备上重放令牌会被拒绝。
- 在登录日志中检索令牌重放指标:使用 KQL 在 Sentinel/Log Analytics 中检测“令牌签发地与使用地不一致”“一小时内多地登录”“deviceCode 认证协议滥用”“同一 CorrelationId 多 IP”等模式。
- 调查与响应:通过 Microsoft Graph PowerShell 撤销会话(
Revoke-MgUserSignInSession)、强制改密(Update-MgUser)、审查并移除恶意 OAuth 授权(Get-MgUserOauth2PermissionGrant/Remove-MgOauth2PermissionGrant)、排查可疑企业应用(Get-MgServicePrincipal)与邮件转发规则(Get-MgUserMailFolderRule)。 - 启用持续访问评估(CAE):让令牌撤销在数分钟内生效,而不是等待 60–90 分钟的令牌自然过期;账户被禁用/删除、密码变更、MFA 启用、管理员撤销刷新令牌、Identity Protection 检测到高风险、网络位置违反条件访问策略等关键事件都会立即触发令牌撤销。
- 配置 Defender for Cloud Apps 会话策略:例如“阻止未托管设备使用失窃令牌下载文件”“5 分钟超过 10 次下载的批量下载行为告警”,用于实时会话监控与阻断。
MITRE ATT&CK 映射
将检测到的行为映射到 ATT&CK 技术编号,便于与威胁情报、SOC 剧本和覆盖率矩阵对齐:
| 技术 | 描述 |
|---|---|
| T1528 | 窃取应用程序访问令牌(Steal Application Access Token) |
| T1550.001 | 使用替代认证材料:应用程序访问令牌复用(Application Access Token reuse) |
| T1078.004 | 有效账户:云账户(Cloud Accounts) |
从 SKILL.md 的 frontmatter 看,该技能还关联了 T1530(从云存储收集数据)、T1537(转移到云账户)、T1580(云基础设施发现),并进一步映射到 MITRE Fight Fraud Framework(F3 v1.1)的欺诈战术——例如 F1004(使用被盗会话 Cookie 访问)、F1006(账户接管)、T1539(窃取 Web 会话 Cookie)、T1557(中间人)、T1185(浏览器会话劫持),覆盖initial-access与positioning两个战术。关于 F3 的映射规范可参考 docs/mitre-f3-mapping.md。
若需可视化本仓库的 ATT&CK 覆盖情况,可将 mappings/attack-navigator-layer.json 导入 MITRE ATT&CK Navigator 查看,其中蓝色深浅代表技能覆盖密度(浅蓝 1–2 个技能引用、中蓝 3–5、深蓝 6–10、最深 11+)。
验证清单与适用边界
实践该方案时,建议逐项确认(对应 SKILL.md 的 Verification 章节):
- Identity Protection 风险检测已启用并产生异常令牌活动告警;
- 条件访问策略已阻断高风险登录、对中风险要求 MFA;
- Token Protection 策略已在试点组生效(从未注册设备访问应失败);
- KQL 查询在 Sentinel 中对合成令牌异常事件能返回结果;
- CAE 已启用并验证(撤销会话后数分钟内访问被阻断);
- Defender for Cloud Apps 会话策略已监控下载活动;
- 设备码流程已通过条件访问限制(阻断或要求合规设备);
- 响应手册包含令牌撤销、改密与 OAuth 授权审查步骤;
- 对被攻陷账户的邮件转发规则与 OAuth 应用授权已完成审计。
需要强调的是,本文方案仅适用于云身份令牌(OAuth/OIDC)失窃场景:本地 Kerberos 票据攻击(Pass-the-Ticket、Golden Ticket)不在本技能范围内,应使用 Active Directory 专项调查技术。另外,使用本仓库的 scripts/agent.py 前需确认环境已安装requests(可选依赖);该脚本默认以内置演示数据运行,正式使用请通过--log-file传入经 Graph/Okta API 拉取的真实登录事件 JSON。
【免费下载链接】Anthropic-Cybersecurity-Skills817 structured cybersecurity skills for AI agents · Mapped to 6 frameworks: MITRE ATT&CK, NIST CSF 2.0, MITRE ATLAS, D3FEND, NIST AI RMF & MITRE F3 (Fight Fraud) · agentskills.io standard · Works with Claude Code, GitHub Copilot, Codex CLI, Cursor, Gemini CLI & 20+ platforms · 29 security domains · Apache 2.0项目地址: https://gitcode.com/GitHub_Trending/an/Anthropic-Cybersecurity-Skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考