一 ,OAuth 2.0
OAuth2.0 即 open auth 开放授权协议,第三方客户端应用通过授权服务器获取用户资源完成登录的,无需输入账号密码,如微信扫码登陆
二,工作流程
用户登录第三方客户端,客户端向用户询问登录请求,用户同意后客户端向授权服务器发送请求,授权服务器返回授权码给客户端,客户端再拿着授权码向授权服务器获取访问令牌,拿到令牌后客户端再用令牌访问用户存储的资源来完成登录
在工作流程中使用访问码再用访问码去获取令牌而不是直接返回令牌的原因是令牌在 url 中被返回给客户端时易遭受中间人攻击导致窃取令牌,用户信息泄露,使用访问码的话即使访问码被泄露攻击者也不能直接利用授权码去获取用户的资源,需要通过授权码和用户信息才能拿到 token,而用户信息存储在后端无法直接拿到,同时授权码有效时长短,被窃取也不易被用来进行攻击
流程图:

oauth 流程代码示例:
def authorization_request(self): """步骤1:构造授权请求""" params = { 'response_type': 'code', 'client_id': 'your_client_id', 'redirect_uri': 'https://client.com/callback', 'scope': 'read write', 'state': self.generate_state(), # 防御CSRF # 可选参数:nonce(OpenID Connect使用) } return f"https://auth.server/authorize?{urlencode(params)}"
def exchange_code_for_token(self, auth_code): """步骤2:用授权码交换令牌""" # 注意:此请求必须是后端到后端的HTTPS请求 data = { 'grant_type': 'authorization_code', 'code': auth_code, 'redirect_uri': 'https://client.com/callback', 'client_id': 'your_client_id', 'client_secret': 'your_client_secret' # 在后端处理! } response = requests.post('https://auth.server/token', data=data) return response.json() # 包含access_token, refresh_token等1.OAuth 隐式流绕过
完成登录流程抓到的四个包:

用户点击使用 OAuth 登录,客户端应用向授权服务器发送请求,授权服务器直接返回 token

授权服务器将 token 放在 url 中返回,重定向到/oauth-callback,前端提取出 url 中的 token

携带提取出的 token 访问 资源 服务器的/ me 请求用户的资源

前端向业务系统的/authenticate 接口发送请求,这一步决定了登录谁,但是后端只验证了 token 的合法性,而不没有将 token 和用户进行绑定,通过修改 email 可以登录其他用户
2.state 参数缺陷导致 csrf

用密码登陆后绑定第三方账号,退出登录再用第三方账号登录

抓到两个关键的包

显然这个包是客户端网站向授权服务器发出授权请求,仔细看发现竟然没有 state 参数,开始都没发现,大意了,艹,state 参数是一段随机的令牌,用来确定用户,防护 csrf 攻击

再次用第三方验证登录,抓包发出的授权请求,放行后再抓包发出的包含授权码的请求,复制这段授权码的 url 放到攻击服务器完成 csrf 构造,先发送攻机服务器的请求再丢弃之前登录发出的包含授权码的请求,保证授权码没有被使用,再次用第三方登录就成功登录管理员账号了

3.通过 redirect_uri 进行账户劫持
按照流程走,抓包客户端发送的请求授权的包,更改 redirect_uri 发包后正常相应,说明服务器未对 url 进行校验
4 .利用子域名的跳转重定向进行账户劫持
这次试验对 redirect_uri 进行了白名单限制,但是子域中没有进行校验,利用子域的开放重定向漏洞进行跳转,劫持到攻击者服务器上
