认证相关逻辑、风险及漏洞总结

-- 普通认证逻辑漏洞 --

验证绕过/利用


验证形式

  • 图形验证码:
    生成图形的二进制数据(通常是base64加密后的)同时生成 跟验证码绑定的token 并返回(通过参数/Cookie),
    验证时只有 提交token和 对应图形中的字符串 才可验证通过
  • 滑块验证码:
    生成 带缺口的背景图 滑块图, 同时生成 跟验证码绑定的token 并返回(通过参数/Cookie),
    前端计算并提交 token 和 用户拖动滑块过程中采集位置、时间、行为特征(判断是否符合人类操作规律)等数据,
    全部通过才可验证成功
  • 手机/邮箱验证码:
    向手机/邮箱发送短信, 并返回与该消息绑定的token(通过参数/Cookie),
    验证时只有 提交token和 对应短信内容 才可验证通过 (注: 有时无token),
    有时验证是和后续业务功能(如注册/重置密码)是用的同一个接口,
    有时是验证接口验证通过后, 返回通过标识(Cookie/参数/认证头), 后续业务接口会验证该标识
  • 密码验证
    输入正确的账户与密码才可通过验证(账户可能是用Cookie标识, 或直接传参数)
    有时验证是和后续业务功能(如重置密码)是用的同一个接口,
    有时是验证接口验证通过后, 返回通过标识(Cookie/参数/认证头), 后续业务接口会验证该标识

图形验证码绕过

  • 可复用: 认证错误/成功后token和验证码未失效, 所以可以复用
  • 回显验证码内容: 生成验证码的接口会回显验证码内容

密码验证绕过

  • 通过标识通用
    情景: 验证接口验证通过后, 返回通过标识(Cookie/参数/认证头), 后续业务接口会验证该标识时
    后续业务接口只验证 通过标识是否存在, 而不验证 通过标识是否来源于对应账户(即未与账户绑定),
    导致后续业务接口 可以使用其它账户的 验证通过标识, 从而绕过验证
  • 无效验证:
    情景: 验证接口验证通过后, 才会调用实际的业务接口(如重置密码), 但实际业务接口可以直接调用而无需验证
  • 爆破: 当站点没有限制必须使用复杂密码 且无最大错误次数时, 可通过暴力破解账户的密码
  • 空密码登录: 由于密码校验存在漏洞, 可以通过空密码/0来进行登录

手机/邮箱验证码绕过

  • token通用:
    情景: 验证逻辑是-验证是和后续业务功能(如注册/重置密码)是用的同一个接口时,
    接口只验证token是否与短信内容匹配, 而不验证token是否来源于对应手机/邮箱(即token未与手机/邮箱绑定),
    从而可以利用其它手机/邮箱的短信内容和token 绕过验证
  • 通过标识通用
    情景: 验证接口验证通过后, 返回通过标识(Cookie/参数/认证头), 后续业务接口会验证该标识时
    后续业务接口只验证 通过标识是否存在, 而不验证 通过标识是否来源于对应手机/邮箱(即未与手机/邮箱绑定),
    导致后续业务接口 可以使用其它手机/邮箱的验证通过标识, 从而绕过验证
  • 无效验证:
    情景: 验证接口验证通过后, 才会调用实际的业务接口(如登录/注册), 但实际业务接口可以直接调用而无需验证
  • 验证可爆破(未设置最大错误次数):
    由于验证码验证时未设置最大错误次数/错误后不弃用, 且验证码简单(如四位数验证码), 所以可以爆破来猜解验证码
  • 可发送多个目标
    可同时选择多个目标发送验证码, 且此时可能会给二者发送同样的验证码, 从而绕过
    常见格式: phone=13888888888,13999999999 phone=13888888888&13999999999
  • 邮箱验证码发可猜解链接
    对于发送的是链接的验证码, 通过用户点击链接来判定邮箱, 一般是通过get参数的值/复杂路由是否正确来判断,
    若这个get参数/路由可猜解(如传送的是用户的uuid或者时间戳), 即可绕过邮箱检测
  • 回显验证码内容: 发送验证码的接口会回显验证码内容

