在任何需要服务器和客户端之间进行通信的系统设计中,会话的安全性总是需要重点考虑的因素之一。不当的安全性设计往往会导致用户帐户容易受到未经授权的访问攻击。业界著名的OWASP(开放Web应用程序安全项目,请参见--
https://dzone.com/articles/continuous-security-using-owasp)将“认证与授权的不当实施”视为应用安全的第二大风险(请参见--
https://www.owasp.org/index.php/Top_10-2017_Top_10)。
下面是近年来发生在网络安全领域的典型案例:
- 今年早些时候,Docker的hub数据库遭到了黑客攻击,并导致了Github访问令牌被盗。消息来源请参见-- https://www.theinquirer.net/inquirer/news/3074793/docker-hub-breach
- Gitlab的一个漏洞曾到导致其所有用户的认证令牌在URL中被公开。它们不但没有到期的时间,并且由于长度过短,极容易受到蛮力攻击。消息来源请参见-- https://threatpost.com/session-hijacking-bug-exposed-gitlab-users-private-tokens/127747/
- 由于某个软件的错误,影响并导致了9000万个Facebook帐户的访问令牌被窃。消息来源请参见--https://newsroom.fb.com/news/2018/09/security-update/
在业界,许多CSO(首席安全官)都承认:在认证和授权方面的投入,向来都是企业安全预算中的烧钱大户。而且,他们普遍认为正确地实施用户会话管理可谓既耗时且昂贵。否则,自己乃至所在企业很可能会成为“下一个Jack和他的泰坦尼克号”。
值得注意的是:我们切勿将会话管理与OAuth(请参见-- https://dzone.com/articles/oauth2-tips-token-validation)相混淆。后者是一种仅用于委托目的的协议。而前者涉及到如何在有效会话期间处理、存储和更改认证令牌。该处的令牌既可以是OAuth流,也可以是服务器与客户端之间的会话流。
JWT和Opaque令牌
下面,我们将简要地探讨会话管理中两种常用的主要令牌类型:
JSON Web令牌(JWT,请参见-- https://jwt.io/)
- 每个JWT都包含可用于解释该令牌的任何持有方的特定信息。例如,颁发给了谁,及其用户ID。
- 由于后端不需要为每个API的调用进行数据库查询,因此JWT的使用具有一定的可扩展性。
- 如果不使用黑名单(请参见-- https://auth0.com/blog/blacklist-json-web-token-api-keys/)之类的方法,我们很难在不影响可扩展性的情况下,按需、或在令牌过期之前吊销单个令牌。当然,我们可以通过更改签名的密钥,来吊销所有的令牌。
Opaque令牌
- 作为随机字符串,它们可被视为仅由颁发系统保存的信息指针。
- 在每次使用它们时,都需要对数据库或高速缓存进行查找。
- 此类令牌可以很容易地被按需吊销。
尽管这两种令牌类型的属性不同,但是一旦被盗用,都可能导致未经授权的帐户访问。
常见的会话攻击
通常情况下,由于验证令牌既可以被存储在前端,又可以被存放在后端,而且往往需要通过会话流经由网络传送,因此,它们很容易遭受到如下类型的攻击:
- 中间人袭击
- OAuth令牌盗用
- XSS(请参见--https://dzone.com/articles/the-cross-site-scripting-xss-vulnerability-definit)
- CSRF(请参见--https://dzone.com/articles/fixing-csrf-vulnerability)
- 数据库/文件系统访问
- 会话固定(请参见--https://dzone.com/articles/session-fixation-and-how-fix)
- 蛮力攻击
面对上述攻击,我们需要通过认真地考虑会话的安全性,部署适当的措施,来降低由于系统自身漏洞,所积累的各种攻击可能性。也就是说,系统架构师不仅要防止令牌被盗,还应当确保系统能够尽快地检测到令牌被盗的情况。
检测与防止认证令牌被盗
由于令牌往往需要被应用程序的前端传输到不受信任的另一方,而且很容易被盗用,因此我们需要通过检查来构建第一道防线。现有的检测方法主要依赖于启发式算法(heuristic algorithms)。例如:跟踪IP地址与浏览器(或移动端)指纹的突变,标记异常的用户行为等。不过此类方法既难以实施,又准确性不高。下面让我们来讨论一些常见的会话管理方法。
实施会话管理的常用方法
最常用的会话管理设置方法包括如下五大类:
- 长期访问令牌。
- 将短—中期有效的令牌,用于获取新的访问令牌。
- 短—中期访问令牌,其使用期限会延长。
- 短期访问令牌。
- 短期访问令牌和长期刷新令牌。
1. 长期访问令牌
在用户主动注销会话的时候,访问令牌将被吊销,并在前端被清除。
- 攻击分析::关键的认证令牌会永久性地暴露在前端、传输通道和后端,三个攻击面上。
- 认证令牌被盗的影响:在令牌的到期之前,攻击者可能会未经授权地访问到受害者的帐户,并长达数周或数月之久。
- 盗用检测:只能通过使用主动的启发式算法、或被动地依靠用户通知再实施检测。如果该方法是使用JWT实现的,则很难吊销令牌;如果使用的Opaque令牌,则比较容易吊销。
2. 将短—中期有效的令牌,用于获取新的访问令牌
- 即使先前的令牌尚未过期,前端也可以使用新的访问令牌。
- 在用户主动注销会话的时候,访问令牌将在后端被吊销,并从前端被清除。
- 如果访问令牌仅短期有效,那么用户就需要尽快注销会话。
(1) 攻击分析
关键的认证令牌会永久性地暴露在前端、传输通道和后端,三个攻击面上。
(2) 认证令牌被盗的影响:
攻击者必须不断地更新其令牌,以维持其未经授权的访问状态。
(3) 盗用检测:
要保持登录状态,攻击者和受害者都需要在当前(被盗)令牌过期之前,向服务器请求新的访问令牌。如果同一令牌两次被用于该请求,那么系统会根据前端的实现方式,推断出发生了盗用行为。可见,短—中期有效的令牌虽然可以更快地被检测出是否存在盗用,但是同样由于寿命短暂,就算没有被盗用,用户的体验也并不佳。当然,一旦盗用行为被检测到,与该会话关联的访问令牌将会被立即吊销。不过,如果访问令牌是JWT,那么阻止此类攻击可能会比较复杂。
3. 短—中期访问令牌,其使用期限会延长
在用户主动注销会话的时候,访问令牌将被吊销,并在前端被清除。
- 攻击分析:关键的认证令牌会永久性地暴露在前端、传输通道和后端,三个攻击面上。
- 认证令牌被盗的影响:只要受害者的会话处于有效状态,攻击者就可以维持未经授权的访问。
- 盗用检测:只能通过使用主动的启发式算法、或被动地依靠用户通知再实施检测。一旦盗用行为被检测到,与该会话关联的访问令牌将会被立即吊销。不过,如果访问令牌是JWT,那么阻止此类攻击可能会比较复杂。
4. 短期访问令牌
在用户主动注销会话的时候,访问令牌将被吊销,并在前端被清除。
- 攻击分析:在这种情况下,虽然没有关键的认证令牌,但是由于在传输过程中会公开用户的凭据,因此同样容易受到中间人的攻击。
- 认证令牌被盗的影响:如果令牌被盗,攻击者将只能在短时间内实施未经授权的访问。
- 盗用检测:只能通过使用主动的启发式算法、或被动地依靠用户通知再实施检测。在检测到攻击时,由于访问令牌寿命非常短,因此我们无需吊销它们。不过,如果确实需要,我们可以通过从数据库中删除Opaque访问令牌的方式,来吊销它们。
5. 短期访问令牌和长期刷新令牌
u 在用户主动注销会话的时候,访问令牌和刷新令牌将被吊销,并在前端被清除。
- 攻击分析:关键的认证令牌(和刷新令牌)会永久性地暴露在前端和后端两个攻击面上,当然也偶尔会在传输过程中被暴露。
- 认证令牌被盗的影响:访问令牌被盗:直到该令牌到期之前,攻击者会在短时间内拥有未经授权的访问权限。
- 刷新令牌被盗:攻击者可以通过盗取刷新令牌,来获取新的访问令牌,并在较长一段时间内,以未经授权的方式访问受害者的帐户。
- 盗用检测:访问令牌被盗:只能通过使用主动的启发式算法、或被动地依靠用户通知再实施检测。
刷新令牌被盗:只有在极少的情况下,我们能够检测到此类盗用行为,并将损失降至最低。例如:通过某种实现方式,让先前的访问令牌在生成新的令牌之后,立即被吊销。据此,系统可以在攻击者和受害者同时在线的情况下,识别出盗用的行为。也就是说,如果攻击者使用了刷新令牌,那么受害者的访问令牌将会被吊销,也就导致了受害者需要去请求新的访问令牌。而这将迫使攻击者发出另一个请求,依此类推。因此,如果后端能够检测到在较短间隔内,系统产生了大量对于新访问令牌的请求,则可以推断出盗用的状况。
在检测到攻击时,由于访问令牌的寿命非常短,因此我们无需吊销它们。不过,如果确实需要,我们可以通过从数据库中删除Opaque访问令牌,来吊销它们。
下面,我们针对不同的会话攻击类型,讨论各种相应的应对方法。
应对攻击的优秀实践
1. 中间人袭击
当会话仅使用HTTP,或错误地实现了HTTPS时,如果应用程序并未启用HTTPS、以及安全的cookie,那么攻击者就可以通过与受害者同处一个网络,来监视网络中的各种数据包,并在传输过程中以纯文本格式,去查看到认证令牌。此外,即使某些应用程序带有SSL证书,而错误的实现方式也可能导致中间人攻击得逞。
正如前面提到的,预防此类攻击的最简单方法是:在整个应用程序中正确地使用HTTPS和安全的cookie。此外,我们还可以通过在每台设备上使用公有、私有密钥来增强额外的预防力度。也就是说,在用户登录之前,前端和后端将在初始化时交换此类公钥。另外,为了后续通信的安全起见,我们也可以使用公钥对令牌数据进行加密。
2. OAuth令牌盗用
如果某个应用程序是通过OAuth的方式,向其他应用程序提供访问和刷新令牌。那么当其他应用程序的所在服务器受到威胁时,该应用本身的认证令牌也具有被盗的风险。前文提到的Docker Hub典型案例,就是属于此类型。
那么预防此类攻击的解决方法是:采取适当的措施,及时检测处被盗的刷新令牌,并仅使用短期有效的访问令牌类型。
3. XSS攻击
在XSS中,攻击者可以恶意地将Javascript注入到受害者的浏览器里,并运行在各种应用程序中。此类注入代码会读取认证令牌,并将其回传给攻击者。如果您想了解更多有关XSS攻击的信息,请参见--https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)。
通过使用HttpOnly或各种Secure cookie来存储认证令牌,我们可以很容易地防御此类攻击的发生。不过,值得注意的是:请勿使用localStorage来存储认证令牌,因为它们会被Javascript所访问到。
4. CSRF
此类攻击的目的并非窃取认证令牌,而是让攻击者可以跟踪(piggyback)现有的活动会话。
为了防止CSRF攻击,我们通常需要使用anti-CSRF令牌或SameSite cookie。当然,您也可以使用其他的方法,来与整个认证过程无缝地结合到一起,以解决此类问题。
5. 数据库/文件系统访问
如果攻击者获得了有效的认证令牌、或JWT/SSL私钥(此类密钥的盗用往往比密码被盗更为糟糕),就能够设法通过数据库的注入攻击,来访问到服务器,乃至数据库和文件系统理的信息。据此,他们将能够轻松地劫持会话,进而产生严重的安全后果。值得注意的是,攻击者很可能是贵组织内部的雇员,所以我们在对数据库/服务器实施访问控制时,需要注意如下两个方面:
- 仅在数据库中存储刷新和访问令牌的哈希值,以防止攻击者劫持到任何实时的会话。
- 由于JWT需要将私钥存储在服务器上,因此一旦攻击者获得了私钥,他们将能够劫持当前、以及将来的会话。为了限制攻击面,我们需要修改用于签发JWT的私钥,以便让所有当前的JWT都立即失效。而由于刷新令牌将被用于生成一个带有新的私钥签名的JWT,因此该更改私钥的方法并不会影响到用户的体验。
6. 会话固定
此类攻击“主打”Web应用程序里的匿名会话,而应对的最佳方法是:让用户每次登录时,都生成一组新的认证令牌,并使旧的令牌(如果有的话)及时失效。注意,这是基于设备而不是基于用户实现的。
7. 蛮力攻击
那些具有足够资源的攻击者,经常会不断地去“猜测”认证令牌,直到其中的一种尝试成功通过为止。据此,他们将获得被盗令牌所授予的所有访问权限。而抵御此类攻击的最佳方法是:使用带有高熵(high entropy)且位数较长的认证令牌。
总结
通过上述分析,我们了解到了会话管理的基本概念、常见的会话安全缺陷、各种攻击类型、以及应对措施的最佳实践。希望本文能够给您在系统架构设计的实践和安全管理中提供帮助。
原All You Need to Know About User Session Security ,作者:Supertokens .io
【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】