• DDs moving castle
    2019-04-01
    波波老师,像piggymetrics演示项目这样在申请令牌时将Client客户端凭证写在ajax的js中,我感觉也是很不安全的,毕竟客户端凭证也是一种校验,请问生产级别应如何处理?
    1、clientId和sercet保存在哪儿比较安全(生产级别)?
    2、令牌申请后存储在哪儿比较安全(生产级别)?
    3、我看之前的留言中说,授权码模式下令牌是在服务器端的??指的是access token和refresh token都在服务器端吗?那下次ajax如何携带access token?

    对OAuth2的授权流程已经基本了解,但还是有些想不清楚,比如前后端分离的场景下,Client客户端凭证应保存在哪儿,zuul网关作为申请令牌的Client保存?前端的Nginx服务器?还是单独的一个web服务器?感觉放在前端js中,浏览器F12就能获取到是不安全的。
    还有申请令牌后应存放在哪儿,access token是肯定要给浏览器的,用于下次访问时携带,有效期较短,可如果refresh token也给浏览器放在LocalStorage,一旦被截获,就更不安全了。
    关于上面这类问题,在不同的场景下生产级别怎么处理比较安全能不能专题分享一下。我感觉这也是一个扩展点。
    展开

    作者回复: 你好,谢谢你的反馈问题,按照最初的OAuth2规范,SPA单页应用建议是使用简化(Implicit)模式的,这种模式下,应用只传clientId,不传secret,而且获取的令牌也是放在浏览器端(一般是localstorage)的。因为这种模式安全性比较弱,所以一般只限于安全不严格的有限场景。

    OAuth2 6749规范制定时间比较早,现在单页SPA开始流行起来,所以这个规范也一直在修订,有些补充规范提出SPA可使用一种授权码+PKCE模式,但我看过应用端实现比较复杂,且对AuthServer有要求,可参考一篇较新文档(https://auth0.com/blog/oauth2-implicit-grant-and-spa/)。

    对于正式的授权码模式,令牌会存在Web服务器上,它和后台API交互是会使用令牌,用户浏览器中没有令牌(因为它不直接和后台API交互),浏览器和Web服务器之间可以有Session,而且这个Session可以和某个令牌关联。

    如果你要使用单页SPA,又想比较好的安全性,推荐一种oauth-proxy做法,相对比较简单,这个oauth-proxy作为代理,可以让单页SPA实现授权代模式,而且简单可靠,具体做法参考这里的github站点代码(https://github.com/madumalt/oauth-proxy),这做法其实通过扩展网关也可以实现,它可以做到令牌存proxy端(有状态),也可以用加密cookie方式(无状态),而且不会在SPA应用中暴露clientId/secret。

     1
     1
  • DDs moving castle
    2019-04-08
    首先谢谢波波老师的回复,推荐的文章及项目对我很有帮助。其实我和同事也讨论在zuul网关上实现OAuth的Client的功能,虽然我心里还是角色SPA是真正的Client,但可以把zuul网关理解为Client的外延,和你提供的oauth-proxy做法很类似。
    oauth-proxy项目我大概看了,它是在浏览器与oauth-proxy之间维持cookie-session,使用oauth-proxy作为OAuth Client获取令牌,获取令牌后,可以不下发给浏览器,cookie与令牌映射关系(有状态),或者加密后放到cookie里下发给浏览器(无状态)。但我有点不明白无状态下,为啥还要加密令牌??我理解这两种下发的形式都是利用了浏览器对cookie的一些安全机制,因为整个oauth-proxy是解决了client凭证存放在哪儿的问题,已经获取token也存放在oauth-proxy,但对于浏览器与oauth-proxy之间,cookie中的内容加密可以放篡改,而不能放窃取,就能JWT的签名一样,而放窃取我感觉是更难也更重要的。
    你推荐的文章我也大概看了(全英文还是挺费力啊),给我感觉OAuth2协议只定义了它4个角色之间怎么安全的获取令牌,校验令牌,但对于现在常用的user-agent(浏览器),OAuth2涉及的不多,或者说它说了也不算,比如google就不想支持token绑定。而文章中给出的一些其它方案:(1)same-site cookie,我感觉对于我们公司这种域名不在Public Suffix List里的应该用不了吧??(2)PKCE,实现起来复杂,而且好像只在获取token环境增加了code exchange,而校验token还是无法校验是不是黑客在使用。(3)我也简单看了pop令牌,也是用于OAuth Client与授权服务器之间证明是真正Client请求而不是黑客的,和Browser感觉没什么关系。
    其实我们公司就是想做前后端分离的应用,可能内部用,也可能公网用,但越看越觉得2012年发布OAuth2设计的Client是一个web server,如果场景是开发平台供第三方授权访问API很合适,但是对于基于浏览器的应用,OAuth2一开始设计的比较简单,对于Browser与OAuth Client之间比较少,后来做扩展的时候也需要各浏览器厂商的支持,目前也没完全成型,所以从浏览器到OAuth Client的安全,还是基于原来的浏览器对cookie-session的安全机制,用token存localstorage可能还没有cookie安全。这就让我产生了一个疑惑,基于浏览器的有必要用OAuth2吗??传统的user/passwd+https+SSO的模式不也一样吗,都要依靠cookie的存储和https的传输时安全。从浏览器到zuul网关后,基本就是偏内网环境了,zuul作为Client和授权服务器之间都是内网,走什么授权模式或者传统模式都差不多了。
    不知道我的理解对不对,请波波老师指点。
    展开

    作者回复: 你好,oauth-proxy主要解决两个问题,一个是将clientid/secret存服务端,保证client验证并且不泄露secret,二是token不流到浏览器端,减少token暴露泄露风险,但是为了实现无状态校验(让token不用存储在服务端,否则需要关联sessionId和查询token很麻烦),所以将token存浏览器cookie,但这又会造成token泄露问题,所以必须加密。

    OAuth2主要针对分布式微服务/API场景,特别是开放API,这个时候传统username/password方式就明显不合适了。

    传统Web应用基于cookie-session实现登录认证和SSO很普遍也很成熟,未必需要用OAuth2,当然现在有OpenID Connect(在OAuth2基础上构建的轻量身份认证协议)也可以实现登录认证和SSO。

    如果你深入下去,不管是Web Session/cookie还是OAuth2/token发现这些机制底层相通,无非是身份权限状态存储和引用标识的问题,达成目标的形式稍有不同而已。你可以根据自己的场景灵活选择,未必需要拘泥,当然安全有个最佳实践,尽量遵循标准保证安全性、扩展性和互操作性,这也是Google/Facebook等大厂一般做法。

    另外,SPA也可以用增强的授权码模式,不少授权服务器提供js封装,可以直接应用,例如idenityserver(https://github.com/IdentityModel/oidc-client-js),还有keycloak应该也有js adapter。

    
    
我们在线,来聊聊吧