手机/邮箱短信轰炸

  • 简介: 由于验证码可连续发送, 所以可以短信轰炸指定 电话/邮箱(每分钟15条以上为漏洞)
  • 绕过:
    高并发绕过: 通过高并发的方式, 使得一次性发送大量的短信绕过
    杂字符绕过: 电话加上空格 @ 逗号 /r /n +86 86 086 0086 字母 0 00等进行绕过
    大小写绕过: 对于邮箱, @后的内容可大小写, example@Qq.cOm
    不同功能绕过: 可能不同功能的验证码CD不统一计算, 可通过改变 用于指定功能的参数的值/更换功能点 来绕过
    删除cookie值绕过: 有些接口是根据Cookie来判断是否短时间内访问的, 通过删除cookie即可绕过
    修改IP绕过: 有些接口是对当前IP进行显示, 通过使用代理池来绕过

登录

  • 暴力破解: 当站点没有限制必须使用复杂密码时, 可通过暴力破解账户的密码
    注: 若有图形/滑块验证码则看是否能绕过, 或者是不是先验证账号密码 再校验验证码
    注: 若有做大错误次数, 则固定密码去爆破用户名
  • 密码通过GET参数传输: 密码通过GET参数传输, 会被记录在日志中 且存在中间人攻击的风险
  • 会话固定攻击
    会话标识在登录后未更新, 而是更新会话标识对应的权限,
    导致可以通过让受害者使用攻击者给予的会话标识来登录, 从而使用相同会话标识来 获取受害者权限
  • 账户枚举: 由于账号存在与否响应不同, 导致可以判断哪些账号存在, 哪些不存在
  • 空密码登录: 由于密码校验存在漏洞, 可以通过空密码/0来进行登录

注册

  • 任意用户注册: 验证可绕过(比如手机/邮箱验证码可绕过), 或没有校验用户的真实信息(如只需要输入手机号/邮箱号而无需验证即可注册成功), 导致可以注册任意用户
  • 覆盖注册: 可以注册已有账户(相同手机/邮箱/昵称), 从而可以覆盖原账户
    注: 有些站点在点击注册按钮时, 可能会前端调用查询接口查询是否存在用户, 若存在则不调用注册接口, 但实际注册接口可以进行覆盖注册
  • 账号枚举: 由于账号存在与否响应不同, 导致可以判断哪些账号存在, 哪些不存在

忘记密码

  • 任意密码重置: 由于验证可绕过(比如手机/邮箱验证码可绕过, 旧密码验证可绕过), 导致可以重置任意账户
  • 账户枚举: 由于账号存在与否响应不同, 导致可以判断哪些账号存在, 哪些不存在

-- 单点登录SSO --

简介

  • 概念: 存在多个相互信任的应用系统中, 只需要认证一次, 就可以访问这些所有的应用系统
  • 认证中心: 通常情况下单点登录存在一个认证中心
    1. 信任该认证中心的应用系统 会让用户 跳转到认证中心 进行认证(并携带类似redirect的get参数)
    2. 认证完成后再跳转到 原来的应用系统(即跳转回redirect指定的url)
  • 实现-同域: 即当多个应用系统(包括认证中心)分别是 同一个主域名下的 不同子域名时
    1. 认证中心认证后 分发的Cookie的domain域属性 设置为主域名, 使得在访问 这些应用系统时 也会带上该Cookie
    2. 同时认证中心的Session 和这些信任的应用系统 进行共享, 从而实单点登录
  • 实现-不同域: 同域也可使用
    1. 认证中心认证后 返回一个token(可能是Cookie, 也可能是其它类型的凭证), 携带该token跳转回原来的应用系统
    2. 认证中心存在认证token有效性的接口, 信任的应用系统接收token后, 携带token向该接口发起请求, 来验证token是否有效, 并获取token对应用户的信息
    3. 验证成功后, 应用系统将登录状态写入session并设置Cookie

-- 多因素认证MFA --

