oauth device code流程仅提供单向认证:用户通过验证verification_uri域名确认授权服务器身份,设备端不校验服务器身份,导致攻击者可利用合法子域名和ui欺骗诱导用户授权,从而窃取令牌。

OAuth Device Code 流程本身不提供服务器身份认证能力,它是一个客户端授权机制,核心目标是让无输入能力或输入受限的设备(如智能电视、IoT终端、CLI工具)安全地获得用户授权,而非验证服务器身份。
设备码流程中谁在认证?认证什么?
该流程中只有单向认证:用户端对授权服务器的身份有隐含依赖,但协议本身不强制执行服务器身份校验。具体来说:
- 设备客户端向授权服务器发起请求时,只提交 client_id 和 scope,不验证对方是否为合法授权方
- 用户在另一设备上访问 verification_uri(如 https://microsoft.com/device)时,需自行判断域名真实性——这是唯一可落地的“服务器身份确认”环节
- 标准未要求设备端校验证书、校验 TLS 指纹或验证 OIDC 发行者(issuer)字段,因此无法抵御中间人或仿冒授权页攻击
为什么容易被用于钓鱼攻击?
根本原因在于流程设计默认信任用户能识别官方域名,而现实里用户常忽略地址栏细节:
- Tycoon2FA 等工具通过 Trustifi 链接跳转,最终落地页使用合法子域名(如 device-login-xyz.microsoft.com),绕过传统恶意域名检测
- 用户看到“Microsoft”字样和相似 UI,直接输入 user_code,授权即完成,全程不暴露密码也不触发 MFA 二次验证
- 攻击者拿到 device_code 后,轮询换取 access_token,等同于用户主动授予了长期访问权限
实际部署中如何补足服务器身份认证?
不能依赖协议原生能力,必须在实现层叠加防护措施:
- 设备端发起 device_authorization 请求时,必须校验授权服务器 TLS 证书有效性,并显式配置可信 CA 或固定证书指纹
- 返回的 verification_uri 必须白名单校验:只允许 microsoft.com、google.com、baidu.com 等已知合法根域及其预定义子路径
- 用户扫码或输入 user_code 前,设备端应在本地显示 verification_uri 的完整域名并高亮标注(如 “✅ 正确来源:login.microsoftonline.com”)
- 企业环境应启用 Conditional Access 策略,限制 device code 流程仅允许从特定 IP 段或已注册设备发起
开发者必须避开的典型误区
很多实现把安全责任完全推给用户,导致防御形同虚设:
- 用 file_get_contents 或 curl 调用 device_authorization 端点却不校验证书(尤其 PHP 默认关闭 CURLOPT_SSL_VERIFYPEER)
- 把 verification_uri 直接嵌入 WebView 加载,而非跳转系统浏览器——WebView 无法展示真实地址栏,用户无法核验域名
- 未对 user_code 格式做长度与字符集校验(如微软要求 8 位大写字母+数字组合),导致伪造 code 提前触发轮询
- 轮询 access_token 时未设置合理间隔(











