6.渗透测试指南-会话管理测试

会话管理模式测试

编号
WSTG - SESS - 01

概述

任何基于Web的应用程序的核心组件之一,是控制和维护与之交互的用户状态的机制。为避免对网站或服务的每个页面进行持续认证,Web应用程序会实施各种机制,在预定的时间段内存储和验证凭据。这些机制被称为会话管理。

在本次测试中,测试人员需要检查Cookie和其他会话令牌是否以安全且不可预测的方式创建。若攻击者能够预测并伪造脆弱的Cookie,就可以轻易劫持合法用户的会话。

Cookie用于实现会话管理,RFC 2965中对其进行了详细描述。简而言之,当用户访问一个需要在多个请求中跟踪该用户的操作和身份的应用程序时,服务器会生成一个或多个Cookie并发送给客户端。之后,在Cookie过期或被销毁之前,客户端会在所有后续连接中将Cookie发送回服务器。存储在Cookie中的数据可以为服务器提供关于用户身份、到目前为止执行的操作、偏好等大量信息,从而为像HTTP这样的无状态协议赋予状态。

一个典型的例子是在线购物车。在用户的整个会话期间,应用程序必须跟踪用户的身份、个人资料、选择购买的商品、数量、单价、折扣等信息。Cookie是一种高效的来回存储和传递这些信息的方式(其他方法包括URL参数和隐藏字段)。

由于Cookie存储的数据很重要,因此它们对应用程序的整体安全性至关重要。能够篡改Cookie可能会导致劫持合法用户的会话、在活动会话中获得更高权限,并且通常会以未经授权的方式影响应用程序的操作。

在本次测试中,测试人员必须检查发给客户端的Cookie是否能够抵御各种旨在干扰合法用户会话和应用程序本身的攻击。总体目标是能够伪造一个被应用程序视为有效的Cookie,并提供某种未经授权的访问(会话劫持、权限提升等)。

通常,攻击模式的主要步骤如下:

  • Cookie收集:收集足够数量的Cookie样本。
  • Cookie逆向工程:分析Cookie生成算法。
  • Cookie操作:伪造一个有效的Cookie以进行攻击。根据Cookie的创建方式,最后一步可能需要进行大量尝试(Cookie暴力攻击)。

另一种攻击模式是使Cookie溢出。严格来说,这种攻击性质不同,因为测试人员在此并不是试图重新创建一个完全有效的Cookie。相反,目标是使内存区域溢出,从而干扰应用程序的正常运行,并可能注入(并远程执行)恶意代码。

测试目标

  • 尽可能为同一用户和不同用户收集会话令牌。
  • 分析并确保会话令牌具有足够的随机性,以阻止会话伪造攻击。
  • 修改未签名且包含可操作信息的Cookie。

测试方法

黑盒测试及示例

客户端与应用程序之间的所有交互至少应针对以下标准进行测试:

  • 所有Set - Cookie指令是否都标记为Secure
  • 是否有任何Cookie操作是通过未加密的传输进行的?
  • 是否可以强制Cookie通过未加密的传输?
  • 如果可以,应用程序如何保持安全性?
  • 是否有任何Cookie是持久化的?
  • 持久化Cookie使用的Expires时间是多少,是否合理?
  • 预期为临时的Cookie是否按此配置?
  • 使用了哪些HTTP / 1.1Cache - Control设置来保护Cookie?
  • 使用了哪些HTTP / 1.0Cache - Control设置来保护Cookie?

Cookie收集

操作Cookie的第一步是了解应用程序如何创建和管理Cookie。为此,测试人员需要尝试回答以下问题:

  • 应用程序使用了多少个Cookie?
    浏览应用程序,记录Cookie何时创建。列出收到的Cookie、设置它们的页面(使用set - cookie指令)、它们有效的域名、它们的值及其特征。
  • 应用程序的哪些部分会生成或修改Cookie?
    浏览应用程序,找出哪些Cookie保持不变,哪些会被修改。哪些事件会修改Cookie?
  • 应用程序的哪些部分需要此Cookie才能访问和使用?
    找出应用程序中哪些部分需要Cookie。访问一个页面,然后尝试在没有Cookie或使用修改后的值的情况下再次访问。尝试映射各个Cookie的使用位置。
    此阶段的一个有价值的输出可以是一个电子表格,将每个Cookie映射到相应的应用程序部分以及相关信息。

会话分析

应检查会话令牌(Cookie、SessionID或隐藏字段)本身,以确保从安全角度来看它们的质量。应根据诸如随机性、唯一性、对统计和密码分析的抵抗力以及信息泄露等标准对它们进行测试。

  • 令牌结构与信息泄露
    第一步是检查应用程序提供的会话ID的结构和内容。一个常见的错误是在令牌中包含特定数据,而不是发布一个通用值并在服务器端引用实际数据。
    如果会话ID是明文的,其结构和相关数据可能会立即显现出来,例如192.168.100.1:owaspuser:password:15:58
    如果部分或整个令牌看起来是经过编码或哈希处理的,应将其与各种技术进行比较,以检查是否存在明显的混淆。例如,字符串192.168.100.1:owaspuser:password:15:58的十六进制、Base64和MD5哈希表示如下:
    • 十六进制:3139322E3136382E3130302E313A6F77617370757365723A70617373776F72643A31353A3538
    • Base64:MTkyLjE2OC4xMDAuMTpvd2FzcHVzZXI6cGFzc3dvcmQ6MTU6NTg=
    • MD5:01c2fc4f0a817afd8366689bd29dd40a
      确定了混淆类型后,有可能将其解码回原始数据。然而,在大多数情况下,这是不太可能的。即便如此,从消息的格式枚举出所使用的编码方式可能会很有用。此外,如果可以推断出格式和混淆技术,就可以设计自动化的暴力攻击。
      混合令牌可能包含诸如IP地址或用户ID之类的信息以及编码部分,例如owaspuser:192.168.100.1:a7656fafe94dae72b1e1487670148412
      分析单个会话令牌后,应检查具有代表性的样本。对令牌进行简单分析应能立即发现任何明显的模式。例如,一个32位的令牌可能包含16位的静态数据和16位的可变数据。这可能表明前16位代表用户的固定属性,例如用户名或IP地址。如果后16位以固定速率递增,可能表明令牌生成具有顺序甚至基于时间的元素。请参阅示例。
      如果识别出令牌中的静态元素,应收集更多样本,每次改变一个潜在的输入元素。例如,通过不同的用户账户或从不同的IP地址进行登录尝试,可能会使会话令牌中之前的静态部分发生变化。
      在单个和多个会话ID结构测试期间,应解决以下问题:
    • 会话ID的哪些部分是静态的?
    • 会话ID中存储了哪些明文的机密信息?例如用户名/用户ID、IP地址。
    • 存储了哪些易于解码的机密信息?
    • 从会话ID的结构可以推断出哪些信息?
    • 在相同的登录条件下,会话ID的哪些部分是静态的?
    • 会话ID整体或各个部分存在哪些明显的模式?

会话ID的可预测性和随机性

应对会话ID的可变区域(如果有)进行分析,以确定是否存在任何可识别或可预测的模式。这些分析可以手动进行,也可以使用定制或现成的统计或密码分析工具来推断会话ID内容中的任何模式。手动检查应包括比较在相同登录条件下(例如,相同的用户名、密码和IP地址)颁发的会话ID。
时间也是一个必须控制的重要因素。应进行大量的同时连接,以便在同一时间窗口内收集样本,并使该变量保持不变。即使是50毫秒或更短的量化间隔也可能太粗,以这种方式获取的样本可能会揭示出原本会被忽略的基于时间的组件。
应随时间分析可变元素,以确定它们是否具有递增性质。如果它们是递增的,应研究与绝对时间或经过时间相关的模式。许多系统使用时间作为其伪随机元素的种子。如果模式看似随机,则应考虑时间或其他环境变化的单向哈希的可能性。通常,加密哈希的结果是十进制或十六进制数字,因此应该可以识别。
在分析会话ID序列、模式或周期时,静态元素和客户端依赖性都应被视为可能影响应用程序结构和功能的因素。

  • 会话ID是否本质上是可证明的随机的?生成的值是否可以重现?
  • 相同的输入条件在后续运行中是否会产生相同的ID?
  • 会话ID是否可证明地抵抗统计或密码分析?
  • 会话ID的哪些元素与时间相关?
  • 会话ID的哪些部分是可预测的?
  • 在完全了解生成算法和先前的ID的情况下,是否可以推断出下一个ID?

Cookie逆向工程

