【THM】Session Management(会话管理)-学习
本文相关的TryHackMe实验房间链接:https://tryhackme.com/r/room/sessionmanagement
本文相关内容:了解会话(session)管理以及针对“不安全的会话管理实现”可以执行的不同攻击。
介绍
在本文内容中,你将学习会话(session)管理。思考一下你与Web应用程序的交互情况,你应该意识到,你无需在每次请求时都向Web应用程序提供用户名和密码。相反,在身份验证之后,你会获得一个会话(session)。这个会话(session)将被Web应用程序用来保存你的状态、跟踪你的操作,并决定是否允许你执行你想要执行的操作,会话管理的目标就是确保这些步骤能够正确执行,否则,威胁行为者可能会危及你的会话(session)并成功地劫持它。
前置学习条件
学习目标
- 了解会话(session)管理是什么;
- 了解身份验证和授权之间的差异以及它们在会话管理中各自发挥的作用;
- 了解两种主要的会话管理方法;
- 了解会话(session)管理生命周期;
- 了解如何实际利用不安全的会话管理实现。
什么是会话(Session)管理?
在讨论所有可能出错的地方之前,我们需要先了解会话管理。正如上一个小节中所提及的,你无需在每次请求时都发送用户名和密码。但是,HTTP协议本质上是无状态的,因此,就需要用到会话(Session),它被用于在用户使用Web应用程序的整个过程中跟踪用户。会话管理就是管理这些会话(Session)并且确保其安全的过程。
会话管理生命周期
了解会话管理的最佳方法是使用会话管理生命周期(session management lifecycle),如下所示。
tips:会话创建——会话跟踪——会话过期——会话终止。
Session Creation(会话创建)
你可能会认为会话管理生命周期的第一步仅在你提供凭据(如用户名和密码)后才会发生。然而,在许多Web应用程序中,初始会话在你访问应用程序时就已经被创建,这是因为某些应用程序甚至希望在身份验证之前就跟踪你的操作。但是,本文内容的重点将放在经过身份验证后所产生的的会话上。在你提供了用户名和密码后,你将收到一个会话值,该值在以后的一段时间内会随着每个新请求一起发送。这些会话值的生成、使用和存储对于确保会话创建的安全至关重要。
Session Tracking(会话跟踪)
当你收到你的会话值后,它会随着每个新请求一起被提交;即使HTTP协议本质上是无状态的,这也能让Web应用程序跟踪你的操作。每次发出请求时,Web应用程序都可以从请求中恢复会话值,并执行服务器端查找,以了解会话的所有者及其所拥有的权限。如果在会话跟踪过程中出现问题,那么就可能会允许威胁行为者劫持会话或者冒充会话。
Session Expiry(会话过期)
由于HTTP协议是无状态的,因此Web应用程序的用户可能会突然停止使用。例如,你可能会关闭某个选项卡或者整个浏览器。由于HTTP协议是无状态的,Web应用程序将无法获知此操作的发生。这时,会话过期机制就派上用场了。你的会话值本身应该附加一个有效期。如果会话值的有效期过期,而你又向Web应用程序提交了一个旧的会话值,则该会话应该被拒绝,因为会话应该已经过期。在此情况下,你应该被重定向到登录页面以重新进行身份验证,并重新开始会话管理生命周期。
Session Termination(会话终止)
然而,在某些情况下,用户可能会强制执行注销操作。如果发生这种情况,Web应用程序应该终止用户的会话。虽然这与会话过期类似,但它的独特之处在于,即使会话的有效期仍然有效,会话本身也应该被终止。如果在这个终止过程中出现问题,那么就可能会允许威胁行为者获得对账户的持久访问权限。
在本文中,我们将探讨每个会话阶段中可能会出现的问题。我们希望确保会话安全涵盖整个会话管理生命周期,不过在此之前,我们首先需要了解更多的一些理论知识。
答题
会话管理生命周期中的哪个阶段会处理用户按下注销(logout)按钮这件事情?
Session Termination(会话终止)
会话管理生命周期中的哪个阶段会处理用户提供他们的凭据这件事情?
Session Creation(会话创建)
会话管理生命周期中的哪个阶段会处理用户在身份验证后所执行的操作?
Session Tracking(会话跟踪)
会话管理生命周期中的哪个阶段会处理忘记注销应用程序的用户?
Session Expiry(会话过期)
身份验证vs授权
要了解会话管理中的常见漏洞,我们首先需要审视身份验证和授权机制。虽然它们听起来相同而且经常容易被混淆,但是它们在会话管理中都扮演着关键、独特的角色。为了更好地解释它们之间的差异,让我们来看一下 IAAA 模型:
tips:IAAA - Identification(识别)、Authentication(身份验证)、Authorisation(授权)、Accountability(问责制)。
Identification(识别)
身份识别是验证用户身份的过程。这将从用户声称自己是某个特定身份开始,在大多数Web应用程序中,这是通过提交用户名来进行的。你可以声称自己是与某个特定用户名关联的个人,一些应用程序会使用唯一创建的用户名,而其他应用程序则会使用你的电子邮件地址作为用户名。
Authentication(身份验证)
身份验证是确保用户身份与其所声称的特定身份相符合的过程。在身份识别中,你需要提供一个用户名,而在身份验证中,你需要提供一个证明,以确保你就是你所声称的那个特定身份。例如,你可以提供与你所声称的用户名相关联的密码。Web应用程序可以确认用户所提供的这些信息是否有效(即进行身份验证);然后就会开始会话创建的过程。
Authorisation(授权)
授权是确保特定用户拥有执行他所请求的操作所需的权限的过程。例如,虽然所有用户都可以查看数据,但只有少数用户可以修改数据。在会话管理生命周期中,会话跟踪在授权中扮演着关键角色。
Accountability(问责制)
问责制是创建“用户所执行的操作”记录的过程。我们应该跟踪用户的会话,并且记录使用特定会话执行的所有操作。这些信息在发生安全事件时起着至关重要的作用,它们可以将已经发生的事情拼凑起来。
IAAA和会话管理
既然你已经了解了身份验证和授权之间的区别,那么让我们继续回到会话管理。
- 身份验证在会话的创建过程中起着重要的作用;
- 授权对于验证与特定会话关联的用户是否有权执行他们所请求的操作很重要;
- 问责制对于我们拼凑出在一个安全事件中实际发生的事情至关重要,这意味着记录请求以及记录与每个请求相关联的会话也很重要。
答题
IAAA 模型中负责跟踪和记录你的操作的流程名称是什么?
Accountability- 问责制
IAAA 模型中负责授予你一个会话值的流程名称是什么?
Authentication-身份验证
在 IAAA 模型中,负责验证你是否具有执行某项操作的相关权限的流程名称是什么?
Authorisation-授权
Cookies vs Tokens
在深入探讨会话管理的安全性之前,我们还需要讨论的最后一个主题是我们所使用的会话类型。两种主要的会话管理方法是:基于Cookies、基于Tokens(令牌)。每种会话管理方法都各有优缺点。
基于Cookie的会话管理
基于 Cookie 的会话管理通常被称为传统的会话管理方式。一旦Web应用程序想要开始跟踪用户,那么在响应消息中,就会发送Set-Cookie
标头值。你的浏览器将解析此标头以存储新的 Cookie 值。让我们查看类似于下面这样的 Set-Cookie 标头:
Set-Cookie: session=12345;
你的浏览器将为名称为session
的 cookie 创建一个cookie条目,其值为 12345
,该条目在接收该cookie的域名下有效。你可以向此标头添加多个属性。如果你想了解更多相关信息,请参阅此处,其中一些值得注意的属性包括:
-
Secure- 指示浏览器只能通过已验证的 HTTPS 通道传输 cookie ,如果出现证书错误或使用了 HTTP,则不会传输 cookie 值。
-
HTTPOnly - 向浏览器指示 cookie 值可能无法被客户端 JavaScript 读取。
-
Expire(过期)-向浏览器指示 cookie 值何时不再有效并应该被删除。
-
SameSite -向浏览器指示是否可以在跨站点的请求中传输Cookie,以帮助抵御 CSRF(跨站点请求伪造) 攻击。
对于基于 Cookie 的身份验证,需要记住的一个关键点是,浏览器本身会决定何时随请求发送某个 Cookie 值。在检查了域和 Cookie 的属性后,浏览器会做出决定,并且 Cookie 会自动附加,而无需任何额外的客户端 JavaScript 代码。
基于Token(令牌)的会话管理
基于令牌的会话管理是一个相对较新的概念。它没有使用浏览器的自动cookie管理功能,而是依赖于客户端代码进行处理。在经过身份验证之后,Web应用程序会在请求正文中提供一个令牌,使用客户端JavaScript代码,这个令牌随后将被存储在浏览器的LocalStorage中。
当发出一个新的请求时,JavaScript代码必须从存储(storage)中加载令牌,并将其作为标头附加。最常见的令牌类型之一是JSON Web Tokens(即JWT),它是通过标头Authorization: Bearer
被传递的。然而,由于我们没有使用浏览器内置的cookie管理功能,这会让事情的走向变得有点狂野:虽然有一定标准,但实际上并没有强制要求任何事物必须遵守这些标准。
优点和缺点
每种方法的优点和缺点都是直接相关的,所以让我们来看看:
基于Cookie的会话管理 | 基于令牌的会话管理 |
---|---|
Cookie是由浏览器在每次请求时自动发送的 | 令牌必须使用客户端 JavaScript 在每个请求中作为标头被提交 |
Cookie属性可以用来增强浏览器对于 Cookie 的保护 | 令牌没有强制执行的自动安全保护措施,因此应保护其免遭泄露 |
Cookies很容易受到传统的客户端攻击影响,例如CSRF攻击,即浏览器被欺骗以代表用户发出请求 | 由于令牌不会自动添加到任何请求中,并且无法被其他域从LocalStorage中读取,因此它可以阻止CSRF等传统的客户端攻击 |
由于cookies被锁定在特定的域中,因此可能很难在分布式Web应用程序中安全地使用它们 | 令牌在分布式Web应用程序中运行良好,因为它们是通过JavaScript进行管理的,并且通常可以包含验证令牌本身所需的所有信息 |
tips:分布式Web应用程序-去中心化Web应用。
答题
什么 cookie 属性可以用来确保 cookie 仅通过安全的 HTTPS 通道被传输?
Secure
在响应中使用什么HTTP标头来通知浏览器正在发送Cookie?
Set-Cookie
在请求中经常会使用什么HTTP标头来指示JWT的传输?
Authorization: Bearer
保护会话(session)生命周期
现在是时候学习会话管理的安全性了。回顾上文提及的会话管理生命周期,让我们来分析一下在每个阶段中可能会出现的安全问题。
会话创建阶段
会话创建是大多数漏洞可能潜伏的地方。让我们深入研究一下在该阶段中可能会出现的一些常见漏洞。
弱会话值(Weak Session Values)
随着框架的不断使用,如今很少会看到弱会话值出现。然而,随着LLMs和其他AI代码辅助解决方案的兴起,你可能会惊讶地发现,这些老派漏洞卷土重来的频率之高令人咋舌。
如果Web应用程序中实现了自定义会话创建机制,那么会话值很可能是可猜测的。这方面一个很好的示例是使用了这样的机制:简单地对用户名进行base64编码来作为会话值。如果威胁行为者可以对会话创建过程进行逆向工程,那么他们就可以生成或猜测会话值,从而劫持合法用户的账户。
可控会话值(Controllable Session Values)
在某些令牌中,例如JWTs,其中提供了创建令牌和验证JWT有效性的所有相关信息。如果安全措施没有强制执行,例如验证令牌的签名或者确保签名本身是被安全创建的,那么威胁行为者将能够尝试生成他们自己的令牌。
会话固定(Session Fixation)
还记得那些在身份验证之前就已经可以为你提供会话的Web应用程序吗?这些Web应用程序可能容易受到所谓的“会话固定(session fixation)”攻击影响。如果你的会话值在你进行身份验证之后未能得到充分轮换,那么在适当位置的威胁行为者就可以在你尚未完成身份验证时就记录该会话值,并等待你进行身份验证以让他获得对于此会话的访问权限。
不安全的会话传输(Insecure Session Transmission)
在现代环境中,身份验证服务器和应用程序服务器通常是不同的。想想像单点登录(SSO)解决方案之类的东西。一个应用程序可用于对多个其他Web应用程序进行身份验证。为了使此过程正常工作,你的会话材料必须通过浏览器从身份验证服务器传输到应用程序服务器。然而,在此传输过程中,某些安全问题可能会悄悄出现,将你的会话信息暴露给威胁行为者。最常见的问题就是不安全的重定向,威胁行为者可以控制你在身份验证后将重定向到的那些URL,这允许威胁行为者劫持你的会话。这不仅仅适用于自定义实现的解决方案,Oracle的SSO解决方案就出现过一个允许这种情况发生的大规模bug。
tips:SSO(Single Sign-On),单点登录。
会话跟踪阶段
会话跟踪是会话管理中的第二大漏洞元凶,我们来看一下在此阶段中会出现的安全问题。
授权绕过(Authorisation Bypass)
当没有充分检查用户是否有权执行他们所请求的操作时,就会发生授权绕过。从本质上讲,这代表我们没能正确跟踪用户的会话及其相关权限。有两种类型的授权绕过值得讨论:
-
垂直绕过(Vertical bypass) - 你可以执行只有更高权限的用户才能执行的操作;这代表你获取到了管理员用户或者其他较高权限用户的执行权限。
-
水平绕过(Horizontal bypass) - 你看似可以执行允许你执行的操作,但针对的对象可以是你不应被允许执行操作的数据集;这代表你获取到了其他普通用户的执行权限。
在大多数应用程序中,垂直绕过很容易防御,因为我们可以使用函数装饰器以及基于路径的访问控制配置。然而,对于水平绕过,用户看起来正在执行他们应该被允许执行的操作,但问题是他们是在其他用户的数据基础上执行的。为了解决这个问题,需要使用实际的代码来验证用户身份(从其会话中提取)、了解用户正在请求哪些数据以及他们是否被允许请求或修改数据集。
日志记录不足(Insufficient Logging)
在安全事件发生时的一个关键问题是没有足够的信息来拼凑还原攻击过程。虽然大量的日志记录将发生在基础设施层面,但应用程序日志记录对于了解问题所在至关重要。如果由特定会话执行的操作没有被记录并且无法从该会话追溯到相关的用户,那么这可能会在调查中留下无法被填补的空白。同时,还应该确保日志记录将涵盖被允许和被拒绝的操作。在发生会话劫持攻击的情况下,一些操作可能看起来是合法的,因此,简单地记录被拒绝的操作并不足以还原完整的攻击过程。
会话过期阶段
关于会话过期只有一个缺陷,那就是会话过期时间过长。会话可以被看作是一张电影票,每天晚上都会放映同一部电影,但我们不希望有人能够用同一张电影票去重复观看这部电影。对于会话来说也是如此,我们不希望有太长的会话过期时间,同时我们还需要确保会话过期时间能够考虑到特定应用程序的使用案例,例如,一个银行应用程序的会话有效期应该比一个网页邮件客户端中的会话有效期要更短。
此外,在会话具有很长的有效期的情况下,例如一个网页邮件客户端中的会话,会话本身应证明它在什么地理位置被使用,如果此位置发生变化(这表明可能存在会话劫持),则应该终止会话。
会话终止阶段
对于会话终止,关键问题在于:当用户执行注销操作时,会话并没有在服务器端被正确终止。假设攻击者劫持了用户的会话,在这种情况下,即使用户意识到了问题所在,如果不能在服务器端使会话失效,那么用户也无法清除攻击者的访问权限。对于令牌来说,这可能会是一个很严重的问题,因为令牌的有效期被嵌入在令牌本身中。在这种情况下,可以将令牌添加到黑名单中进行验证。一些应用程序甚至更进一步,允许查看和终止用户的所有会话。此外,在成功重置密码后,也建议终止所有会话,以允许用户重新获得对其账户的完全控制。
答题
如果你可以预测会话的值,那么会话管理生命周期的哪个阶段将容易受到攻击?
Session Creation
如果你无法清除威胁行为者对于你的会话的访问权限,那么会话管理生命周期的哪个阶段将容易受到攻击?
Session Termination
如果没有足够的信息来拼凑出安全事件发生期间所出现的具体情况,那么会话管理生命周期的哪个阶段将容易受到攻击?
Session Tracking
如果会话值本身是通过不安全的重定向被传输的,那么会话管理生命周期的哪个阶段将容易受到攻击?
Session Creation
利用不安全的会话(Session)管理
利用你已经获得的知识,现在是时候探索如何绘制和测试会话管理生命周期了。通过点击与本文相关的TryHackMe实验房间页面顶部的Start Machine按钮,你可以很快地启动该实验虚拟机,同时你还可以使用 AttackBox 或者你自己的本地Kali虚拟机来作为你的攻击机。
枚举
为了有效地利用易受攻击的会话管理生命周期,我们首先需要绘制出整个生命周期并详细记录每个阶段的观察结果。一旦我们理解了预期的生命周期,我们就可以开始寻找其中的漏洞了。我们将使用浏览器的内置工具来完成下面的示例演示。在该演示中,你可以使用更高级的Web应用程序测试工具,例如Burp。
首先,我们在AttackBox攻击机的浏览器中导航到我们的目标Web应用程序:http://MACHINE_IP/
我们应该可以看到以下页面:
我们首先注意到,当我们第一次访问上述页面时,我们没有在Storage中看到任何cookie或令牌。这告诉我们,在目标应用程序中,未经身份验证的会话很可能不会被跟踪。如果我们点击上述页面中的“Sign-Up/注册”按钮,我们会看到有两个主要的注册项:
-
Student(学生) -任何人都可以使用它来创建个人资料;
-
Lecturer(讲师) - 在注册过程中需要验证码。
这告诉我们,即使不使用任何暴力破解技术,我们也可以通过创建学生账户来启动会话管理生命周期。让我们创建一个学生账户,看看会发生什么:
在创建了用户账户后,我们会收到账户已创建的提示,并且会被导航回登录页面。接下来,让我们以我们的用户身份执行登录并监控network流量:
tips:可能需要多试几次,才能看到Set-Cookie。
这告诉了我们很多信息:
- Cookies 被用于会话管理。
- 设置了HTTPOnly标志,这意味着我们将无法利用JavaScript来读取cookie值。
- 这里的cookie过期时间看起来很奇怪,因为显示的cookie创建时间和过期时间完全相同(这表明该会话将即时过期)-上面的配图是错的,并不能体现这一点。
通过这个身份验证,我们还注意到我们现在可以访问该应用程序的更多功能:
使用菜单导航并查看浏览器内置工具所提供的network流量部分内容,我们可以看到会话跟踪是通过与每个请求一起被传输的cookie来强制执行的:
请注意,根据你所使用的浏览器,你的请求标头可能会略有不同。不过,值得注意的是,即使cookie已经过期,相同的set cookie标头仍然被用来将cookie刷新为与之前完全相同的值。这可能指示我们有一个持久化的cookie。让我们看看当我们删除这个cookie后会发生什么。在开发者工具的storage选项下,我们删除cookie并再次发出/module
请求:
此请求似乎仍然会成功?但是,如果你仔细观察一下,你会发现我们现在只能看到如下图所示的modules(模块),而看不到已注册学生的数量或潜在的考试:
这告诉我们,我们可能需要做进一步调查,以确定我们从完全未经身份验证的角度究竟会被允许访问哪些内容。同样,只有经过进一步调查,我们才能完整地绘制出会话管理的生命周期。不过,我们会尽量简化流程。让我们先来看看应用程序的注销功能。当我们按下注销按钮后,我们可以看到我们的会话在客户端被移除了:
但是,我们或许应该测试一下会话是否也在服务器端被终止了。我们可以重新对这个应用程序进行身份验证,并将新的Cookie替换为旧的Cookie值;但是,当我们刷新页面时会收到 500 内部服务器错误,这告诉我们这里确实出了问题,因为无效的会话不应该会导致内部服务器错误。让我们来调查一下。
让我们回顾一下我们之前的一些做法。如果我们现在导航到浏览器内置工具的Local Storage部分,我们会注意到这里存储了一些数据:
让我们将上图中的用户角色(userRole)从学生(student)更新为讲师(lecturer),并刷新一下页面:
虽然我们现在可以访问更多的选项卡,但似乎我们无法获得更多的信息,这需要我们继续探索。让我们进一步在Local Storage中将user值中的role从2更新为3。遗憾的是,结果仍然相同。不过,这里还有更多的值可以让我们尝试,比如我们的id和username。这些新信息告诉我们,该应用程序中的会话可能并不是纯粹通过cookie进行管理的,这里的会话可能还通过了令牌信息进行管理。
现在,我们已经绘制出了会话管理的生命周期,让我们来看一下:
Lifecycle Phase 生命周期阶段 | Observation 观察结果 |
---|---|
Session Creation-会话创建 | 正在使用基于 cookie 和基于令牌的会话管理组合 |
Session Creation-会话创建 | 每次登录尝试都会提供一个新的会话值 |
Session Creation-会话创建 | 会话值本身似乎足够随机 |
Session Tracking-会话跟踪 | 未经身份验证的操作不会通过会话进行跟踪 |
Session Tracking-会话跟踪 | 每次请求都会发送 cookie 以进行跟踪 |
Session Tracking-会话跟踪 | 可以在没有cookie的情况下发出多个请求 |
Session Tracking-会话跟踪 | 身份验证后加载的初始令牌值决定了可见的信息 |
Session Expiry-会话过期 | 客户端和服务器端的会话过期时间不匹配 |
Session Expiry-会话过期 | 有效期长得不可思议 |
Session Termination-会话终止 | 用户可以强制终止其会话 |
Session Termination--会话终止 | 会话在服务器端终止,但是重用旧会话会导致内部服务器错误 |
鉴于所有这些信息,我们可以在安全评估中报告以下漏洞:
- 会话有效期过长(Excessive Session Lifetimes)。
我们还需要进一步调查以下问题:
- 所有 API 端点的访问控制;
- 用于对操作进行问责的 Web 应用程序日志。
漏洞利用
鉴于以上所有信息,我们似乎需要做进一步探索,看看能否访问敏感数据。运用你所学到的关于保护会话管理生命周期的知识以及目前已绘制的生命周期信息,看看你是否能够以学生身份访问讲师信息,并回答以下问题。
我们先部署好实验环境(实验虚拟机、AttackBox攻击机),然后在AttackBox攻击机的浏览器中访问目标应用程序:http://10.10.88.51/
首先,以学生身份在目标网站上进行注册,然后登录,当我们查看浏览器内置工具中的network选项卡,可以注意到有一个 superadmin
的仪表面板 - 来自发送到服务器的请求。所以我们尝试将权限升级到超级管理员。在浏览器内置工具的Local Storage中,将 userRole
的值更改为 superadmin
并刷新页面。
注意:将 userRole
的值更改为 admin
并刷新页面,最终可以查看到的信息会更全面,所以superadmin
可能是没有删除干净的身份。
答题
阅读本小节内容并执行相关操作,以回答以下问题。
学生X在该应用程序上所使用的用户名称是什么?
THM{Got.the.User} 。
有多少讲师(lecturers)在应用程序上注册了账户?
1
除去未经身份验证的用户,应用程序中还有多少种角色?
3 -学生,讲师,管理员(这里输入 3 ,才会显示正确)
在目标应用程序的相关页面上,我们可以看到总共进行了多少次考试尝试?
tips:在浏览器的Local Storage中,将 userRole
的值更改为 admin
并刷新页面。
4
学生1在考试中获得的最高分是多少?
3
Database Types考试的正确答案顺序是什么?(格式 y=yes 以及 n=no ,用逗号分隔)
y,n,n
本文小结
防御
为了防御上文中所提及的这些攻击,实现一个安全的会话管理生命周期至关重要,我们应该了解会话管理生命周期以及如何保护它。在本文内容中我们提到了几个注意事项,让我们来快速回顾一下:
- 会话(Session)的值必须被安全存储,无论是 cookie 还是 token(令牌)。
- 会话(Session)值本身必须是足够随机且不可猜测的,或者使用签名机制来确保它们不会被轻易篡改。
- 会话(Session)应该被用于跟踪用户操作并执行授权检查,以确保用户可以执行所请求的操作。
- 会话(Session)应该在一段时间后过期,以防止它们被用于持久化访问。
- 如果按下注销按钮,则会话(Session)应在客户端被删除,并在服务器端失效;否则,如果会话被盗用,用户将无法销毁其会话。