Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

再扯 Web 授权

  最近一直在纠结关于 Web 授权的问题。如何才能安全地给客户端做授权呢?或者说如何才能安全地识别客户端呢?这个话题之前就纠结过,然而我还是想不到有什么靠谱的解决方案。那么再退一步想想,我们的障碍好像不是授权,而是安全问题。
  既然确实找不到一个靠谱的授权方案,那就从更本质的问题开始考虑:为何 Sessoin ID 就不能暴露给前端程序?
  这应该是 XSS 的坑吧?如果页面上存在 XSS,暴露出来的 Session ID 就可能被盗取。攻击者盗取 Session ID 后可以存入自己的数据库,即使 XSS 漏洞被修复,攻击者依然可以用这些存储下来的 Session ID 胡作非为。如果这些 Session ID 的时效很长,那后果将非常严重。
  最近公司也曝了个安全相关的问题:用户修改过密码后没有退出登录。这个漏洞的根本原因就是修改密码这个操作没有销毁 Session。如果存在这个漏洞,并且 Session ID 被盗取,那么即使用户修改了密码,账号也依然会被攻击者登陆。当然,这些都是题外话了,我想强调的是 Session 太顽固是很危险的。
  我们只要能解决 Session ID 被攻击者存储下来的问题就可以无视 Session ID 暴露的问题。但这也是个很困难的问题。通常 Session ID 的过期时间都是几天到几个月。这么长的时间显然是不能容忍的!如果 Session ID 的时效是一天以内,那么攻击者盗取这些 Session ID 将不会有什么意义。但用户显然不能容忍每天都输入用户名密码来登录,这个矛盾要如何化解呢?
  第三方授权是我比较喜欢的一种模式,虽然第三方通常也是使用 HTTP Only 的 Cookie 来存储用户状态的,但至少不需要在自己的业务代码中处理授权问题。其实我目前也没想到什么更优雅的解决方案,只是偷偷地把状态管理问题移到了别的地方,让它不再碍眼而已。就目前的 Web 而言(也许以后会出现解决授权问题的新特性也说不定),授权终究逃不出 Cookie。
  具体实现可以是这样:当前端需要调用一个用户相关的 API 并发现自己没有 Access Token(Session ID)时就到第三方去取。至于怎么取大概有这么几种方式,一种是直接发起一个 withCredentials 的 XHR 请求(兼容浏低版本览器可以用 JSONP)到第三方的域名上获取 Access Token。如果用户曾经在第三方登录过就可以立即取到,否则取不到就说明用户尚未登录。另一种是页面直接跳转过去,当跳回来的时候 URL 里面带上行 Access Token。拿到 Access Token 后请求自己服务器的 API,服务器端去第三方服务器提供的接口上查询 Access Token 的有效性以及对应的用户基本信息(比如用户的唯一标识符)。
  这里 Access Token 的时效性可以设置地非常短,因为获取新的 Access Token 只是一次网络请求而已。这样即使页面上存在 XSS 漏洞, Access Token 被盗取也无法长期存储。另外以上所说的「第三方」只是一个单独的域而已,未必是它人提供,完全可以视为一个大项目中的子项目。
  也许我用文字把这个过程描述出来有繁琐(主要是懒得画图),但比起自己实现授权而言这已经是非常简明的方案了。虽然这整个方案只是将抽取作为一个独立服务单独抽取出来,但它解决了业务逻辑中对状态的依赖问题。这样一来业务方面就可以完全地使用 RESTful 或其他无状态的架构了。
网名:
54.144.24.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^