现在测试人员已经枚举了Cookie并大致了解了它们的用途,是时候深入研究那些看起来有趣的Cookie了。测试人员对哪些Cookie感兴趣呢?为了提供一种安全的会话管理方法,Cookie必须具备几个特性,每个特性旨在保护Cookie免受不同类型的攻击。
这些特性总结如下:

  1. 不可预测性:Cookie必须包含一些难以猜测的数据。越难伪造有效的Cookie,就越难闯入合法用户的会话。如果攻击者能够猜测出合法用户活动会话中使用的Cookie,他们就能够完全冒充该用户(会话劫持)。为了使Cookie不可预测,可以使用随机值或密码学。
  2. 防篡改:Cookie必须抵抗恶意修改尝试。如果测试人员收到一个像IsAdmin = No这样的Cookie,那么将其修改为获取管理员权限是很容易的,除非应用程序进行双重检查(例如,在Cookie后面附加其值的加密哈希)。
  3. 过期机制:关键的Cookie必须仅在适当的时间段内有效,之后必须从磁盘或内存中删除,以避免被重放的风险。这不适用于存储需要在会话之间记住的非关键数据的Cookie(例如,网站外观)。
  4. Secure标志:对于会话完整性至关重要的Cookie,应启用此标志,以仅允许在加密通道中传输该Cookie,从而防止窃听。
    这里的方法是收集足够数量的Cookie实例,并开始寻找其值中的模式。“足够数量”的确切含义可能会有所不同,如果Cookie生成方法很容易破解,可能只需要少量样本;如果测试人员需要进行一些数学分析(例如,卡方检验、吸引子分析。详见后文),则可能需要数千个样本。
    特别要注意应用程序的工作流程,因为会话状态会对收集的Cookie产生重大影响。认证前收集的Cookie可能与认证后获得的Cookie非常不同。
    另一个需要考虑的方面是时间。只要有可能时间会影响Cookie的值(服务器可能会使用时间戳作为Cookie值的一部分),就一定要记录获取Cookie的确切时间。记录的时间可以是本地时间,也可以是HTTP响应中包含的服务器时间戳(或者两者都记录)。
    在分析收集到的值时,测试人员应尝试找出所有可能影响Cookie值的变量,并尝试一次改变一个变量。向服务器传递相同Cookie的修改版本,对于理解应用程序如何读取和处理Cookie非常有帮助。
    此阶段要执行的检查示例包括:
  • Cookie使用了什么字符集?Cookie的值是数字、字母数字还是十六进制的?如果测试人员在Cookie中插入不属于预期字符集的字符会发生什么?
  • Cookie是否由携带不同信息的不同子部分组成?不同部分是如何分隔的?使用了哪些分隔符?Cookie的某些部分可能具有较高的变异性,有些可能是常量,有些可能只取有限的一组值。将Cookie分解为其基本组件是第一步也是最基本的一步。
    一个易于识别的结构化Cookie示例如下:
ID=5a0acfc7ffeb919:CR=1:TM=1120514521:LM=1120514521:S=j3am5KzC4v01ba3q

特别相关代码片段翻译

这个示例展示了 5 个不同的字段,携带不同类型的数据:

  • ID —— 十六进制
  • CR —— 小整数
  • TM 和 LM —— 大整数。(奇怪的是它们的值相同。修改其中一个看看会发生什么,这很值得尝试)
  • S —— 字母数字组合

即使没有分隔符,有足够多的样本也有助于理解其结构。

暴力攻击

暴力攻击不可避免地与可预测性和随机性相关。在考虑会话 ID 时,必须结合应用程序的会话持续时间和超时设置,来评估其内部的变化情况。如果会话 ID 的变化相对较小,并且会话 ID 的有效期较长,那么暴力攻击成功的可能性就会高得多。

较长的会话 ID(或者说具有大量变化可能性的会话 ID)和较短的有效期会使暴力攻击成功的难度大大增加。

  • 对所有可能的会话 ID 进行暴力攻击需要多长时间?
  • 会话 ID 的空间是否足够大以防止暴力破解?例如,与有效生命周期相比,密钥长度是否足够?
  • 使用不同会话 ID 进行连接尝试之间的延迟是否能降低这种攻击的风险?

灰盒测试及示例

如果测试人员能够访问会话管理架构的实现代码,他们可以检查以下方面:

  • 随机会话令牌
    发给客户端的会话 ID 或 Cookie 不应容易被预测(不要使用基于可预测变量,如客户端 IP 地址的线性算法)。鼓励使用密钥长度为 256 位的加密算法(如 AES)。
  • 令牌长度
    会话 ID 的长度至少应为 50 个字符。
  • 会话超时
    会话令牌应该有明确的超时设置(这取决于应用程序所管理数据的重要性)。
  • Cookie 配置
    • 非持久化:仅存储在内存中。
    • 安全(仅在 HTTPS 通道上设置):Set-Cookie: cookie=data; path=/; domain=.aaa.it; secure
    • HTTP 仅用(脚本不可读取):Set-Cookie: cookie=data; path=/; domain=.aaa.it; HttpOnly

更多信息请参考:Cookies 属性测试

工具

参考资料

白皮书

测试Cookie属性

ID
WSTG - SESS - 02

概述

Web Cookie(以下简称Cookie)通常是恶意用户(通常针对其他用户)的关键攻击载体,应用程序应始终谨慎保护Cookie。

HTTP是一种无状态协议,这意味着它不会保留同一用户发送的请求的任何引用。为了解决这个问题,人们创建了会话并将其附加到HTTP请求中。如[测试浏览器存储](…/11 - 客户端测试/12 - 测试浏览器存储.md)中所述,浏览器包含多种存储机制,该指南的该部分对每种机制都进行了详细讨论。