简介

  • 概念: 为了提高登录的安全性, 要求用户进行两种及以上的认证才可完成登录
  • 常见认证类型: 账户密码 手机/邮箱验证码OTP 安全问题答案 指纹/人脸/声纹 动态令牌TOTP(steam 腾讯云)
  • 状态令牌: 通常情况下 多因素认证 会在因素一认证后 发放一个状态令牌, 用于代表因素一认证通过, 只有携带该状态令牌才可进行下一因素认证

多因素认证绕过

  • 密码重置: 许多系统在密码重置后会自动登录, 若此时密码重置的认证比登录的认证还要简单, 则可通过密码重置绕过
    防御: 1.密码重置不自动登录 2.密码重置认证设置的比登录难
  • 状态令牌可混用:
    当账号1的状态令牌在因素二认证时, 可以通过账号2携带该状态令牌来认证 从而成功登录时;
    若登录上的是状态令牌 对应的账号, 则可绕过账号1的 因素二认证;
    若登录上的是因素二认证 使用的账号, 则可绕过账号2的 因素一认证;
    防御: 1.状态令牌不允许其它账号携带进行认证 2.在因素二认证时再进行一次因素一的认证

-- OAuth2 --

- 基础 -

简介

  • 概念: OAuth是一种授权框架, 允许 网站/应用 申请 另一个网站/应用上用户 的有限访问权限
    例子: 微信/QQ扫描第三方登录
  • 认证流程(通用)
    客户端请求授权: 客户端应用(如"百度") 向资源所有者(用户) 申请访问其在第三方平台(如"微信") 的特定资源(如用户头像、邮箱), 申请中需明确客户端身份、访问范围等信息
    用户批准授权: 用户通过授权服务器(第三方平台的认证系统)的界面, 明确同意或拒绝客户端的访问请求, 若同意, 授权服务器会生成"授权证据"(如授权码/证书等) 并返回给客户端
    客户端获取访问令牌: 客户端将用户的"授权证据"提交给授权服务器, 同时验证自身身份(如通过client_secret, 但若为公开客户端, 则无需提供client_secret), 授权服务器验证通过后, 发放访问令牌(Access Token)
    客户端访问资源: 客户端携带访问令牌访问资源服务器(存储用户数据的服务器), 资源服务器验证令牌有效性/权限后, 返回相应数据
  • 认证模式:
    OAuth定义了多种授权类型, 其中 授权码模式 和 隐式授权类型(已过时, 设计初衷是用于纯前端页面) 最常用
  • 机密客户端/公开客户端
    授权码模式中可处理 机密客户端和公开客户端
    公开客户端对比机密客户端的区别在于 其通常不可存储client_secret, 或存储可能会存在很大的泄露风险
    公开客户端常见于 纯前端页面(无法存储client_secret) APP(因为安装包可被反编译, client_secret容易泄露)

授权码模式(机密客户端)

  • 客户端请求授权: 客户端向授权服务器的/authorization端点发送GET请求,
    /authorization?client_id=<客户端在授权服务器注册的唯一标识>&redirect_uri=<授权成功后跳转URL>&scope=<申请访问信息的范围>&state=<客户端生成的随机值(防CSRF)>&response_type=code(代表使用授权码模式)
  • 用户登录与授权: 授权服务器将用户重定向到登录页面, 用户输入第三方平台(如微信)的账号密码登录, 并在授权界面确认是否允许客户端访问请求的资源(如 “百度请求获取你的头像和昵称”)
  • 授权服务器返回授权码: 用户同意授权后, 授权服务器将用户浏览器重定向到redirect_uri指定的回调地址, 并在 URL中携带 授权码(code) 和 state参数, 通过用户携带访问的方式, 将授权码和state传给客户端 (此时客户端应该检测state是否与之前的相同从而防止CSRF)
  • 客户端用授权码换访问令牌: 客户端 向授权服务器的/token端点发送 POST请求, 提交授权码、客户端身份凭证(client_idclient_secret,后者为客户端注册时生成的密钥), 请求换取访问令牌, 换取后授权码会立即失效
    如POST请求/token client_id=xxx&client_secret=xxx&redirect_uri=<跳转的url>&code=<授权码>&grant_type=authorization_code(代表使用授权码换访问令牌)
  • 授权服务器返回访问令牌: 响应返回access_token给客户端, 后端通过将access_token 放在Authorization头中可以向资源服务器申请资源 (整个过程用户无法得知access_token)
    响应格式如{ "access_token": "xxx", "token_type": "Bearer", "expires_in": 3600, "scope": "openid profile" }

