像处置密码一样去处置令牌
由于任何掌握了令牌和API密钥的人都能访问到对应的资源。因此,我们需要像处置各种密码那样,去认真地处理和保存各种令牌。
OAuth并非是身份验证协议
OAuth处理的是对资源访问权限的委派,因此它并非是一种身份验证协议(尽管名称很像)。我们可以将令牌看作酒店房间的钥匙。您需要让自己的身份得以验证,方可获得酒店钥匙。但是,一旦您手中已有了钥匙,它就不能再去验证您是谁了。最近发生的一些用户信息泄露事件证明了,API提供者不可单一地将是否持有令牌作为身份验证的依据。
另外,我建议您也参考一下OpenID Connect(OIDC,详见https://www.oauth.com/oauth2-servers/openid-connect/)。不过,它只是一种补充性的规范,而并非是想在OAuth之上实现身份验证的功能。OIDC允许用户与应用程序共享其配置文件里的某些信息,但并不是他们的信任凭据。
注意您在JWT中存储的内容和谁有权限访问
JWT能够以各种声明的形式存储大量的信息,如果这些信息被捕获,攻击者就能够轻松地解析出具体的内容(除非它们被加密了)。因此,如果您想使用JWT向后端服务传递有用的信息,那么您可以采用如下的实现方法:
· 在客户端和后端之间,仅使用Opaque字符串、或是基本的JWT。
· 在后端,验证某个请求、并注入一个新的JWT,它的有效负载中可包含一个能够被下游用到的声明。许多API安全网关都能以“开箱即用”的方式提供该功能。
如果想在整个流程中使用相同的令牌,并且让该令牌携带一些敏感的信息,那么请您务必加密该令牌的有效负载。也就是说,请永远不要使用JWT来携带用户的信任凭据,例如:密码!
彻底验证JWT
当您在服务器端收到JWT时,请务必彻底验证其内容。需要特别注意的是:您应该直接拒绝任何不符合预期的签名算法、使用了弱签名算法、和使用了弱非对称/对称密钥进行签名的JWT。此外,您必须验证所有的声明、到期日期、发布者和受用者。
在市面上,有些库和工具可以直接为您执行该操作、有些则需要您事先进行适当的配置、而另一些可能只能做到部分检查。因此,具体该使用哪一种方式,还取决于您所使用到的库。
不要将令牌存储在本地,请使用安全的Cookie
任何在浏览器上的本地存储、和会话存储,都有可能被JavaScript所读取到。可见,用此方式来存储令牌之类的敏感信息是极不安全的。因此,您可以使用安全的cookie、带httpOnly的标识、以及CSRF等措施,来防止令牌被盗。
始终通过HTTPS和请求正文(Request Body)的方式传输令牌
通过这种方法,您可以限制令牌在传输过程中被捕获,或是被写到代理日志、以及服务器日志之中的风险。您还应该确保只使用TLS的1.2/1.3版本,以及在颁发和验证令牌的各个环境中,使用最安全的密码套件。
使用专用的浏览器视图来请求信息
许多应用程序都用到了嵌入式的用户代理,但是,由于它屏蔽了用户去验证与之通信的网站真伪,因此,我们实际上应当避免使用这样的代理。此外,应用程序应当能够完全掌握用户所输入的凭据。正如那些OAuth原生应用所采用的最佳做法那样,一些API提供者会采取强安全措施,来应对此类问题。
结论
访问令牌是如今各种应用程序的实现基础,因此我们在处置的时候一定要倍加小心。如果您是一名后端开发者,您必须确保提供适当的授权类型,以获取访问令牌;同时还应该支持移动应用的PKCE;以及对JWT进行全面验证。而如果您是一位前端开发者,则必须能够管控JWT的存储、并保护应用的各种信任凭据。
参考
· PKCE(https://tools.ietf.org/html/rfc7636)
· JWT的验证实践(https://tools.ietf.org/html/draft-ietf-oauth-jwt-bcp-03)
· 原生应用程序的最佳实践OAuth(https://tls.mbed.org/)
【原标题】Security Best Practices for Managing API Access Tokens (作者: Isabelle Mauny)
原文链接:https://dzone.com/articles/security-best-practices-for-managing-api-access-to