浏览器中最常用的会话存储机制是Cookie存储。服务器可以通过在HTTP响应中包含[Set - Cookie](https://developer.mozilla.org/en - US/docs/Web/HTTP/Headers/Set - Cookie)标头或通过JavaScript来设置Cookie。Cookie可用于多种目的,例如:

  • 会话管理
  • 个性化设置
  • 跟踪

为了保护Cookie数据,行业内已经开发出了一些方法来锁定这些Cookie并减少其攻击面。随着时间的推移,Cookie已成为Web应用程序首选的存储机制,因为它们在使用和保护方面具有很大的灵活性。

保护Cookie的方法有:

测试目标

确保为Cookie设置了适当的安全配置。

测试方法

以下将讨论每个属性和前缀。测试人员应验证应用程序是否正确使用了它们。可以使用[拦截代理](#intercepting - proxy)或查看浏览器的Cookie存储来查看Cookie。

Cookie属性

Secure属性

[Secure](https://developer.mozilla.org/en - US/docs/Web/HTTP/Headers/Set - Cookie#Secure)属性告诉浏览器仅在请求通过安全通道(如HTTPS)发送时才发送Cookie。这有助于防止Cookie在未加密的请求中被传递。如果应用程序可以通过HTTPHTTPS访问,攻击者可能能够重定向用户,使其在非受保护的请求中发送Cookie。

HttpOnly属性

[HttpOnly](https://developer.mozilla.org/en - US/docs/Web/HTTP/Headers/Set - Cookie#HttpOnly)属性用于帮助防止会话泄露等攻击,因为它不允许通过客户端脚本(如JavaScript)访问Cookie。

这并不能限制XSS攻击的整个攻击面,因为攻击者仍然可以代替用户发送请求,但会极大地限制XSS攻击向量的影响范围。

Domain属性

[Domain](https://developer.mozilla.org/en - US/docs/Web/HTTP/Cookies#Scope_of_cookies)属性用于将Cookie的域与发出HTTP请求的服务器的域进行比较。如果域匹配或为子域,则接下来将检查[path](#path - attribute)属性。

请注意,只有属于指定域的主机才能为该域设置Cookie。此外,domain属性不能是顶级域(如.gov.com),以防止服务器为其他域设置任意Cookie(例如为owasp.org设置Cookie)。如果未设置domain属性,则生成Cookie的服务器的主机名将用作domain的默认值。

例如,如果app.mydomain.com上的应用程序设置了一个Cookie且未设置domain属性,则该Cookie将在对app.mydomain.com的所有后续请求中重新提交,但不会发送到其子域(如hacker.app.mydomain.com)或otherapp.mydomain.com。(不过,旧版本的Edge/IE行为不同,它们会将这些Cookie发送到子域。)如果开发人员想放宽此限制,可以将domain属性设置为mydomain.com。在这种情况下,Cookie将被发送到对app.mydomain.commydomain.com子域(如hacker.app.mydomain.com,甚至bank.mydomain.com)的所有请求中。如果子域(例如otherapp.mydomain.com)上有一个易受攻击的服务器,并且domain属性设置得过于宽松(例如mydomain.com),则该易受攻击的服务器可能会被用于跨mydomain.com的整个范围收集Cookie(如会话令牌)。

Path属性

[Path](https://developer.mozilla.org/en - US/docs/Web/HTTP/Cookies#Scope_of_cookies)属性与[domain](#domain - attribute)属性一起在设置Cookie的作用域方面起着重要作用。除了域之外,还可以指定Cookie有效的URL路径。如果域和路径匹配,则Cookie将包含在请求中发送。与domain属性一样,如果path属性设置得过于宽松,可能会使应用程序容易受到同一服务器上其他应用程序的攻击。例如,如果path属性设置为Web服务器根目录/,则应用程序的Cookie将被发送到同一域内的每个应用程序(如果多个应用程序位于同一服务器下)。同一服务器下多个应用程序的一些示例如下:

  • path=/bank
  • path=/private
  • path=/docs
  • path=/docs/admin
Expires属性

[Expires](https://developer.mozilla.org/en - US/docs/Web/HTTP/Cookies#Permanent_cookies)属性用于:

  • 设置持久化Cookie
  • 如果会话存在时间过长,则限制其生命周期
  • 通过将其设置为过去的日期来强制删除Cookie

与[会话Cookie](https://developer.mozilla.org/en - US/docs/Web/HTTP/Cookies#Session_cookies)不同,持久化Cookie将被浏览器使用,直到Cookie过期。一旦过期日期超过设置的时间,浏览器将删除该Cookie。

SameSite属性

[SameSite](https://developer.mozilla.org/en - US/docs/Web/HTTP/Cookies#SameSite_cookies)属性可用于确定Cookie是否应随跨站请求一起发送。此功能允许服务器降低跨源信息泄露的风险。在某些情况下,它也用作降低风险(或纵深防御机制)策略,以防止[跨站请求伪造](05 - 测试跨站请求伪造.md)攻击。此属性可以配置为三种不同的模式:

  • Strict

  • Lax

  • None

  • Strict值Strict值是SameSite最严格的用法,它允许浏览器仅在第一方上下文且无顶级导航的情况下发送Cookie。换句话说,与Cookie关联的数据仅会在与浏览器URL栏中显示的当前站点匹配的请求中发送。Cookie不会在第三方站点生成的请求中发送。此值特别适用于在同一域中执行的操作。但是,它可能会对某些会话管理系统产生一些限制,从而对用户的导航体验产生负面影响。由于浏览器不会在第三方域或电子邮件生成的任何请求中发送Cookie,因此即使用户已经有经过身份验证的会话,也需要再次登录。

  • Lax值Lax值比Strict宽松。如果URL等于Cookie的域(第一方),即使链接来自第三方域,Cookie也会被发送。大多数浏览器将此值视为默认行为,因为它比Strict值提供更好的用户体验。它不会为不需要Cookie即可访问的资源(如图像)触发。

  • None值None值指定浏览器将在所有上下文中发送Cookie,包括跨站请求(这是在实现SameSite之前的正常行为)。如果设置了Samesite=None,则必须设置Secure属性,否则现代浏览器将忽略SameSite属性,例如SameSite=None; Secure

Cookie前缀

从设计上讲,Cookie无法保证存储在其中的信息的完整性和保密性。这些限制使得服务器无法确定给定Cookie的属性在创建时是如何设置的。为了以向后兼容的方式为服务器提供这些功能,行业引入了[Cookie名称前缀](https://tools.ietf.org/html/draft - ietf - httpbis - cookie - prefixes - 00)的概念,以便将这些详细信息作为Cookie名称的一部分进行传递。

Host前缀

[__Host -](https://developer.mozilla.org/en - US/docs/Web/HTTP/Cookies#Cookie_prefixes)前缀要求Cookie满足以下条件:

  1. 必须使用[Secure属性](#secure - attribute)设置Cookie。
  2. 必须从用户代理认为安全的URI设置Cookie。
  3. 仅发送到设置Cookie的主机,并且不得包含任何[Domain属性](#domain - attribute)。
  4. 必须使用[Path属性](#path - attribute)将Cookie设置为/,以便它会随对主机的每个请求一起发送。

因此,Cookie Set - Cookie: __Host - SID = 12345; Secure; Path = /将被接受,而以下任何一个都将始终被拒绝:

Set - Cookie: __Host - SID = 12345
Set - Cookie: __Host - SID = 12345; Secure
Set - Cookie: __Host - SID = 12345; Domain = site.example
Set - Cookie: __Host - SID = 12345; Domain = site.example; Path = /
Set - Cookie: __Host - SID = 12345; Secure; Domain = site.example; Path = /
Secure前缀

[__Secure -](https://developer.mozilla.org/en - US/docs/Web/HTTP/Cookies#Cookie_prefixes)前缀限制较少,可以通过在Cookie名称前添加区分大小写的字符串__Secure -来引入。任何匹配__Secure -前缀的Cookie都应满足以下条件:

  1. 必须使用Secure属性设置Cookie。
  2. 必须从用户代理认为安全的URI设置Cookie。

最佳实践

根据应用程序的需求以及Cookie的功能,必须应用相应的属性和前缀。对Cookie的限制越多越好。

综合以上内容,我们可以将最安全的Cookie属性配置定义为:Set - Cookie: __Host - SID = <session token>; path = /; Secure; HttpOnly; SameSite = Strict

工具

拦截代理

浏览器插件

参考资料

会话固定测试

编号
WSTG - SESS - 03

概述

会话固定漏洞是由于在认证前后保留会话cookie的相同值这一不安全做法所导致的。这种情况通常发生在会话cookie在登录前就被用于存储状态信息时,例如在为支付进行认证之前向购物车中添加商品。

在针对会话固定漏洞的典型攻击中,攻击者可以在未进行认证的情况下从目标网站获取一组会话cookie。然后,攻击者可以使用不同的技术将这些cookie强制注入到受害者的浏览器中。如果受害者随后在目标网站进行认证,并且登录时cookie没有刷新,那么受害者将通过攻击者选择的会话cookie被识别。攻击者随后就能够使用这些已知的cookie来冒充受害者。

可以通过在认证过程后刷新会话cookie来修复此问题。另外,也可以通过确保会话cookie的完整性来防止此类攻击。当考虑网络攻击者(即控制受害者所使用网络的攻击者)时,可以使用完整的 HSTS 或者在cookie名称前添加 __Host- / __Secure- 前缀。

完整的HSTS采用是指主机为自身及其所有子域名启用HSTS。这在Stefano Calzavara、Alvise Rabitti、Alessio Ragazzo和Michele Bugliesi撰写的一篇名为《Testing for Integrity Flaws in Web Sessions》的论文中有描述。

测试目标

  • 分析认证机制及其流程。
  • 强制注入cookie并评估影响。

测试方法

在本节中,我们将解释下一节中会展示的测试策略。

第一步是向要测试的网站(例如 www.example.com)发出请求。如果测试人员发出以下请求:

GET / HTTP/1.1
Host: www.example.com

他们将获得以下响应:

HTTP/1.1 200 OK
Date: Wed, 14 Aug 2008 08:45:11 GMT
Server: IBM_HTTP_Server
Set - Cookie: JSESSIONID=0000d8eyYq3L0z2fgq10m4v - rt4:-1; Path=/; secure
Cache - Control: no - cache="set - cookie,set - cookie2"
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Keep - Alive: timeout=5, max=100
Connection: Keep - Alive
Content - Type: text/html;charset=Cp1254
Content - Language: en - US

应用程序为客户端设置了一个新的会话标识符 JSESSIONID=0000d8eyYq3L0z2fgq10m4v - rt4:-1

接下来,如果测试人员通过以下向 https://www.example.com/authentication.php 的POST请求成功对应用程序进行认证:

POST /authentication.php HTTP/1.1
Host: www.example.com
[...]
Referer: https://www.example.com
Cookie: JSESSIONID=0000d8eyYq3L0z2fgq10m4v - rt4:-1
Content - Type: application/x - www - form - urlencoded
Content - length: 57

Name=Meucci&wpPassword=secret!&wpLoginattempt=Log+in

测试人员会观察到服务器的以下响应:

HTTP/1.1 200 OK
Date: Thu, 14 Aug 2008 14:52:58 GMT
Server: Apache/2.2.2 (Fedora)
X - Powered - By: PHP/5.1.6
Content - language: en
Cache - Control: private, must - revalidate, max - age=0
X - Content - Encoding: gzip
Content - length: 4090
Connection: close
Content - Type: text/html; charset=UTF - 8
...
HTML数据
...

由于成功认证后没有发出新的cookie,测试人员知道,除非确保会话cookie的完整性,否则就有可能进行会话劫持。

测试人员可以将有效的会话标识符发送给用户(可能使用社会工程学技巧),等待用户进行认证,然后验证此cookie是否已被赋予相应权限。

强制注入cookie测试

此测试策略针对的是网络攻击者,因此仅需应用于未完全采用HSTS的网站(完全采用HSTS的网站是安全的,因为它们所有的cookie都具有完整性)。我们假设在被测网站上有两个测试账户,一个用作受害者,一个用作攻击者。我们模拟这样一个场景:攻击者将登录后未新生成且不具有完整性的所有cookie强制注入到受害者的浏览器中。受害者登录后,攻击者将这些强制注入的cookie提交给网站以访问受害者的账户:如果这些cookie足以代表受害者进行操作,则会话固定攻击是可行的。

以下是执行此测试的步骤:

  1. 访问网站的登录页面。
  2. 保存登录前cookie存储的快照,排除名称中包含 __Host-__Secure- 前缀的cookie。
  3. 以受害者身份登录网站,并访问任何提供需要认证的安全功能的页面。
  4. 将cookie存储设置为步骤2中拍摄的快照。
  5. 触发步骤3中确定的安全功能。
  6. 观察步骤5中的操作是否成功执行。如果成功,则攻击成功。
  7. 清除cookie存储,以攻击者身份登录并访问步骤3中的页面。
  8. 将步骤2中保存的cookie逐个写入cookie存储。
  9. 再次触发步骤3中确定的安全功能。
  10. 清除cookie存储,再次以受害者身份登录。
  11. 观察步骤9中的操作是否在受害者账户中成功执行。如果成功,则攻击成功;否则,该网站对会话固定攻击具有防护能力。

我们建议为受害者和攻击者使用不同的机器或浏览器。如果Web应用程序使用指纹识别来验证从给定cookie进行的访问,这样可以减少误报的数量。该测试策略的一个更简短但不太精确的变体只需要一个测试账户。它遵循相同的步骤,但在步骤6停止。

修复建议

在用户成功认证后实现会话令牌更新。

应用程序在对用户进行认证之前,应始终先使现有的会话ID无效,如果认证成功,则提供另一个会话ID。

工具

参考资料

暴露会话变量的测试

编号
WSTG - SESS - 04

概述

会话令牌(Cookie、会话 ID、隐藏字段)如果被暴露,攻击者通常能够假冒受害者并非法访问应用程序。因此,必须始终保护这些会话令牌不被窃听,特别是在客户端浏览器和应用程序服务器之间传输时。

此处的信息涉及传输安全如何应用于敏感会话 ID 数据的传输,而非一般数据的传输,并且其可能比网站所提供数据的缓存和传输策略更为严格。

使用个人代理,可以确定每个请求和响应的以下信息:

  • 所使用的协议(例如,HTTP 与 HTTPS)
  • HTTP 标头
  • 消息体(例如,POST 请求或页面内容)

每次会话 ID 数据在客户端和服务器之间传递时,都应检查协议、缓存、隐私指令和消息体。此处的传输安全是指通过 GET 或 POST 请求、消息体或其他有效 HTTP 请求方式传递的会话 ID。

测试目标

  • 确保实施了适当的加密。
  • 审查缓存配置。
  • 评估通道和传输方法的安全性。

测试方法

会话令牌加密和重用漏洞测试

防止窃听通常通过 TLS 加密来实现,但也可能包括其他隧道或加密技术。需要注意的是,会话 ID 的加密或加密哈希应与传输加密分开考虑,因为保护的是会话 ID 本身,而非其可能代表的数据。

如果攻击者可以向应用程序提交会话 ID 以获得访问权限,那么必须在传输过程中保护该会话 ID 以降低风险。因此,无论使用何种机制(例如,隐藏表单字段),都应确保在传递会话 ID 的任何请求或响应中,加密是默认设置且强制执行的。在与应用程序交互时,应进行简单的检查,例如将 https:// 替换为 http://,并修改表单提交,以确定安全和非安全站点之间是否实现了充分的隔离。

请注意,如果网站中有一部分使用会话 ID 跟踪用户,但不具备安全性(例如,记录注册用户下载了哪些公共文档),则必须使用不同的会话 ID。因此,当客户端从安全部分切换到非安全部分时,应监控会话 ID,以确保使用了不同的会话 ID。

每次身份验证成功时,用户应该期望收到:

  • 不同的会话令牌
  • 每次进行 HTTP 请求时,令牌都通过加密通道发送

代理和缓存漏洞测试

在审查应用程序安全性时,还必须考虑代理。在许多情况下,客户端会通过企业、互联网服务提供商(ISP)或其他代理或协议感知网关(例如,防火墙)访问应用程序。HTTP 协议提供了控制下游代理行为的指令,也应评估这些指令的正确实施情况。

一般来说,会话 ID 永远不应通过未加密的传输方式发送,也不应被缓存。应检查应用程序,确保在任何会话 ID 传输中,加密通信都是默认设置且强制执行的。此外,每当传递会话 ID 时,应设置指令以防止中间缓存甚至本地缓存对其进行缓存。

应用程序还应配置为在 HTTP/1.0 和 HTTP/1.1 中保护缓存中的数据。RFC 2616 讨论了与 HTTP 相关的适当控制措施。HTTP/1.1 提供了多种缓存控制机制。Cache-Control: no-cache 表示代理不得重用任何数据。虽然 Cache-Control: Private 似乎是一个合适的指令,但它仍然允许非共享代理缓存数据。在网吧或其他共享系统的情况下,这存在明显的风险。即使在单用户工作站上,缓存的会话 ID 也可能因文件系统被攻破或使用网络存储而暴露。HTTP/1.0 缓存不识别 Cache-Control: no-cache 指令。

应使用 Expires: 0Cache-Control: max-age = 0 指令,以进一步确保缓存不会暴露数据。应检查每个传递会话 ID 数据的请求/响应,以确保使用了适当的缓存指令。

GET 和 POST 漏洞测试

一般来说,不应使用 GET 请求,因为会话 ID 可能会在代理或防火墙日志中暴露。此外,GET 请求比其他传输类型更容易被操纵,不过需要注意的是,使用合适的工具,几乎任何传输机制都可以被客户端操纵。此外,跨站脚本攻击(XSS) 最容易通过向受害者发送特制链接来实施。如果数据从客户端以 POST 请求方式发送,这种攻击的可能性会大大降低。

应测试所有从 POST 请求接收数据的服务器端代码,以确保如果数据以 GET 请求方式发送,服务器端代码不会接受。例如,考虑登录页面生成的以下 POST 请求 (https://owaspapp.com/login.asp):

POST /login.asp HTTP/1.1
Host: owaspapp.com
[...]
Cookie: ASPSESSIONIDABCDEFG=ASKLJDLKJRELKHJG
Content-Length: 51

Login=Username&password=Password&SessionID=12345678

如果 login.asp 实现不当,可能可以使用以下 URL 进行登录:https://owaspapp.com/login.asp?Login=Username&password=Password&SessionID=12345678

通过这种方式检查每个 POST 请求,可以识别出潜在的不安全服务器端脚本。

传输漏洞测试

应至少根据以下标准测试客户端和应用程序之间的所有交互:

  • 会话 ID 是如何传输的?例如,GET、POST、表单字段(包括隐藏字段)
  • 会话 ID 是否默认始终通过加密传输方式发送?
  • 是否可以操纵应用程序以未加密方式发送会话 ID?例如,将 HTTPS 更改为 HTTP
  • 对传递会话 ID 的请求/响应应用了哪些缓存控制指令?
  • 这些指令是否始终存在?如果不是,例外情况在哪里?
  • 是否使用了包含会话 ID 的 GET 请求?
  • 如果使用了 POST 请求,是否可以与 GET 请求互换?

参考资料

白皮书

跨站请求伪造测试

编号
WSTG - SESS - 05

概述

跨站请求伪造(CSRF)是一种攻击手段,它迫使终端用户在已登录认证的 Web 应用程序中执行非本意的操作。攻击者借助一些社会工程学手段(如通过电子邮件或聊天工具发送链接),就能迫使 Web 应用程序的用户执行攻击者所期望的操作。若攻击目标是普通用户,成功的 CSRF 攻击会危及用户的数据和操作。若目标用户是管理员账户,CSRF 攻击则可能危及整个 Web 应用程序。

CSRF 攻击依赖于以下几点:

  1. 浏览器处理与会话相关信息(如 Cookie 和 HTTP 认证信息)的行为。
  2. 攻击者对有效 Web 应用程序 URL、请求或功能的了解。
  3. 应用程序会话管理仅依赖于浏览器所掌握的信息。
  4. 存在能立即访问 HTTP[S] 资源的 HTML 标签,例如图片标签 <img>

第 1、2、3 点是产生此漏洞的必要条件,而第 4 点有助于实际实施攻击,但并非绝对必要。

  1. 浏览器会自动发送用于识别用户会话的信息。假设 site 是托管 Web 应用程序的站点,用户 victim 刚在 site 完成认证。作为响应,site 会向 victim 发送一个 Cookie,用于识别 victim 发送的请求属于其已认证的会话。浏览器接收到 site 设置的 Cookie 后,会在后续向 site 发送的任何请求中自动附带该 Cookie。
  2. 如果应用程序未在 URL 中使用与会话相关的信息,那么应用程序的 URL、其参数和合法值就可能被识别出来。这可以通过代码分析或访问应用程序并记录 HTML 或 JavaScript 中嵌入的表单和 URL 来实现。
  3. “浏览器所掌握的信息”指的是像 Cookie 或基于 HTTP 的认证信息(如基本认证,而非基于表单的认证)这类信息,这些信息由浏览器存储,并会在每个指向需要认证的应用程序区域的请求中自动携带。接下来讨论的漏洞适用于完全依赖此类信息来识别用户会话的应用程序。

为简便起见,以可通过 GET 方式访问的 URL 为例(不过讨论内容同样适用于 POST 请求)。若 victim 已完成认证,当提交另一个请求时,浏览器会自动附带 Cookie。下图展示了用户访问 www.example.com 上的应用程序的情况。

在这里插入图片描述

图 4.6.5 - 1:会话劫持

用户可以通过以下几种不同方式发送 GET 请求:

  • 使用 Web 应用程序。
  • 直接在浏览器中输入 URL。
  • 点击指向该 URL 的外部链接。

应用程序无法区分这些调用方式。特别是第三种方式可能相当危险。有许多技术和漏洞可用于掩盖链接的真实属性。链接可以嵌入电子邮件中,出现在引诱用户访问的恶意网站上,或者出现在第三方托管的内容(如其他网站或 HTML 电子邮件)中,并指向应用程序的某个资源。如果用户点击该链接,由于他们已在 site 的 Web 应用程序中完成认证,浏览器会向该 Web 应用程序发出一个附带认证信息(会话 ID Cookie)的 GET 请求。这会导致在 Web 应用程序上执行用户意料之外的有效操作,例如在网上银行应用程序中进行资金转账。

通过使用如上述第 4 点中提到的 <img> 标签,甚至无需用户点击特定链接。假设攻击者向用户发送一封电子邮件,诱使用户访问一个包含以下(简化)HTML 页面的 URL。

<html>
    <body>
...
<img src="https://www.company.example/action" width="0" height="0">
...
    </body>
</html>

当浏览器显示此页面时,它也会尝试显示来自 https://www.company.example 的指定零尺寸(因此不可见)图片。这会导致自动向 site 上托管的 Web 应用程序发送一个请求。图片 URL 是否指向一个合适的图片并不重要,因为其存在会触发 src 字段中指定的 action 请求。只要浏览器未禁用图片下载,就会发生这种情况。大多数浏览器不会禁用图片下载,因为那样会使大多数 Web 应用程序无法正常使用。

这里的问题是由以下原因导致的:

  • 页面上的 HTML 标签会导致自动执行 HTTP 请求(<img> 就是其中之一)。
  • 浏览器无法判断 <img> 引用的资源是否为合法图片。
  • 无论所谓的图片源位于何处,图片都会加载,即表单和图片本身无需位于同一主机甚至同一域名下。

与 Web 应用程序无关的 HTML 内容可能引用应用程序中的组件,以及浏览器会自动向应用程序发出有效请求这一事实,使得此类攻击成为可能。除非让攻击者无法与应用程序功能进行交互,否则无法禁止这种行为。

在集成的邮件/浏览器环境中,仅仅显示包含图片引用的电子邮件消息就会导致使用相关浏览器 Cookie 向 Web 应用程序执行请求。电子邮件消息可能引用看似有效的图片 URL,例如:

<img src="https://[attacker]/picture.gif" width="0" height="0">

在这个例子中,[attacker] 是攻击者控制的站点。通过利用重定向机制,恶意站点可以使用 https://[attacker]/picture.gif 将受害者重定向到 https://[thirdparty]/action 并触发 action

Cookie 并非这种漏洞的唯一示例。会话信息完全由浏览器提供的 Web 应用程序也容易受到攻击。这包括仅依赖 HTTP 认证机制的应用程序,因为认证信息由浏览器掌握,并且会在每次请求时自动发送。这并不包括基于表单的认证,这种认证仅发生一次,并会生成某种与会话相关的信息,通常是一个 Cookie。

假设受害者已登录到防火墙 Web 管理控制台。用户登录时需要进行身份验证,会话信息会存储在 Cookie 中。

假设防火墙 Web 管理控制台有一个功能,允许已认证的用户删除由数字 ID 指定的规则,或者如果用户指定 *,则删除配置中的所有规则(实际上这是一个危险的功能,但作为示例更有趣)。接下来展示删除页面。为简单起见,假设表单发出一个 GET 请求。要删除规则编号为 1 的规则:

https://[target]/fwmgt/delete?rule=1

要删除所有规则:

https://[target]/fwmgt/delete?rule=*

这个例子有意设计得较为简单,但以简化的方式展示了 CSRF 的危险性。

在这里插入图片描述

图 4.6.5 - 2:会话劫持防火墙管理

使用上图所示的表单,输入值 * 并点击“删除”按钮将提交以下 GET 请求:

https://www.company.example/fwmgt/delete?rule=*

这将删除所有防火墙规则。

在这里插入图片描述

图 4.6.5 - 3:会话劫持防火墙管理 2

用户也可以通过手动提交 URL 来达到相同的结果:

https://[target]/fwmgt/delete?rule=*

或者通过点击直接或通过重定向指向上述 URL 的链接。或者,再次通过访问嵌入指向同一 URL 的 <img> 标签的 HTML 页面。

在所有这些情况下,如果用户当前已登录到防火墙管理应用程序,请求将成功并修改防火墙的配置。可以想象针对敏感应用程序的攻击,如自动进行拍卖投标、资金转账、下订单、更改关键软件组件的配置等。

有趣的是,这些漏洞可能在防火墙后面被利用;即只要被攻击的链接可被受害者访问,而不必直接被攻击者访问即可。特别是,它可以是任何内部网 Web 服务器;例如,在前面提到的防火墙管理场景中,该服务器不太可能暴露在互联网上。

自我易受攻击的应用程序,即既被用作攻击向量又被用作攻击目标的应用程序(如 Web 邮件应用程序),会使情况变得更糟。由于用户在阅读电子邮件消息时已登录,这种类型的易受攻击应用程序会使攻击者能够执行诸如删除消息或发送看似来自受害者的消息等操作。

测试目标

  • 确定是否有可能代表用户发起并非由用户发起的请求。

测试方法

审查应用程序,以确定其会话管理是否存在漏洞。如果会话管理仅依赖于客户端的值(浏览器可获取的信息),那么该应用程序就存在漏洞。“客户端的值”指的是 Cookie 和 HTTP 认证凭证(基本认证和其他形式的 HTTP 认证;不包括基于表单的认证,这是一种应用程序级别的认证)。

通过 HTTP GET 请求可访问的资源很容易受到攻击,不过 POST 请求也可以通过 JavaScript 实现自动化,同样存在漏洞;因此,仅使用 POST 方法不足以解决 CSRF 漏洞的问题。

对于 POST 请求,可以使用以下示例。

  1. 创建一个类似于下面所示的 HTML 页面。
  2. 将该 HTML 页面托管在恶意或第三方站点上。
  3. 将该页面的链接发送给受害者,并诱使他们点击。
<html>
<body onload='document.CSRF.submit()'>

<form action='https://targetWebsite/Authenticate.jsp' method='POST' name='CSRF'>
    <input type='hidden' name='name' value='Hacked'>
    <input type='hidden' name='password' value='Hacked'>
</form>

</body>
</html>

对于开发人员使用 JSON 进行浏览器与服务器通信的 Web 应用程序,可能会出现一个问题,因为 JSON 格式没有查询参数,而自提交表单必须有查询参数。为了绕过这种情况,我们可以使用带有 JSON 有效负载(包括隐藏输入)的自提交表单来利用 CSRF。我们需要将编码类型 (enctype) 更改为 text/plain,以确保有效负载按原样传递。攻击代码如下所示:

<html>
 <body>
  <script>history.pushState('', '', '/')</script>
   <form action='https://victimsite.com' method='POST' enctype='text/plain'>
     <input type='hidden' name='{"name":"hacked","password":"hacked","padding":"'value='something"}' />
     <input type='submit' value='Submit request' />
   </form>
 </body>
</html>

POST 请求如下:

POST / HTTP/1.1
Host: victimsite.com
Content-Type: text/plain

{"name":"hacked","password":"hacked","padding":"=something"}

当此数据作为 POST 请求发送时,服务器将愉快地接受 namepassword 字段,并忽略名为 padding 的字段,因为它不需要该字段。

修复建议

工具

参考资料

注销功能测试

编号
WSTG - SESS - 06

概述

会话终止是会话生命周期的重要组成部分。将会话令牌的生命周期减至最短,可降低会话劫持攻击成功的可能性。这可以被视为一种防范跨站脚本攻击(Cross - Site Scripting)和跨站请求伪造(Cross - Site Request Forgery)等其他攻击的控制手段。已知这些攻击依赖于用户存在已认证的会话。不安全的会话终止只会增加这些攻击的攻击面。

安全的会话终止至少需要以下组件:

  • 提供允许用户手动注销的用户界面控件。
  • 在给定的无活动时间后终止会话(会话超时)。
  • 正确使服务器端会话状态无效。

有多个问题可能会妨碍会话的有效终止。对于理想的安全 Web 应用程序,用户应该能够通过用户界面随时终止会话。每个页面都应在直接可见的位置包含一个注销按钮。不清晰或模棱两可的注销功能可能会导致用户不信任此类功能。

会话终止中另一个常见的错误是,客户端会话令牌被设置为新值,而服务器端状态仍然处于活动状态,并且可以通过将会话 cookie 恢复为先前的值来重新使用。有时仅向用户显示确认消息,而不执行任何进一步的操作。这种情况应该避免。

一些 Web 应用程序框架仅依赖会话 cookie 来识别已登录用户。用户 ID 嵌入在(加密的)cookie 值中。应用程序服务器在服务器端不进行任何会话跟踪。注销时,会话 cookie 会从浏览器中移除。然而,由于应用程序不进行任何跟踪,它并不知道会话是否已注销。因此,通过重用会话 cookie 有可能访问已认证的会话。一个众所周知的例子是 ASP.NET 中的表单身份验证功能。

Web 浏览器的用户通常不介意应用程序仍处于打开状态,只是关闭浏览器或标签页。Web 应用程序应该意识到这种行为,并在定义的时间后在服务器端自动终止会话。

使用单点登录(SSO)系统而非特定于应用程序的身份验证方案通常会导致多个会话共存,这些会话必须分别终止。例如,特定于应用程序的会话终止并不会终止 SSO 系统中的会话。导航回 SSO 门户会让用户有机会重新登录到刚刚注销的应用程序。另一方面,SSO 系统中的注销功能并不一定会导致关联应用程序中的会话终止。

测试目标

  • 评估注销用户界面。
  • 分析会话超时情况,以及注销后会话是否被正确终止。

测试方法

注销用户界面测试

验证用户界面中注销功能的外观和可见性。为此,从想要从 Web 应用程序注销的用户的角度查看每个页面。

以下属性表明是一个良好的注销用户界面:

  • Web 应用程序的所有页面上都存在注销按钮。
  • 想要从 Web 应用程序注销的用户应该能够快速识别注销按钮。
  • 页面加载后,注销按钮应该无需滚动即可看到。
  • 理想情况下,注销按钮应放置在浏览器视口中固定的页面区域,不受内容滚动的影响。

服务器端会话终止测试

首先,存储用于识别会话的 cookie 值。调用注销功能并观察应用程序的行为,特别是关于会话 cookie 的行为。尝试导航到仅在已认证会话中可见的页面,例如使用浏览器的后退按钮。如果显示的是页面的缓存版本,请使用重新加载按钮从服务器刷新页面。如果注销功能将会话 cookie 设置为新值,请恢复会话 cookie 的旧值并重新加载应用程序已认证区域的页面。如果这些测试在特定页面上未显示任何漏洞,请至少尝试应用程序中被认为是安全关键的其他一些页面,以确保应用程序的这些区域能正确识别会话终止。

在执行测试时,检查的页面上不应显示仅应向已认证用户显示的数据。理想情况下,在会话终止后访问已认证区域时,应用程序应重定向到公共区域或登录表单。虽然设置会话 cookie 为新值对应用程序的安全性并非必需,但通常认为这是一种良好的做法。

会话超时测试

尝试通过以递增的延迟向 Web 应用程序已认证区域的页面发送请求来确定会话超时时间。如果出现注销行为,则使用的延迟时间大致与会话超时值匹配。

由非活动超时导致的注销应与前面描述的服务器端会话终止测试结果相同。

会话超时的合适值取决于应用程序的用途,应在安全性和可用性之间取得平衡。在银行应用程序中,将非活动会话保持超过 15 分钟是没有意义的。另一方面,在维基或论坛中,较短的超时时间可能会因不必要的登录请求而困扰正在撰写长篇文章的用户。在这种情况下,一小时或更长时间的超时是可以接受的。

单点登录环境中的会话终止测试(单点注销)

在被测应用程序中执行注销操作。验证是否存在中央门户或应用程序目录,允许用户无需身份验证即可重新登录到该应用程序。测试当请求应用程序的入口点 URL 时,应用程序是否要求用户进行身份验证。在被测应用程序中登录时,在 SSO 系统中执行注销操作。然后尝试访问被测应用程序的已认证区域。

期望连接到 SSO 系统的 Web 应用程序或 SSO 系统本身调用注销功能时,能导致所有会话的全局终止。在 SSO 系统和关联应用程序中注销后,应要求用户进行身份验证才能访问应用程序。

工具

参考资料

白皮书

测试会话超时

编号
WSTG - SESS - 07

概述

在此阶段,测试人员需检查应用程序是否会在用户闲置一段时间后自动注销用户,确保无法“复用”同一会话,并且浏览器缓存中不会残留敏感数据。

所有应用程序都应实现会话的闲置或非活动超时机制。此超时机制定义了在用户无活动的情况下,会话保持活跃的时长。自 Web 应用程序接收到给定会话 ID 的最后一个 HTTP 请求起,达到定义的闲置时间后,会话将关闭并失效。最合适的超时时间应在安全性(较短的超时时间)和可用性(较长的超时时间)之间取得平衡,并且很大程度上取决于应用程序处理的数据的敏感程度。例如,对于公共论坛而言,60 分钟的注销时间可能是可以接受的,但对于家庭银行应用程序来说,这样长的时间就过长了(建议最长超时时间为 15 分钟)。无论如何,任何未强制执行基于超时的注销功能的应用程序都应被视为不安全的,除非特定的功能需求要求有此行为。

闲置超时机制减少了攻击者猜测并使用其他用户有效会话 ID 的机会,在某些情况下,还可以防止公共计算机上的会话被复用。然而,如果攻击者能够劫持某个会话,闲置超时机制并不能限制攻击者的操作,因为攻击者可以定期在会话上产生活动,使会话长时间保持活跃。

会话超时管理和过期必须在服务器端强制执行。如果使用客户端控制的数据来强制执行会话超时,例如使用 cookie 值或其他客户端参数来跟踪时间参考(如自登录时间起的分钟数),攻击者可以操纵这些数据来延长会话时长。因此,应用程序必须在服务器端跟踪非活动时间,并且在超时到期后,自动使当前用户的会话失效,并删除存储在客户端的所有数据。

这两个操作都必须谨慎实施,以避免引入可能被攻击者利用的漏洞。如果用户忘记从应用程序中注销,攻击者可能会利用这些漏洞获得未经授权的访问权限。更具体地说,对于注销功能,重要的是要确保所有会话令牌(如 cookie)都被正确销毁或变得不可用,并且在服务器端实施适当的控制,以防止会话令牌被复用。如果这些操作没有正确执行,攻击者可以重放这些会话令牌,以“复活”合法用户的会话并假冒该用户(这种攻击通常被称为“cookie 重放”)。当然,一个缓解因素是攻击者需要能够访问这些令牌(这些令牌存储在受害者的计算机上),但在很多情况下,这并非不可能或特别困难。

这种攻击最常见的场景是在公共计算机上访问某些私人信息(如网络邮件、在线银行账户)。如果用户在离开计算机时没有明确注销,并且应用程序未实现会话超时机制,那么攻击者只需按下浏览器的“后退”按钮就可以访问同一账户。

测试目标

  • 验证是否存在硬性会话超时机制。

测试方法

黑盒测试

在测量超时注销时,可以采用与[测试注销功能](06 - Testing_for_Logout_Functionality.md)部分相同的方法。测试方法非常相似。首先,测试人员必须检查是否存在超时机制,例如,通过登录并等待超时注销被触发。与注销功能一样,超时过后,所有会话令牌都应被销毁或变得不可用。

然后,如果配置了超时机制,测试人员需要了解该超时机制是由客户端还是服务器(或两者)强制执行的。如果会话 cookie 是非持久的(或者更一般地说,会话 cookie 不存储任何与时间相关的数据),测试人员可以假设超时机制是由服务器强制执行的。如果会话 cookie 包含一些与时间相关的数据(如登录时间、最后访问时间或持久 cookie 的过期日期),则客户端可能参与了超时的强制执行。在这种情况下,测试人员可以尝试修改 cookie(如果它没有经过加密保护),并观察会话会发生什么变化。例如,测试人员可以将会话 cookie 的过期日期设置为遥远的未来,看看会话是否可以延长。

一般来说,所有的检查都应该在服务器端进行,通过将会话 cookie 重新设置为以前的值,不应该能够再次访问应用程序。

灰盒测试

测试人员需要检查以下几点:

  • 注销功能是否有效地销毁了所有会话令牌,或者至少使它们不可用;
  • 服务器是否对会话状态进行了适当的检查,禁止攻击者重放先前已销毁的会话标识符;
  • 是否强制执行了超时机制,并且该机制是由服务器正确执行的。如果服务器使用从客户端发送的会话令牌中读取的过期时间(但不建议这样做),则该令牌必须经过加密保护,以防被篡改。

请注意,最重要的是应用程序要在服务器端使会话失效。一般来说,这意味着代码必须调用适当的方法,例如 Java 中的 HttpSession.invalidate() 和 .NET 中的 Session.abandon()。建议清除浏览器中的 cookie,但这不是严格必要的,因为如果会话在服务器端被正确失效,浏览器中存在 cookie 也不会帮助攻击者。

参考资料

OWASP 资源

会话混淆测试

ID
WSTG-SESS-08

总结

会话变量重载(也称为会话混淆)是一种应用程序级别的漏洞,攻击者可利用该漏洞执行多种恶意操作,包括但不限于:

  • 绕过有效的身份验证强制机制,假冒合法用户。
  • 在原本被认为万无一失的环境中提升恶意用户账户的权限。
  • 跳过多阶段流程中的限定阶段,即使该流程包含所有常用的代码级限制。
  • 以无法预测或检测的间接方法操纵服务器端的值。
  • 在以前无法访问甚至被认为安全的位置执行传统攻击。

当应用程序将同一个会话变量用于多个目的时,就会出现此漏洞。攻击者可能会以开发人员未预料到的顺序访问页面,从而使会话变量在一个上下文中被设置,然后在另一个上下文中被使用。

例如,攻击者可以使用会话变量重载来绕过应用程序的身份验证强制机制,这些应用程序通过验证包含身份相关值的会话变量的存在来强制进行身份验证,这些值通常在成功的身份验证过程后存储在会话中。这意味着攻击者首先访问应用程序中设置会话上下文的位置,然后访问检查此上下文的特权位置。

例如,攻击者可以通过访问一个公共可访问的入口点(如密码恢复页面)来执行身份验证绕过攻击,该入口点会根据固定值或用户输入在会话中填充相同的会话变量。

测试目标

  • 识别所有会话变量。
  • 破坏会话生成的逻辑流程。

测试方法

黑盒测试

可以通过枚举应用程序使用的所有会话变量以及它们在哪些上下文中有效来检测和利用此漏洞。具体来说,可以通过访问一系列入口点,然后检查出口点来实现。在黑盒测试的情况下,此过程很困难,需要一些运气,因为每个不同的序列都可能导致不同的结果。

示例

一个非常简单的示例是密码重置功能,在入口点,该功能可能会要求用户提供一些识别信息,如用户名或电子邮件地址。然后,此页面可能会将会话用这些识别值填充,这些值直接从客户端接收,或者通过查询或基于接收到的输入进行计算获得。此时,应用程序中可能有一些页面会根据此会话对象显示私人数据。通过这种方式,攻击者可以绕过身份验证过程。

灰盒测试

检测这些漏洞最有效的方法是进行源代码审查。

修复建议

会话变量应该仅用于单一的、一致的目的。

参考资料

会话劫持测试

ID
WSTG-SESS-09

概述

攻击者若获取了用户的会话 cookie,就可以通过提交这些 cookie 来冒充该用户。这种攻击被称为会话劫持。当考虑网络攻击者(即控制受害者所使用网络的攻击者)时,会话 cookie 可能会在 HTTP 协议下过度暴露给攻击者。为防止这种情况,会话 cookie 应标记为 Secure 属性,这样它们就只会通过 HTTPS 进行传输。

请注意,当 Web 应用程序完全部署在 HTTPS 上时,也应该使用 Secure 属性,否则可能会发生以下 cookie 窃取攻击。假设 example.com 完全部署在 HTTPS 上,但没有将会话 cookie 标记为 Secure,则可能会出现以下攻击步骤:

  1. 受害者向 https://another-site.com 发送请求。
  2. 攻击者篡改相应的响应,使其触发对 https://example.com 的请求。
  3. 浏览器现在尝试访问 https://example.com
  4. 尽管请求失败,但会话 cookie 会以明文形式通过 HTTP 泄露。

另外,也可以通过使用 HSTS 禁止使用 HTTP 来防止会话劫持。需要注意的是,这里与 cookie 作用域相关存在一个微妙的问题。特别是,当会话 cookie 设置了 Domain 属性时,需要全面采用 HSTS。

Stefano Calzavara、Alvise Rabitti、Alessio Ragazzo 和 Michele Bugliesi 撰写的论文《Testing for Integrity Flaws in Web Sessions》中描述了全面采用 HSTS 的情况。当一个主机为自身及其所有子域启用 HSTS 时,即为全面采用 HSTS;当一个主机仅为自身启用 HSTS 时,则为部分采用 HSTS。

设置 Domain 属性后,会话 cookie 可以在子域之间共享。应避免在子域中使用 HTTP,以防止通过 HTTP 发送的未加密 cookie 泄露。为举例说明这个安全漏洞,假设站点 example.com 在未使用 includeSubDomains 选项的情况下启用了 HSTS。该站点将会话 cookie 的 Domain 属性设置为 example.com,则可能会发生以下攻击:

  1. 受害者向 https://another-site.com 发送请求。
  2. 攻击者篡改相应的响应,使其触发对 https://fake.example.com 的请求。
  3. 浏览器现在尝试访问 https://fake.example.com,这在 HSTS 配置下是允许的。
  4. 由于请求是发送到 example.com 的子域,且设置了 Domain 属性,因此请求中包含会话 cookie,这些 cookie 会以明文形式通过 HTTP 泄露。

应在顶级域名上全面启用 HSTS 以防止此类攻击。

测试目标

  • 识别易受攻击的会话 cookie。
  • 劫持易受攻击的 cookie 并评估风险级别。

测试方法

此测试策略针对的是网络攻击者,因此仅需应用于未全面采用 HSTS 的站点(全面采用 HSTS 的站点是安全的,因为它们的 cookie 不会通过 HTTP 传输)。我们假设在被测站点上有两个测试账户,一个作为受害者,一个作为攻击者。我们模拟一个场景,攻击者窃取所有未针对通过 HTTP 泄露进行保护的 cookie,并将这些 cookie 提交给站点以访问受害者的账户。如果这些 cookie 足以代表受害者进行操作,则会话劫持是可能的。

以下是执行此测试的步骤:

  1. 以受害者身份登录站点,并访问任何提供需要身份验证的安全功能的页面。
  2. 从 cookie 存储中删除满足以下任何条件的所有 cookie:
    • 如果未采用 HSTS:设置了 Secure 属性。
    • 如果部分采用 HSTS:设置了 Secure 属性或未设置 Domain 属性。
  3. 保存 cookie 存储的快照。
  4. 触发步骤 1 中确定的安全功能。
  5. 观察步骤 4 中的操作是否成功执行。如果成功,则攻击成功。
  6. 清空 cookie 存储,以攻击者身份登录并访问步骤 1 中的页面。
  7. 逐个将步骤 3 中保存的 cookie 写入 cookie 存储。
  8. 再次触发步骤 1 中确定的安全功能。
  9. 清空 cookie 存储,再次以受害者身份登录。
  10. 观察步骤 8 中的操作是否在受害者账户中成功执行。如果成功,则攻击成功;否则,该站点对会话劫持具有防护能力。

我们建议为受害者和攻击者使用两台不同的机器或浏览器。如果 Web 应用程序使用指纹识别来验证从给定 cookie 进行的访问,这样可以减少误报的数量。此测试策略的一个更简短但不太精确的变体只需要一个测试账户。它遵循相同的模式,但在步骤 5 停止(请注意,这使得步骤 3 变得无用)。

工具

测试 JSON Web 令牌

编号
WSTG - SESS - 10

概述

JSON Web 令牌(JWT)是经过加密签名的 JSON 令牌,旨在在不同系统之间共享声明信息。它们经常被用作身份验证或会话令牌,特别是在 REST API 中。

JWT 无论是在应用程序中的实现方式,还是在底层库中,都常常是漏洞的来源。由于它们用于身份验证,一旦出现漏洞,很容易导致应用程序被完全攻破。

测试目标

  • 确定 JWT 是否暴露了敏感信息。
  • 确定 JWT 是否可以被篡改或修改。

测试方法

总体概述

JWT 由三个部分组成:

  • 头部
  • 负载(或主体)
  • 签名

每个部分都经过 Base64 编码,并用句点(.)分隔。请注意,JWT 中使用的 Base64 编码会去除等号(=),因此在解码这些部分时可能需要添加这些等号。

分析内容

头部

头部定义了令牌的类型(通常为 JWT)以及用于签名的算法。以下是一个解码后的头部示例:

{
  "alg": "HS256",
  "typ": "JWT"
}

用于计算签名的主要算法有三种:

算法描述
HSxxx使用密钥和 SHA - xxx 的 HMAC 算法。
RSxxx 和 PSxxx使用 RSA 的公钥签名算法。
ESxxx使用 ECDSA 的公钥签名算法。
还有一系列其他算法可用于加密令牌(JWE),不过这些情况不太常见。
负载

JWT 的负载包含实际的数据。以下是一个负载示例:

{
  "username": "administrator",
  "is_admin": true,
  "iat": 1516239022,
  "exp": 1516242622
}

负载通常不进行加密,因此需要检查其中是否包含敏感或可能不适当的数据。

这个 JWT 包含了用户的用户名和管理员状态,以及两个标准声明(iatexp)。这些声明在 RFC 5719 中定义,下面的表格对它们进行了简要总结:

声明全称描述
iss签发者签发令牌的一方的身份。
iat签发时间令牌签发的 Unix 时间戳。
nbf生效时间令牌最早可以使用的 Unix 时间戳。
exp过期时间令牌过期的 Unix 时间戳。
签名

签名是使用 JWT 头部中定义的算法计算得出的,然后进行 Base64 编码并附加到令牌上。修改 JWT 的任何部分都应该导致签名无效,并且服务器会拒绝该令牌。

审查使用情况

除了 JWT 本身需要具备加密安全性外,还需要以安全的方式存储和传输它。这应该包括以下检查:

还应该根据 iatnbfexp 声明来审查 JWT 的有效性,以确定:

  • JWT 对于应用程序来说有合理的有效期。
  • 应用程序会拒绝过期的令牌。

签名验证

JWT 最严重的漏洞之一是应用程序未能验证签名的正确性。这种情况通常发生在开发人员使用如 NodeJS 的 jwt.decode() 函数时,该函数只是简单地解码 JWT 的主体,而不是使用 jwt.verify() 函数,后者会在解码 JWT 之前验证签名。

可以通过修改 JWT 的主体而不更改头部或签名的任何内容,然后在请求中提交修改后的 JWT,查看应用程序是否接受来轻松测试此漏洞。

“无”算法

除了基于公钥和 HMAC 的算法外,JWT 规范还定义了一种名为 none 的签名算法。顾名思义,这意味着 JWT 没有签名,从而可以对其进行修改。

可以通过将 JWT 头部中的签名算法(alg)修改为 none 来进行测试,如下例所示:

{
        "alg": "none",
        "typ": "JWT"
}

然后将头部和负载重新进行 Base64 编码,并移除签名(保留末尾的句点)。使用上面的头部和负载部分列出的负载,将得到以下 JWT:

eyJhbGciOiAibm9uZSIsICJ0eXAiOiAiSldUIn0K.eyJ1c2VybmFtZSI6ImFkbWluaW5pc3RyYXRvciIsImlzX2FkbWluIjp0cnVlLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6MTUxNjI0MjYyMn0.

一些实现会尝试通过显式阻止使用 none 算法来避免此问题。如果是以不区分大小写的方式进行阻止,那么可以通过指定诸如 NoNe 之类的算法来绕过。

ECDSA “通灵签名”

在 Java 15 到 18 版本中发现了一个漏洞,即在某些情况下它们无法正确验证 ECDSA 签名(CVE - 2022 - 21449,称为“通灵签名”)。如果使用这些易受攻击的版本之一来解析使用 ES256 算法的 JWT,则可以通过篡改主体,然后将签名替换为以下值来完全绕过签名验证:

MAYCAQACAQA

结果得到的 JWT 类似于以下形式:

eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6InRydWUifQ.MAYCAQACAQA

弱 HMAC 密钥

如果 JWT 使用基于 HMAC 的算法(如 HS256)进行签名,则签名的安全性完全依赖于 HMAC 中使用的密钥的强度。

如果应用程序使用现成的或开源软件,第一步应该是研究代码,查看是否使用了默认的 HMAC 签名密钥。

如果没有默认密钥,那么可能可以猜测或暴力破解该密钥。最简单的方法是使用 crackjwt.py 脚本,该脚本只需要 JWT 和一个字典文件。

更强大的选择是使用 jwt2john.py 脚本将 JWT 转换为 John the Ripper 可以使用的格式。然后可以使用 John 对密钥进行更高级的攻击。

如果 JWT 很大,可能会超过 John 支持的最大大小。可以通过增加 /src/hmacSHA256_fmt_plug.c(或其他 HMAC 格式的等效文件)中的 SALT_LIMBS 变量的值并重新编译 John 来解决这个问题,如以下 GitHub 问题 中所讨论的。

如果能够获取到这个密钥,就可以创建并签署任意 JWT,这通常会导致应用程序被完全攻破。

HMAC 与公钥混淆

如果应用程序使用基于公钥签名的 JWT,但不检查算法是否正确,那么就可能会受到签名类型混淆攻击。为了使这种攻击成功,需要满足以下条件:

  1. 应用程序必须期望 JWT 使用基于公钥的算法(即 RSxxxESxxx)进行签名。
  2. 应用程序不能检查 JWT 实际使用的签名算法。
  3. 攻击者必须能够获取用于验证 JWT 的公钥。

如果所有这些条件都满足,那么攻击者可以使用公钥通过基于 HMAC 的算法(如 HS256)对 JWT 进行签名。例如,Node.js jsonwebtoken 库对基于公钥和 HMAC 的令牌使用相同的函数,如下例所示:

// 验证使用 RS256 签名的 JWT
jwt.verify(token, publicKey);

// 验证使用 HS256 签名的 JWT
jwt.verify(token, secretKey);

这意味着如果使用 publicKey 作为 HS256 算法的密钥对 JWT 进行签名,签名将被视为有效。

为了利用这个问题,必须获取公钥。最常见的情况是,如果应用程序在签署 JWT 和作为 TLS 证书的一部分时使用相同的密钥,那么可以使用以下命令从服务器下载该密钥:

openssl s_client -connect example.org:443 | openssl x509 -pubkey -noout

或者,该密钥可能可以从网站上的公共文件中获取,例如在常见位置 /.well-known/jwks.json 处。

为了测试这个问题,可以修改 JWT 的内容,然后使用之前获取的公钥通过 HS256 算法对 JWT 进行签名。在没有访问源代码或实现细节的情况下进行测试时,这通常很难实现,因为密钥的格式必须与服务器使用的格式完全相同,所以空格或 CRLF 编码等问题可能会导致密钥不匹配。

攻击者提供公钥

JSON Web 签名(JWS)标准(定义了 JWT 使用的头部和签名)允许将用于签署令牌的密钥嵌入到头部中。如果用于验证令牌的库支持这一点,并且不将密钥与批准的密钥列表进行核对,那么攻击者就可以使用他们提供的任意密钥对 JWT 进行签名。

有多种脚本可用于实现这一点,例如 [jwk - node - jose.py](https://github.com/zi0Black/POC - CVE - 2018 - 0114) 或 jwt_tool

相关测试用例

修复建议

  • 使用安全且最新的库来处理 JWT。
  • 确保签名有效,并且使用的是预期的算法。
  • 使用强 HMAC 密钥或唯一的私钥进行签名。
  • 确保负载中不暴露敏感信息。
  • 确保 JWT 被安全地存储和传输。
  • 请参阅 OWASP JSON Web 令牌备忘单

工具

参考资料

并发会话测试

ID
WSTG - SESS - 11

概述

并发会话是 Web 应用程序的一个常见特性,它允许用户进行多个同时的交互操作。此测试用例旨在评估应用程序处理单个用户多个活动会话的能力。这一功能对于有效管理并发用户会话至关重要,特别是在包含个人身份信息(PII)的管理面板、个人用户账户或依赖第三方服务来丰富用户提供的数据的 API 等敏感区域。主要目标是确保并发会话符合应用程序的安全要求。

了解应用程序的安全需求是评估启用并发会话是否符合预期功能的关键。允许并发会话本身并非有害,而且许多应用程序会有意允许并发会话。然而,至关重要的是要确保应用程序的功能在并发会话方面与安全措施有效匹配。如果允许并发会话,那么必须确保实施额外的安全控制,例如管理活动会话、终止会话以及可能的新会话通知。相反,如果应用程序不打算或未计划支持并发会话,那么就必须验证现有的会话管理漏洞检查机制。

要认识到并发会话的必要性,应考虑以下因素:

  • 了解应用程序的性质,特别是用户可能需要从不同位置或设备同时访问的情况。
  • 识别关键操作,例如需要安全访问的金融交易。
  • 处理敏感数据,如个人身份信息(PII),这表明需要进行安全交互。
  • 区分管理面板和普通用户仪表板,以实现正常的用户访问。

测试目标

通过评估单个用户账户多个活动会话的处理情况,来评估应用程序的会话管理能力。

测试方法

  1. 生成有效会话
    • 提交有效的凭据(用户名和密码)以创建会话。
    • 示例 HTTP 请求:
POST /login HTTP/1.1
Host: www.example.com
Content-Length: 32

username=admin&password=admin123
- 示例响应:
HTTP/1.1 200 OK
Set-Cookie: SESSIONID=0add0d8eyYq3HIUy09hhus; Path=/; Secure
- 存储生成的身份验证 cookie。在某些情况下,生成的身份验证 cookie 会被诸如 JSON Web Tokens(JWT)之类的令牌所取代。
  1. 测试生成活动会话
    • 尝试通过提交登录请求(例如,一百次)来创建多个身份验证 cookie。

注意:使用隐私浏览模式或多账户容器进行这些测试可能会有所帮助,因为它们可以提供独立的环境,用于测试会话管理,而不会受到浏览器中现有会话或 cookie 的干扰。
3. 测试验证活动会话
- 尝试使用初始会话令牌(例如 SESSIONID=0add0d8eyYq3HIUy09hhus)访问应用程序。
- 如果使用第一个生成的令牌成功进行了身份验证,则应将其视为一个潜在问题,表明会话管理不足。

此外,还有一些额外的测试用例,这些用例扩展了测试方法的范围,涵盖了来自不同 IP 地址和位置的多个会话的场景。这些测试用例有助于识别与地理位置或网络相关因素有关的会话处理中的潜在漏洞或异常情况:

  • 测试来自同一 IP 的多个会话。
  • 测试来自不同 IP 的多个会话。
  • 测试来自同一用户在短时间内不太可能或不可能访问的位置的多个会话(例如,一个会话在某个特定国家创建,五分钟后在另一个国家又生成了另一个会话)。

修复建议

应用程序应监控并限制每个用户账户的活动会话数量。如果超过了允许的最大会话数,系统必须使先前的会话无效,以维护安全性。实施以下额外的解决方案可以进一步减轻此漏洞:

  1. 用户通知:每次成功登录后通知用户,以提高用户对活动会话的认识。
  2. 会话管理页面:创建一个专用页面,用于显示并允许用户终止活动会话,以增强用户控制。
  3. IP 地址跟踪:跟踪登录到账户的用户的 IP 地址,并标记任何可疑活动,例如来自不同位置的多次登录。
  4. IP 地址限制:允许用户指定可用于访问其账户的受信任 IP 地址或范围,通过将会话限制在已知和批准的位置来增强安全性。

推荐工具

拦截代理工具

    - 示例响应:
```http
HTTP/1.1 200 OK
Set-Cookie: SESSIONID=0add0d8eyYq3HIUy09hhus; Path=/; Secure
- 存储生成的身份验证 cookie。在某些情况下,生成的身份验证 cookie 会被诸如 JSON Web Tokens(JWT)之类的令牌所取代。
  1. 测试生成活动会话
    • 尝试通过提交登录请求(例如,一百次)来创建多个身份验证 cookie。

注意:使用隐私浏览模式或多账户容器进行这些测试可能会有所帮助,因为它们可以提供独立的环境,用于测试会话管理,而不会受到浏览器中现有会话或 cookie 的干扰。
3. 测试验证活动会话
- 尝试使用初始会话令牌(例如 SESSIONID=0add0d8eyYq3HIUy09hhus)访问应用程序。
- 如果使用第一个生成的令牌成功进行了身份验证,则应将其视为一个潜在问题,表明会话管理不足。

此外,还有一些额外的测试用例,这些用例扩展了测试方法的范围,涵盖了来自不同 IP 地址和位置的多个会话的场景。这些测试用例有助于识别与地理位置或网络相关因素有关的会话处理中的潜在漏洞或异常情况:

  • 测试来自同一 IP 的多个会话。
  • 测试来自不同 IP 的多个会话。
  • 测试来自同一用户在短时间内不太可能或不可能访问的位置的多个会话(例如,一个会话在某个特定国家创建,五分钟后在另一个国家又生成了另一个会话)。

修复建议

应用程序应监控并限制每个用户账户的活动会话数量。如果超过了允许的最大会话数,系统必须使先前的会话无效,以维护安全性。实施以下额外的解决方案可以进一步减轻此漏洞:

  1. 用户通知:每次成功登录后通知用户,以提高用户对活动会话的认识。
  2. 会话管理页面:创建一个专用页面,用于显示并允许用户终止活动会话,以增强用户控制。
  3. IP 地址跟踪:跟踪登录到账户的用户的 IP 地址,并标记任何可疑活动,例如来自不同位置的多次登录。
  4. IP 地址限制:允许用户指定可用于访问其账户的受信任 IP 地址或范围,通过将会话限制在已知和批准的位置来增强安全性。

推荐工具

拦截代理工具

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值