授权码模式(公开客户端)

  • 客户端请求授权: 相同, 需多加两个参数code_challenge=<PKCE挑战码,是对code_verifier哈希后的值>&code_challenge_method=S256(哈希算法)
  • 用户登录与授权: 相同
  • 授权服务器返回授权码: 相同
  • 客户端用授权码换访问令牌: 相同, 但无需提供client_secret参数, 需提供code_verifier参数, 授权服务器会校验 该参数值用code_challenge_method中的算法哈希后 与之前提交code_challenge是否相同
  • 授权服务器返回访问令牌: 相同

隐式授权类型

  • 客户端请求授权: 与授权码模式相同, response_type需改为token
  • 用户登录与授权: 与授权码模式相同
  • 授权服务器直接返回访问令牌: 用户同意授权后, 授权服务器直接返回令牌, 存储在用户的前端页面(一般存储在localStorage/sessionStorage)
  • 前端提取令牌并访问资源: 通过前端脚本 从URL片段中提取访问令牌, 随后用户携带令牌(通过将access_token放在Authorization头)向资源服务器请求数据, 用户将数据发送给客户端

- 漏洞 -

授权码劫持

  • 简介: 授权服务器漏洞, 当redirect_uri未校验时, 可通过修改伪造 客户端的网站来钓鱼获取授权码(redirect_uri就指向钓鱼网站), 或者直接发送带有恶意redirect_uri的链接让别人点击并授权 来获取授权码
  • 绕过
    ///www.gh0st.com//.. ///www.gh0st.com//../ /https:/gh0st.com/ //www.gh0st.com//.. //www.gh0st.com
    /www.gh0st.com //gh0st.com https://www.xxx.com/www.gh0st.com http://www.xxx.com.gh0st.com
    http://gh0st.cn:80#@xxx.com http://www.xxx.com@gh0st.com http://www.xxx.com#gh0st.com
    http://www.xxx.com?gh0st.com http://www.xxx.comgh0st.com http://www.xxx.comgh0st.com
  • 修复: 授权服务器 redirect_uri使用白名单进行匹配过滤
  • 注: 这只能获取授权码, 授权码的进一步利用则 需要获取客户端的client_id/client_secret(机密客户端), 知道code_verifier(公开客户端)

CSRF绑定劫持

  • 简介: 客户端漏洞, 对于类似绑定qq/微信的功能点, 当客户端不使用/校验state参数时, 此时攻击者可发送 带有自己的qq/微信授权码的 换取访问令牌的请求链接, 点击后受害者账号就会绑定攻击者QQ与微信
  • 修复: 客户端 校验state参数是否与用户会话存储的state相同, 再进行绑定
  • 注: 对于OAuth2, state参数是可选的, 但某些授权服务器会强制使用state参数, 否则会拒绝请求

隐式授权

  • 简介:
    客户端漏洞, 隐式授权已过时, 而且其设计初衷是用于 纯前端页面,
    若用于带有后端的页面, 则客户端 要不让用户提交token到客户端(还不如用授权码),
    要不让用户自行向授权服务器申请数据然后将数据提交给客户端(没法校验数据是否正确),
    若token前端存储(localStorage/sessionStorage), 也可 XSS 脚本窃取
  • 修复: 不使用隐式授权的方式, 改为授权码(公开客户端)的形式

其它

  • 授权码重复使用: 授权服务器漏洞, 授权码应一次性有效且短期有效, 否则可能会因授权码泄露而导致用户信息泄露
  • client_secret泄露: 客户端漏洞, 可伪造合法客户端, 用授权码向授权服务器请求access_token/refresh_token
  • access_token泄露: 可访问授权服务器资源
  • refresh_token泄露: 可重新申请access_token
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