我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第16篇文章,点击查看活动详情
Token
由于酒店A的订餐流程制定了合理高效的处理方式,酒店A的订餐需求日益增长。合理化方式为以下几项。
(1)酒店和公司协商,制定了详细的订餐协议,保证和公司交互信息的正确性。
(2)为解决每一次订餐的信息不流通,为公司制定了通行证,保证数据的状态可传递性。
(3)同样为保证交互数据的有状态性,酒店建立了数据库服务器创建“公司订餐明细表”,用于保存及验证公司的身份。
随着酒店A业务的突飞猛涨,依靠手工及查询数据库的方式已经不再满足日益增长的订餐需求。酒店决定放弃人工辅助,建立订餐用户认证及管理系统,运用自动化的方式实现公司与酒店的订餐行为。虽然运用系统实现功能可以节约人力成本、提高效率,但机器不如人灵活,不能随机应变,需要制定一系列规则,使它根据确定的模式进行运作。为此,订餐用户认证及管理系统的需求及设计人员进行了以下讨论。
(1)每个公司需要保存自己的通行证,但对于酒店系统需要保存所有人的 Session ID。再加上Session的生命周期是在会话内,如果订餐申请过多,这无疑是一笔巨大的开销。
(2)如果为了减轻负载而使用集群,如何保证机器与机器间的 Session 复制。假设集群由两台机器组成,公司A登录机器A,那么公司A的Session ID保存在机器A上。如果下一次公司A的登录申请被转发到机器B上了怎么处理?如果机器A挂了,又怎么处理?
(3)如果运用Memcached把Session ID集中存储到一个地方,所有的机器都来访问这个地方的数据,这样一来,就不用复制SessionID了,但是增加了单点失败的可能性,要是那个负责Session的机器挂了,则还是需要所有人重新登录。
如果把单点的机器也搞出集群增加可靠性,那又是一个巨大的负担。
(4)对于过多的订单申请请求,反复查询数据库会造成性能的问题,直接影响用户体验及功能使用。
(5)当用户的客户端是一个原生平台(iOS,Android,Windows 8等)时,Cookie是不被支持 的,如何解决?
(6)为了更有利于CDN的运用,服务端是否可以只提供API即可?(7)当在做用户的身份认证时,是否可以制定标准化的模式运行?
以上问题都是由服务器端需要保存 Session 信息造成的,如果服务器端不用保存 Session信息就好了。考虑至此,设计人员想出了一种以时间换取空间的方式。给所有用户发送一个令牌(Token),其是签名后的用户身份信息,每一次用户需要发送订餐请求把用户信息和这个令牌给酒店系统进行验证即可。酒店系统不保存令牌,只保留用户签名过程中的加密算法及密钥即可。
Token的原理
Token的原理如图所示。
(1)当客户端第一次请求时,发送用户信息至服务器。服务器对用户信息使用HS256算法及密钥进行签名,再将这个签名和数据一起作为Token,返回给客户端。
(2)服务器端不保存Token,客户端保存Token。
(3)当客户端再次发送请求时,在请求信息中将Token一起发给服务器。
(4)服务器用同样的HSA256 算法和同样的密钥,对数据再计算一次签名,和Token中的签名做比较。
·如果相同,服务器就知道客户端已经登录过了,并且可以直接取到客户端的user ID。
·如果不相同,数据部分肯定被人篡改过,服务器就返回客户端:认证不通过。
运用Token 服务器就不再需要保存Session ID,只负责生成Token,然后验证Token。这就是服务器用CPU计算时间换取Session存储空间的方式。Token的传递通常被放在Cookie中,如果客户端不支持Cookie,Token也可以放置在请求头中。和Cookie一样,为了数据安全性 Token中不应该放如密码等敏感信息。可以通过抓包工具获取 Token值,具体操作就不反复说了。Token通常被用于一种轻巧的规范下,这种规范就叫作JSON Web Token(JWT),也就是下一节要讲的内容。
JSON Web Token
当酒店满足了用户订餐的基本功能后,为了提升用户活跃度,以及增强用户黏性,需要加入一系列的交互功能。
(1)用户之间是否可以免登录互加好友,推荐美食。
(2)直接通过系统购物车的方式下订单,而不是提交订餐申请单。(3)实现Web应用的单点登录。
假设订餐用户有个人主页,上面展示各种好吃的菜肴。我在浏览对方页面时发现和他的口味相同,希望加其为好友,以后一起交流吃货的经验。页面上有个 button(按钮)为添加好友,我复制链接后,发现这条链接与众不同。
链接后面包含了一串jwt=LCJhbiOiJIUzIlNiJ9.eyJmcm9widVzZXIiOmyAYwugdloRp字符串。
这里的jwt就是JSON Web Token的简称。它可以完成我在不登录系统的情况下,点击链接后自动登录加对方为好友的功能。
JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑且安全的标准,用于将各方之间的信息传输为JSON对象。该信息通过数字签名进行验证。使用HMAC算法或使用RSA的公钥/私钥对JWT进行签名,它是rest接口的一种安全策略。
首先,了解一下JWT的组成部分。实际上它就是一串字符串,由三个部分组成:头部、载荷与签名。
头部(Header)
头部用于描述关于JWT的最基本的信息,例如,其类型以及签名所用的算法等。它被表示成 一个JSON对象。
{"typ": "JWT" "alg": ": "HS256" }
在这里,我们说明了这是一个JWT,并且我们所用的签名算法是HS256算法。 对它进行Base64编码后形成的字符串就成了JWT的header(头部)。
载荷(Payload)
将添加好友的操作描述成一个JSON对象。其中添加了一些其他的信息,帮助今后收到这个 JWT的服务器理解这个JWT。
{"iss": "Kathy Yang JWT", "iat": 1455624102, "exp": 1475632522, "aud":"www.example.com", "sub": " jrocket@example.com", "Givename": "Smark","Surname": "Kathy"}
这里面的前五个字段都是由JWT的标准所定义的。 iss:该JWT的签发者
sub:该JWT所面向的用户。 aud:接收该JWT的一方。
exp(expires):什么时候过期,这里是一个UNIX时间戳。 iat(issued at):在什么时候签发的。
将上面的JSON对象进行Base64编码可以得到一串字符串。这个字符串我们将它称作JWT 的Payload(载荷)。
签名(Signature)
将上面的两个编码后的字符串都用符号“”连接在一起(头部在前),就形成了一串新的字 符串。最后,我们将上面拼接完的字符串用HS256算法进行加密。在加密的时候,我们还需要提 供一个密钥(secret)。通过密钥和加密算法加密后的部分就叫作签名。
最后将这一部分签名也拼接在被签名的字符串后面,我们就得到了完整的JWT,也就是 restaurant-app.com/make-friend…
LCJhbiOiJIUzI1NiJ9.eyJmcm9widVzZXIiOmyAYwugd1 oRp\链接中jwt的值了。
下面我们再通过一个实例了解JWT机制实现认证的过程。 当用户第一次登录系统时,如图所示。
创建JWT的步骤如下。
(1)第一次登录,用户从客户端输入用户名/密码,提交后到服务器的登录处理 Action 层 (Login Action)。
(2)Login Action 调用认证服务进行用户名密码认证。
(3)如果认证通过,Login Action 层调用用户信息服务获取用户信息(包括完整的用户信息及对应权限信息)。
(4)返回用户信息后,Login Action从配置文件中获取Token签名生成的密钥信息,进行Token的生成。
(5)在生成Token的过程中可以调用第三方JWT Lib生成签名后的JWT数据。
(6)完成JWT数据签名后,将其设置到Cookie对象中,并重定向到首页,完成登录过程。经历过第一次登录,以后的每一次该客户端的请求都会经历请求认证,如图所示。
请求认证的步骤如下。
(1)客户端(App客户端或浏览器)通过get或post 请求访问资源(页面或调用API)。
(2)认证服务作为一个Middleware HOOK对请求进行拦截。基于Token的认证机制会在每一 次请求中都带上完成签名的Token 信息,这个Token 信息可能在Cookie中,也可能在HTTP的 Authorization 头中。首先认证服务在 Cookie 中查找 Token 信息,如果没有找到,则在HTTP Authorization Head中查找。
(3)如果找到Token信息,则根据配置文件中的签名加密密钥,调用JWT Lib对Token 信息 进行解密和解码。
(4)完成解码并验证签名通过后,对Token中的exp、nbf、aud等信息进行验证。
(5)全部通过后,根据获取的用户的角色权限信息,对请求的资源的权限进行逻辑判断。
(6)如果权限逻辑判断通过,则通过response对象返回,否则返回未授权,登录失败。
JWT是目前项目中使用最多的处理请求无状态性的方式。由于Token是被签名的,所以我们 可以认为一个可以解码认证通过的 Token 是由系统发放的,其中带的信息是合法有效的。使用 Token很大程度上解决了Session的弊端,让数据在网络传输中更精确并且保障了数据在传输过程 中的安全性。本质上,测试人员是以找漏洞或许可以说以“破坏”作为技术手段实行测试过程的。 例如,我们的安全性测试工程师就可以运用XSS Attacks、Replay Attacks 以及 MITM Attacks 跨站 脚本攻击等手段获取Token 模拟正常请求发送场景,服务器是不会发现这是假请求的。
我们掌握了数据传输的基础知识,对请求的本质就有了清晰的认识。下一节开始,我们就讲 解具体的网络协议,大家会发现由于对基础知识理解得非常透彻,协议原本枯燥的内容也变得通俗好记了,并不需要测试人员死记硬背。