测试目录遍历与文件包含
编号 |
---|
WSTG - ATHZ - 01 |
概述
许多 Web 应用程序在日常运行中会使用和管理文件。如果输入验证方法设计或部署不当,攻击者就可能利用系统漏洞来读取或写入本不可访问的文件。在某些特定情况下,甚至可以执行任意代码或系统命令。
传统上,Web 服务器和 Web 应用程序会实施身份验证机制来控制对文件和资源的访问。Web 服务器会尝试将用户文件限制在“根目录”或“Web 文档根目录”内,这代表着文件系统上的一个物理目录。用户需要将此目录视为 Web 应用程序层次结构的基础目录。
权限的定义是通过访问控制列表(ACL)来完成的,该列表会识别哪些用户或用户组应该能够访问、修改或执行服务器上的特定文件。这些机制旨在防止恶意用户访问敏感文件(例如,类 UNIX 平台上常见的 /etc/passwd
文件),或者避免执行系统命令。
许多 Web 应用程序使用服务器端脚本来包含各种类型的文件。使用这种方法来管理图像、模板、加载静态文本等是很常见的。不幸的是,如果输入参数(即表单参数、Cookie 值)没有得到正确验证,这些应用程序就会暴露出安全漏洞。
在 Web 服务器和 Web 应用程序中,这种问题会在路径遍历/文件包含攻击中出现。通过利用此类漏洞,攻击者能够读取他们通常无法访问的目录或文件,访问 Web 文档根目录之外的数据,或者从外部站点包含脚本和其他类型的文件。
出于 OWASP 测试指南的目的,仅考虑与 Web 应用程序相关的安全威胁,而不考虑对 Web 服务器的威胁(例如,微软 IIS Web 服务器中臭名昭著的 %5c
转义码)。对于感兴趣的读者,参考部分将提供进一步的阅读建议。
这种攻击也被称为“点点斜杠”攻击(../
)、目录遍历、目录攀升或回溯。
在评估过程中,为了发现路径遍历和文件包含漏洞,测试人员需要执行两个不同的阶段:
- 输入向量枚举(对每个输入向量进行系统评估)
- 测试技术(对攻击者用于利用漏洞的每种攻击技术进行系统评估)
测试目标
- 识别与路径遍历相关的注入点。
- 评估绕过技术并确定路径遍历的程度。
测试方法
黑盒测试
输入向量枚举
为了确定应用程序的哪些部分容易受到输入验证绕过的影响,测试人员需要枚举应用程序中所有接受用户输入的部分。这还包括 HTTP GET 和 POST 查询,以及文件上传和 HTML 表单等常见选项。
以下是此阶段需要执行的一些检查示例:
- 是否存在可用于文件相关操作的请求参数?
- 是否存在不寻常的文件扩展名?
- 是否有有趣的变量名?
https://example.com/getUserProfile.jsp?item=ikki.html
https://example.com/index.php?file=content
https://example.com/main.cgi?home=index.htm
- 是否可以识别 Web 应用程序用于动态生成页面或模板的 Cookie?
Cookie: ID=d9ccd3f4f9f18cc1:TM=2166255468:LM=1162655568:S=3cFpqbJgMSSPKVMV:TEMPLATE=flower
Cookie: USER=1826cc8f:PSTYLE=GreenDotRed
测试技术
测试的下一阶段是分析 Web 应用程序中存在的输入验证函数。以前面的示例为例,名为 getUserProfile.jsp
的动态页面从文件中加载静态信息并将内容显示给用户。攻击者可以插入恶意字符串 ../../../../etc/passwd
来包含 Linux/UNIX 系统的密码哈希文件。显然,只有当验证检查点失败时,这种攻击才有可能成功;根据文件系统权限,Web 应用程序本身必须能够读取该文件。
注意:为了成功测试此漏洞,测试人员需要了解被测试系统以及所请求文件的位置。从 IIS Web 服务器请求 /etc/passwd
是没有意义的。
https://example.com/getUserProfile.jsp?item=../../../../etc/passwd
另一个常见的示例是包含来自外部源的内容:
https://example.com/index.php?file=https://www.owasp.org/malicioustxt
同样的方法也适用于 Cookie 或任何其他用于动态页面生成的输入向量。
更多文件包含有效负载可以在 PayloadsAllTheThings - 文件包含 中找到。
需要注意的是,不同的操作系统使用不同的路径分隔符:
- 类 Unix 系统:
- 根目录:
/
- 目录分隔符:
/
- 根目录:
- Windows 系统:
- 根目录:
<驱动器号>:
- 目录分隔符:
\
或/
- 根目录:
- 经典 macOS 系统:
- 根目录:
<驱动器号>:
- 目录分隔符:
:
- 根目录:
开发人员常见的一个错误是没有考虑到所有形式的编码,因此只对基本编码的内容进行验证。如果最初的测试字符串没有成功,可以尝试另一种编码方案。
你可以在 PayloadsAllTheThings - 目录遍历 中找到编码技术和现成的目录遍历有效负载。
Windows 特定注意事项
- Windows 命令行:在 shell 命令中使用的路径末尾添加以下任何内容,功能上不会有任何差异:
- 路径末尾的尖括号
<
和>
- 路径末尾正确闭合的双引号
- 多余的当前目录标记,如
./
或.\\
- 带有任意项(可能存在也可能不存在)的多余父目录标记:
file.txt
file.txt...
file.txt<空格>
file.txt""""
file.txt<<<>>><
./././file.txt
nonexistant/../file.txt
- 路径末尾的尖括号
- Windows API:在任何将字符串作为文件名的 shell 命令或 API 调用中,以下项会被丢弃:
- 句点
- 空格
- Windows UNC 文件路径:用于引用 SMB 共享上的文件。有时,可以使应用程序引用远程 UNC 文件路径上的文件。如果是这样,Windows SMB 服务器可能会将存储的凭据发送给攻击者,这些凭据可以被捕获并破解。这些路径也可以与自引用的 IP 地址或域名一起使用,以绕过过滤器,或者用于访问攻击者无法访问但 Web 服务器可以访问的 SMB 共享上的文件。
\\server_or_ip\path\to\file.abc
\\?\server_or_ip\path\to\file.abc
- Windows NT 设备命名空间:用于引用 Windows 设备命名空间。某些引用将允许使用不同的路径访问文件系统。
- 可能等同于驱动器号,如
c:\
,甚至是没有分配驱动器号的卷:\\.\GLOBALROOT\Device\HarddiskVolume1\
- 引用机器上的第一个光盘驱动器:
\\.\CdRom0\
- 可能等同于驱动器号,如
灰盒测试
当采用灰盒测试方法进行分析时,测试人员需要遵循与黑盒测试相同的方法。然而,由于他们可以查看源代码,因此可以更轻松、准确地搜索输入向量。在源代码审查过程中,他们可以使用简单的工具(如 grep
命令)在应用程序代码中搜索一个或多个常见模式:包含函数/方法、文件系统操作等。
- PHP:
include()
、include_once()
、require()
、require_once()
、fopen()
、readfile()
等。 - JSP/Servlet:
java.io.File()
、java.io.FileReader()
等。 - ASP:
include file
、include virtual
等。
使用在线代码搜索引擎(如 Searchcode),也有可能在互联网上发布的开源软件中找到路径遍历漏洞。
对于 PHP,测试人员可以使用以下正则表达式:
(include|require)(_once)?\s*['"(]?\s*\$_(GET|POST|COOKIE)
使用灰盒测试方法,可以发现通常在标准黑盒评估中难以发现甚至无法发现的漏洞。
一些 Web 应用程序使用存储在数据库中的值和参数来生成动态页面。当应用程序向数据库添加数据时,可能可以插入精心设计的路径遍历字符串。由于包含函数内的参数看起来是内部的且 安全,但实际上并非如此,因此这种安全问题很难发现。
此外,通过审查源代码,可以分析那些用于处理无效输入的函数:一些开发人员试图将无效输入转换为有效输入,以避免警告和错误。这些函数通常容易出现安全漏洞。
考虑一个具有以下指令的 Web 应用程序:
filename = Request.QueryString("file");
Replace(filename, "/","\");
Replace(filename, "..\","");
可以通过以下方式测试此漏洞:
file=....//....//boot.ini
file=....\\....\\boot.ini
file= ..\..\boot.ini
工具
参考资料
白皮书
绕过授权方案测试
编号 |
---|
WSTG - ATHZ - 02 |
概述
此类测试主要关注验证针对每个角色或权限实现的授权方案,以确保其对受限功能和资源的访问控制有效性。
在评估过程中,针对测试人员所拥有的每个特定角色,以及应用程序在认证后阶段执行的每个功能和请求,有必要验证以下几点:
- 用户未认证时是否仍可访问该资源?
- 用户注销后是否仍可访问该资源?
- 拥有不同角色或权限的用户是否可以访问本应受限的功能和资源?
尝试以管理员用户身份访问应用程序,并跟踪所有管理功能。
- 非管理员用户登录时是否可以访问管理功能?
- 拥有不同角色且该操作应被拒绝的用户是否可以使用这些管理功能?
测试目标
评估是否存在水平或垂直越权访问的可能性。
测试方法
- 进行水平资源访问和操作。
- 进行垂直资源访问和操作。
水平绕过授权方案测试
对于应用程序执行的每个功能、特定角色或请求,需要验证以下内容:
- 拥有相同角色或权限但不同身份的用户是否可以访问其他用户应可访问的资源?
- 拥有相同角色或权限但不同身份的用户是否可以对其他用户应可访问的资源执行操作?
针对每个角色:
- 注册或生成两个具有相同权限的用户。
- 建立并保持两个不同的会话处于活动状态(每个用户一个会话)。
- 对于每个请求,将相关参数和会话标识符从一个令牌更改为另一个令牌,并分析每个令牌的响应。
- 如果响应相同、包含相同的私有数据或表明对其他用户的资源或数据进行了成功操作,则认为该应用程序存在漏洞。
例如,假设 viewSettings
函数是具有相同角色的应用程序每个账户菜单的一部分,并且可以通过请求以下 URL 来访问:https://www.example.com/account/viewSettings
。那么,调用 viewSettings
函数时会生成以下 HTTP 请求:
POST /account/viewSettings HTTP/1.1
Host: www.example.com
[其他 HTTP 头部]
Cookie: SessionID=USER_SESSION
username=example_user
有效且合法的响应:
HTTP1.1 200 OK
[其他 HTTP 头部]
{
"username": "example_user",
"email": "example@email.com",
"address": "Example Address"
}
攻击者可能会尝试使用相同的 username
参数执行该请求:
POST /account/viewCCpincode HTTP/1.1
Host: www.example.com
[其他 HTTP 头部]
Cookie: SessionID=ATTACKER_SESSION
username=example_user
如果攻击者的响应包含 example_user
的数据,则该应用程序容易受到横向移动攻击,即用户可以读取或写入其他用户的数据。
管理功能访问测试
例如,假设 addUser
函数是应用程序管理菜单的一部分,并且可以通过请求以下 URL 来访问:https://www.example.com/admin/addUser
。
那么,调用 addUser
函数时会生成以下 HTTP 请求:
POST /admin/addUser HTTP/1.1
Host: www.example.com
[...]
userID=fakeuser&role=3&group=grp001
进一步的问题或考虑方向如下:
- 非管理员用户尝试执行该请求时会发生什么?
- 用户是否会被创建?
- 如果创建成功,新用户是否可以使用其权限?
不同角色资源访问测试
各种应用程序会根据用户角色设置资源访问控制。以职业申请表上上传到 S3 存储桶的简历(CV)为例。
作为普通用户,尝试访问这些文件的存储位置。如果能够检索、修改或删除它们,则该应用程序存在漏洞。
特殊请求头处理测试
一些应用程序支持非标准头部,如 X - Original - URL
或 X - Rewrite - URL
,以便允许用头部值中指定的 URL 覆盖请求中的目标 URL。
当应用程序位于根据请求 URL 实施访问控制限制的组件之后时,可以利用这种行为。
基于请求 URL 的访问控制限制示例包括,阻止从互联网访问暴露在 /console
或 /admin
上的管理控制台。
要检测对 X - Original - URL
或 X - Rewrite - URL
头部的支持,可以采取以下步骤。
1. 发送不包含任何 X - Original - Url 或 X - Rewrite - Url 头部的正常请求
GET / HTTP/1.1
Host: www.example.com
[...]
2. 发送一个 X - Original - Url 头部指向不存在资源的请求
GET / HTTP/1.1
Host: www.example.com
X - Original - URL: /donotexist1
[...]
3. 发送一个 X - Rewrite - Url 头部指向不存在资源的请求
GET / HTTP/1.1
Host: www.example.com
X - Rewrite - URL: /donotexist2
[...]
如果任一请求的响应包含资源未找到的标记,则表明该应用程序支持这些特殊请求头。这些标记可能包括 HTTP 响应状态码 404,或响应正文中的“资源未找到”消息。
一旦验证了对 X - Original - URL
或 X - Rewrite - URL
头部的支持,就可以通过向应用程序发送预期的请求来尝试绕过访问控制限制,具体做法是将前端组件允许的 URL 作为主请求 URL,并根据支持的头部将实际目标 URL 指定在 X - Original - URL
或 X - Rewrite - URL
头部中。如果两个头部都支持,则依次尝试,以验证哪个头部可以有效绕过限制。
4. 其他需要考虑的头部
通常,管理面板或与管理相关的功能仅允许本地网络中的客户端访问,因此可能可以滥用各种代理或转发相关的 HTTP 头部来获取访问权限。一些需要测试的头部和值如下:
- 头部:
X - Forwarded - For
X - Forward - For
X - Remote - IP
X - Originating - IP
X - Remote - Addr
X - Client - IP
- 值:
127.0.0.1
(或127.0.0.0/8
或::1/128
地址范围内的任何地址)localhost
- 任何 RFC1918 地址:
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
- 链路本地地址:
169.254.0.0/16
注意:在地址或主机名后面包含端口号也可能有助于绕过 Web 应用防火墙等边缘防护机制。例如:127.0.0.4:80
、127.0.0.4:443
、127.0.0.4:43982
修复建议
对用户、角色和资源应用最小权限原则,以确保不会发生未经授权的访问。
工具
- Zed Attack Proxy (ZAP)
- [ZAP 插件:访问控制测试](https://www.zaproxy.org/docs/desktop/addons/access - control - testing/)
- Port Swigger Burp Suite
参考资料
OWASP 应用程序安全验证标准 4.0.1,v4.0.1 - 1,v4.0.1 - 4,v4.0.1 - 9,v4.0.1 - 16
权限提升测试
ID |
---|
WSTG - ATHZ - 03 |
概述
本节描述了从一个级别提升权限到另一个级别的问题。在此阶段,测试人员应验证用户是否无法以可能导致权限提升攻击的方式修改其在应用程序内的权限或角色。
当用户获得比正常情况下更多的资源或功能访问权限时,就会发生权限提升,而这种提升或更改本应由应用程序阻止。这通常是由应用程序中的漏洞引起的。结果是,应用程序以比开发人员或系统管理员预期更高的权限执行操作。
权限提升的程度取决于攻击者被授权拥有的权限,以及在成功利用漏洞时可以获得的权限。例如,一个编程错误允许用户在成功认证后获得额外的权限,这种情况下权限提升的程度有限,因为用户已经被授权拥有某些权限。同样,一个远程攻击者在未经任何认证的情况下获得超级用户权限,则代表着更高程度的权限提升。
通常,当可以访问授予更高级别账户的资源时(例如,获取应用程序的管理权限),人们称之为“垂直提升”;当可以访问授予类似配置账户的资源时(例如,在网上银行应用程序中,访问与另一个用户相关的信息),则称之为“水平提升”。
测试目标
- 识别与权限操作相关的注入点。
- 进行模糊测试或以其他方式尝试绕过安全措施。
测试方法
角色/权限操作测试
在应用程序中,用户可以在数据库中创建信息(例如,进行支付、添加联系人或发送消息)、接收信息(账户对账单、订单详情等)或删除信息(删除用户、消息等)的每个部分,都需要记录这些功能。测试人员应尝试以其他用户的身份访问这些功能,以验证是否可以访问该用户角色/权限不允许访问的功能(但其他用户可能被允许访问)。
用户组操作
例如,以下 HTTP POST 请求允许属于 grp001
用户组的用户访问订单 #0001:
POST /user/viewOrder.jsp HTTP/1.1
Host: www.example.com
...
groupID=grp001&orderID=0001
验证不属于 grp001
用户组的用户是否可以修改 groupID
和 orderID
参数的值,以访问该特权数据。
用户配置文件操作
例如,以下服务器响应显示了用户成功认证后返回的 HTML 中的一个隐藏字段:
HTTP/1.1 200 OK
Server: Netscape - Enterprise/6.0
Date: Wed, 1 Apr 2006 13:51:20 GMT
Set - Cookie: USER=aW78ryrGrTWs4MnOd32Fs51yDqp; path=/; domain=www.example.com
Set - Cookie: SESSION=k+KmKeHXTgDi1J5fT7Zz; path=/; domain= www.example.com
Cache - Control: no - cache
Pragma: No - cache
Content - length: 247
Content - Type: text/html
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Connection: close
<form name="autoriz" method="POST" action = "visual.jsp">
<input type="hidden" name="profile" value="SysAdmin">
<body onload="document.forms.autoriz.submit()">
</td>
</tr>
如果测试人员将 profile
变量的值修改为 SysAdmin
会怎样?是否有可能成为 管理员?
条件值操作
例如,在一个环境中,服务器在一组响应代码的特定参数值中包含错误消息,如下所示:
@0`1`3`3``0`UC`1`Status`OK`SEC`5`1`0`ResultSet`0`PVValid`-1`0`0` Notifications`0`0`3`Command Manager`0`0`0` StateToolsBar`0`0`0`
StateExecToolBar`0`0`0`FlagsToolBar`0
服务器对用户给予了隐式信任。它认为用户会使用上述消息关闭会话。
在这种情况下,验证是否无法通过修改参数值来提升权限。在这个特定示例中,将 PVValid
的值从 -1
修改为 0
(无错误条件),可能有可能以管理员身份对服务器进行认证。
IP 地址操作
有些网站根据 IP 地址限制访问或统计登录失败次数。
例如:
X - Forwarded - For: 8.1.1.1
在这种情况下,如果网站使用 X - Forwarded - For
的值作为客户端 IP 地址,测试人员可以更改 X - Forwarded - For
HTTP 头的 IP 值,以绕过 IP 源识别。
垂直绕过授权方案测试
垂直授权绕过是指攻击者获得比自己更高的角色的情况。对此类绕过的测试重点在于验证每个角色的垂直授权方案是如何实现的。对于应用程序执行的每个功能、页面、特定角色或请求,都需要验证是否可以:
- 访问只有更高级别角色用户才能访问的资源。
- 对只有更高级别或特定角色用户才能操作的资源执行功能。
对于每个角色:
- 注册一个用户。
- 基于两个不同的角色建立并维护两个不同的会话。
- 对于每个请求,将会话标识符从原始角色更改为另一个角色的会话标识符,并评估每个响应。
- 如果权限较低的会话包含相同的数据,或者表明对高级别权限功能的操作成功,则该应用程序将被视为存在漏洞。
银行网站角色场景
下表说明了银行网站上的系统角色。每个角色都与事件菜单功能的特定权限绑定:
角色 | 权限 | 额外权限 |
---|---|---|
管理员 | 完全控制 | 删除 |
经理 | 修改、添加、读取 | 添加 |
员工 | 读取、修改 | 修改 |
客户 | 只读 | 无 |
如果出现以下情况,应用程序将被视为存在漏洞:
- 客户可以执行管理员、经理或员工的功能。
- 员工用户可以执行经理或管理员的功能。
- 经理可以执行管理员的功能。
假设 deleteEvent
函数是应用程序管理员账户菜单的一部分,可以通过请求以下 URL 来访问它:https://www.example.com/account/deleteEvent
。然后,调用 deleteEvent
函数时会生成以下 HTTP 请求:
POST /account/deleteEvent HTTP/1.1
Host: www.example.com
[其他 HTTP 头]
Cookie: SessionID=ADMINISTRATOR_USER_SESSION
EventID=1000001
有效响应:
HTTP/1.1 200 OK
[其他 HTTP 头]
{"message": "Event was deleted"}
攻击者可能会尝试执行相同的请求:
POST /account/deleteEvent HTTP/1.1
Host: www.example.com
[其他 HTTP 头]
Cookie: SessionID=CUSTOMER_USER_SESSION
EventID=1000002
如果攻击者的请求响应包含相同的数据 {"message": "Event was deleted"}
,则该应用程序存在漏洞。
管理员页面访问
假设管理员菜单是管理员账户的一部分。
如果除管理员之外的任何角色都可以访问管理员菜单,则该应用程序将被视为存在漏洞。有时,开发人员仅在 GUI 级别执行授权验证,而不对功能进行授权验证,从而可能导致漏洞。
URL 遍历
尝试遍历网站,检查是否有某些页面可能缺少授权检查。
例如:
/../.././userInfo.html
白盒测试
如果 URL 授权检查仅通过部分 URL 匹配完成,那么测试人员或黑客很可能可以通过 URL 编码技术绕过授权。
例如:
startswith(), endswith(), contains(), indexOf()
参考资料
白皮书
工具
不安全直接对象引用测试
ID |
---|
WSTG - ATHZ - 04 |
概述
不安全直接对象引用(Insecure Direct Object References,IDOR)是指应用程序根据用户提供的输入直接访问对象。由于此漏洞,攻击者可以绕过授权并直接访问系统中的资源,例如数据库记录或文件。
不安全直接对象引用允许攻击者通过修改用于直接指向对象的参数值来绕过授权并直接访问资源。这些资源可以是属于其他用户的数据库条目、系统中的文件等等。这是因为应用程序接受用户提供的输入并使用它来检索对象,而没有进行足够的授权检查。
测试目标
- 识别可能出现对象引用的位置。
- 评估访问控制措施是否易受 IDOR 攻击。
测试方法
要测试此漏洞,测试人员首先需要找出应用程序中所有直接使用用户输入来引用对象的位置。例如,使用用户输入来访问数据库行、文件、应用程序页面等的位置。接下来,测试人员应修改用于引用对象的参数值,并评估是否可以检索属于其他用户的对象或以其他方式绕过授权。
测试直接对象引用的最佳方法是至少有两个(通常更多)用户,以涵盖不同的自有对象和功能。例如,两个用户分别可以访问不同的对象(如购买信息、私人消息等),并且(如果适用)具有不同权限的用户(例如管理员用户),以查看是否存在对应用程序功能的直接引用。通过多个用户,测试人员可以节省宝贵的测试时间,无需猜测不同的对象名称,因为他可以尝试访问属于其他用户的对象。
以下是此漏洞的几种典型场景以及针对每种场景的测试方法:
参数值直接用于检索数据库记录
示例请求:
https://foo.bar/somepage?invoice=12345
在这种情况下,invoice 参数的值被用作数据库中发票表的索引。应用程序获取此参数的值并将其用于数据库查询。然后,应用程序将发票信息返回给用户。
由于 invoice 的值直接进入查询,通过修改该参数的值,可以检索任何发票对象,而无论该发票属于哪个用户。为了测试这种情况,测试人员应获取属于不同测试用户的发票标识符(确保根据应用程序业务逻辑他不应查看此信息),然后检查是否可以未经授权访问对象。
参数值直接用于在系统中执行操作
示例请求:
https://foo.bar/changepassword?user=someuser
在这种情况下,user
参数的值用于告诉应用程序应该为哪个用户更改密码。在许多情况下,此步骤将是向导或多步骤操作的一部分。在第一步中,应用程序将收到一个请求,说明要更改哪个用户的密码,在下一步中,用户将提供新密码(无需提供当前密码)。
user
参数用于直接引用要执行密码更改操作的用户对象。为了测试这种情况,测试人员应尝试提供一个与当前登录用户不同的测试用户名,并检查是否可以修改其他用户的密码。
参数值直接用于检索文件系统资源
示例请求:
https://foo.bar/showImage?img=img00011
在这种情况下,img
参数的值用于告诉应用程序用户想要检索哪个文件。通过提供不同文件的名称或标识符(例如 img = image00012.jpg),攻击者将能够检索属于其他用户的对象。
为了测试这种情况,测试人员应获取一个用户不应能够访问的引用,并尝试将其用作 img
参数的值来访问该文件。注意:此漏洞通常与目录/路径遍历漏洞一起被利用(请参阅[路径遍历测试](01 - Testing_Directory_Traversal_File_Include.md))。
参数值直接用于访问应用程序功能
示例请求:
https://foo.bar/accessPage?menuitem=12
在这种情况下,menuitem
参数的值用于告诉应用程序用户试图访问哪个菜单项(以及因此哪个应用程序功能)。假设用户应该受到限制,因此只有访问菜单项 1、2 和 3 的链接可用。通过修改 menuitem
参数的值,可以绕过授权并访问额外的应用程序功能。为了测试这种情况,测试人员应识别应用程序功能由菜单项引用确定的位置,映射给定测试用户可以访问的菜单项的值,然后尝试其他菜单项。
在上述示例中,修改单个参数就足够了。但是,有时对象引用可能会分散在多个参数之间,测试应相应地进行调整。
参考资料
OAuth 漏洞测试
ID |
---|
WSTG - ATHZ - 05 |
概述
OAuth 2.0(以下简称 OAuth)是一个授权框架,它允许客户端代表用户访问资源。
为了实现这一点,OAuth 严重依赖令牌在不同实体之间进行通信,每个实体都有不同的角色:
- 资源所有者:授予资源访问权限的实体,通常就是用户本身。
- 客户端:代表资源所有者请求访问资源的应用程序。这些客户端有两种类型:
- 公共客户端:无法保护机密信息的客户端(例如,以前端为主的应用程序,如单页应用程序、移动应用程序等)。
- 机密客户端:能够通过安全保存其注册的机密信息与授权服务器进行安全认证的客户端(例如,后端服务)。
- 授权服务器:保存授权信息并授予访问权限的服务器。
- 资源服务器:提供客户端访问内容的应用程序。
由于 OAuth 的职责是由资源所有者将访问权限委托给客户端,因此它成为攻击者极具吸引力的目标,而糟糕的实现会导致用户资源和信息被未经授权访问。
为了向客户端应用程序提供访问权限,OAuth 依赖于几种授权授予类型来生成访问令牌:
- 授权码:由机密客户端和公共客户端用于将授权码交换为访问令牌,但仅建议用于机密客户端。
- 基于授权码的 PKCE 扩展:PKCE 建立在授权码授予的基础之上,为公共客户端使用授权码授予提供了更强的安全性,并改善了机密客户端的安全状况。
- 客户端凭证:用于机器对机器的通信,这里的“用户”是从资源服务器请求访问其自身资源的机器。
- 设备码:用于输入能力有限的设备。
- 刷新令牌:授权服务器提供的令牌,允许客户端在用户的访问令牌无效或过期后刷新它们。此授予类型与其他一种授予类型结合使用。
在 OAuth 2.1 版本中,两种流程将被弃用,不建议使用:
- 隐式流程*:PKCE 的安全实现使此流程过时。在 PKCE 之前,隐式流程被客户端应用程序(如[单页应用程序](https://en.wikipedia.org/wiki/Single - page_application))使用,因为 [CORS](https://developer.mozilla.org/en - US/docs/Web/HTTP/CORS) 放宽了站点间通信的[同源策略](https://developer.mozilla.org/en - US/docs/Web/Security/Same - origin_policy)。有关为什么不建议使用隐式授予的更多信息,请查看此[部分](https://datatracker.ietf.org/doc/html/draft - ietf - oauth - security - topics#section - 2.1.2)。
- 资源所有者密码凭证:用于直接与客户端交换用户的凭证,然后客户端将其发送到授权服务器以交换访问令牌。有关为什么不建议使用此流程的信息,请查看此[部分](https://datatracker.ietf.org/doc/html/draft - ietf - oauth - security - topics#section - 2.4)。
*:仅 OAuth 中的隐式流程已被弃用,但在 Open ID Connect (OIDC) 中,它仍然是检索 id_tokens
的可行解决方案。请务必了解隐式流程的使用方式,如果仅使用 /authorization
端点来获取访问令牌,而不依赖 /token
端点,则可以识别其使用方式。有关此方面的示例,请参见[此处](https://auth0.com/docs/get - started/authentication - and - authorization - flow/implicit - flow - with - form - post)。
请注意,OAuth 流程是一个复杂的主题,以上仅包含关键领域的摘要。内联引用包含有关特定流程的更多信息。
测试目标
- 确定 OAuth 2 实现是否存在漏洞,或者是否使用了已弃用或自定义的实现。
测试方法
测试已弃用的授予类型
已弃用的授予类型由于安全和功能原因而被淘汰。识别它们是否被使用可以让我们快速审查它们是否容易受到与其使用相关的任何威胁。有些可能不在攻击者的范围内,例如客户端可能使用用户凭证的方式。应记录这些情况并向内部工程团队报告。
对于公共客户端,通常可以在对 /token
端点的请求中识别授予类型。在令牌交换中,它通过参数 grant_type
来指示。
以下示例展示了带有 PKCE 的授权码授予:
POST /oauth/token HTTP/1.1
Host: as.example.com
[...]
{
"client_id":"example-client",
"code_verifier":"example",
"grant_type":"authorization_code",
"code":"example",
"redirect_uri":"https://client.example.com"
}
grant_type
参数的值及其表示的授予类型如下:
password
:表示资源所有者密码凭证(ROPC)授予。client_credentials
:表示客户端凭证授予。authorization_code
:表示授权码授予。
隐式流程类型不由 grant_type
参数指示,因为令牌会在对 /authorization
端点请求的响应中呈现,而是可以通过 response_type
来识别。以下是一个示例:
GET /authorize
?client_id=<some_client_id>
&response_type=token
&redirect_uri=https%3A%2F%2Fclient.example.com%2F
&scope=openid%20profile%20email
&state=<random_state>
以下 URL 参数指示正在使用的 OAuth 流程:
response_type=token
:表示隐式流程,因为客户端直接请求授权服务器返回令牌。response_type=code
:表示授权码流程,因为客户端请求授权服务器返回一个代码,随后该代码将被交换为令牌。code_challenge=sha256(xyz)
:表示 PKCE 扩展,因为没有其他流程使用此参数。
以下是带有 PKCE 的授权码流程的示例授权请求:
GET /authorize
?redirect_uri=https%3A%2F%2Fclient.example.com%2F
&client_id=<some_client_id>
&scope=openid%20profile%20email
&response_type=code
&response_mode=query
&state=<random_state>
&nonce=<random_nonce>
&code_challenge=<random_code_challenge>
&code_challenge_method=S256 HTTP/1.1
Host: as.example.com
[...]
公共客户端
建议公共客户端使用带有 PKCE 扩展的授权码授予。带有 PKCE 的授权码流程的授权请求应包含 response_type=code
和 code_challenge=sha256(xyz)
。
令牌交换应包含授予类型 authorization_code
和 code_verifier
。
公共客户端不适合的授予类型包括:
- 不带有 PKCE 扩展的授权码授予
- 客户端凭证
- 隐式流程
- 资源所有者密码凭证(ROPC)
机密客户端
建议机密客户端使用授权码授予。也可以使用 PKCE 扩展。
机密客户端不适合的授予类型包括:
- 客户端凭证(机器对机器通信除外,见下文)
- 隐式流程
- 资源所有者密码凭证(ROPC)
机器对机器通信
在没有用户交互且客户端仅为机密客户端的情况下,可以使用客户端凭证授予。
如果知道 client_id
和 client_secret
,可以通过传递 client_credentials
授予类型来获取令牌。
$ curl --request POST \
--url https://as.example.com/oauth/token \
--header 'content-type: application/json' \
--data '{"client_id":"<some_client_id>","client_secret":"<some_client_secret>","grant_type":"client_credentials"}' --proxy https://localhost:8080/ -k
凭证泄露
根据流程的不同,OAuth 会在 URL 参数中传输几种类型的凭证。
以下令牌可被视为泄露的凭证:
- 访问令牌
- 刷新令牌
- 授权码
- PKCE 代码挑战/代码验证器
由于 OAuth 的工作方式,授权 code
以及 code_challenge
和 code_verifier
可能是 URL 的一部分。如果 response_mode
未设置为 [form_post
](https://openid.net/specs/oauth - v2 - form - post - response - mode - 1_0.html),隐式流程会将授权令牌作为 URL 的一部分进行传输。由于这些参数在查询字符串或片段中传递,这可能会导致所请求的令牌或代码在引用头、日志文件和代理中泄露。
隐式流程泄露令牌所带来的风险远高于泄露 code
或任何其他 code_*
参数,因为这些参数与特定客户端绑定,在泄露的情况下更难被滥用。
为了测试这种情况,可以使用诸如 ZAP 之类的 HTTP 拦截代理来拦截 OAuth 流量。
- 逐步完成授权过程,识别 URL 中存在的任何凭证。
- 如果参与 OAuth 流程的页面中包含任何外部资源,分析对它们的请求。凭证可能会在引用头中泄露。
在逐步完成 OAuth 流程并使用应用程序后,HTTP 拦截代理的请求历史记录中会捕获一些请求。在请求历史记录中搜索包含授权服务器和客户端 URL 的 HTTP 引用头(例如 Referer: https://idp.example.com/
)。
查看 HTML 元标签(尽管并非所有浏览器都[支持](https://caniuse.com/mdn - html_elements_meta_name_referrer)此标签)或 [Referrer - Policy](https://developer.mozilla.org/en - US/docs/Web/HTTP/Headers/Referrer - Policy) 可以帮助评估是否通过引用头发生了任何凭证泄露。
相关测试用例
- [JSON Web 令牌测试](…/06 - Session_Management_Testing/10 - Testing_JSON_Web_Tokens.md)
修复建议
- 实施 OAuth 时,始终考虑所使用的技术,以及应用程序是可以避免泄露机密信息的服务器端应用程序,还是无法做到这一点的客户端应用程序。
- 在几乎所有情况下,都使用带有 PKCE 的授权码流程。机器对机器的流程可能是一个例外。
- 使用 POST 参数或头值来传输机密信息。
- 当没有其他可能性时(例如,在无法迁移的遗留应用程序中),实施额外的安全头,如
Referrer - Policy
。
工具
参考资料
- 使用 OAuth 2.0 进行用户认证
- OAuth 2.0 授权框架
- OAuth 2.0 授权框架:Bearer 令牌使用
- OAuth 2.0 威胁模型和安全考虑
- OAuth 2.0 安全最佳实践
- 带有 PKCE 的授权码流程
测试OAuth授权服务器漏洞
概述
OAuth在授权服务器(AS)中存储用户身份及其相应的访问权限。在OAuth流程中,授权服务器起着至关重要的作用,因为它会授予客户端访问资源的权限。为了能够安全地完成这一过程,授权服务器必须对OAuth流程中的参数进行正确验证。
若未能对参数进行验证,可能会导致账户被接管、未经授权的资源访问以及权限提升等问题。
测试目标
- 识别授权服务器中的漏洞。
测试方法
为了测试授权服务器的漏洞,你需要实现以下目标:
- 获取用于授权的凭证。
- 通过强制浏览的方式获取对任意资源的访问权限。
- 绕过授权验证。
测试重定向URI验证不足的问题
如果redirect_uri
参数未得到正确验证,攻击者可以构造一个包含指向其控制服务器的URL链接。这样一来,攻击者就可以诱使授权服务器将授权码发送到他们的服务器上。在下面的示例中,client.evil.com
就是被伪造的redirect_uri
:
https://as.example.com/authorize?client_id=example-client&redirect_uri=http%3A%2F%client.evil.com%2F&state=example&response_mode=fragment&response_type=code&scope=openid&nonce=example
如果用户在用户代理中打开这个链接,授权服务器会将用户代理重定向到恶意URL。攻击者可以捕获伪造URL中传递的code
值,然后将其提交到授权服务器的令牌端点。
以下请求展示了一个将redirect_uri
发送到授权服务器的授权请求。客户端client.example.com
向授权服务器as.example.com
发送授权请求,其中redirect_uri
经过了URL编码,值为http%3A%2F%2Fclient.example.com%2F
:
GET /authorize
?redirect_uri=http%3A%2F%2Fclient.example.com%2F
&client_id=example-client
&errorPath=%2Ferror
&scope=openid%20profile%20email
&response_type=code
&response_mode=query
&state=example
&nonce=example
&code_challenge=example
&code_challenge_method=S256 HTTP/1.1
Host: as.example.com
授权服务器会以包含授权码的重定向响应。在令牌请求中,这个授权码可以用来交换访问令牌。如下所示,Location
头中的URL就是之前redirect_uri
参数中指定的URI:
HTTP/1.1 302 Found
Date: Mon, 18 Oct 2021 20:46:44 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 340
Location: https://client.example.com/?code=example&state=example
要测试授权服务器是否存在重定向URI验证不足的漏洞,可以使用像ZAP这样的HTTP拦截代理来捕获流量:
- 启动OAuth流程,并在授权请求处暂停。
- 修改
redirect_uri
的值,并观察响应。 - 分析响应,判断授权服务器是否接受了任意的
redirect_uri
参数。
如果授权服务器将用户代理重定向到你指定的redirect_uri
,则说明授权服务器没有正确验证redirect_uri
。
此外,你还可以参考测试服务器端请求伪造中的“常见过滤绕过”部分,以识别重定向URI验证的常见绕过方法。
测试授权码注入漏洞
在授权码流程的代码交换过程中,授权服务器会向客户端颁发一个代码,随后客户端会将该代码提交到令牌端点,以换取授权令牌和刷新令牌。
针对授权服务器进行以下测试:
- 发送一个针对其他
client_id
的有效代码。 - 发送一个针对其他资源所有者的有效代码。
- 发送一个针对其他
redirect_uri
的有效代码。 - 多次重发同一个代码(代码重放)。
测试公共客户端
发送到令牌端点的请求中包含授权码,该代码会被用于交换令牌。使用像ZAP这样的HTTP拦截代理捕获这个请求,并重新发送修改后的请求:
POST /oauth/token HTTP/1.1
Host: as.example.com
[...]
{
"errorPath":"/error",
"client_id":"example-client",
"code":"INJECT_CODE_HERE",
"grant_type":"authorization_code",
"redirect_uri":"https://client.example.com"
}
如果授权服务器返回了access_token
,则说明代码注入成功。
测试机密客户端
由于机密客户端的OAuth流程还受到客户端密钥的保护,因此不能直接将授权码提交到令牌端点。相反,需要将授权码注入到客户端中。注入的代码会由机密客户端连同客户端密钥一起包含在令牌请求中发送。
首先,从授权服务器捕获一个授权码:
- 使用用户Alice启动授权码流程。当从授权服务器收到代码时暂停。
- 不要将代码提交给客户端,记录下代码和相应的状态。
然后,注入代码:
- 使用用户Mallory启动授权码流程,并将之前为用户Alice收集的代码和状态值注入到该流程中。
- 如果攻击成功,客户端现在应该拥有一个
authorization_token
,该令牌可以授予对用户Alice所拥有资源的访问权限。
GET /callback?code=INJECT_CODE_HERE&state=example HTTP/1.1
Host: client.example.com
[...]
测试PKCE降级攻击
在某些情况下,PKCE扩展可能会从授权码流程中被移除。这可能会使公共客户端容易受到PKCE扩展原本可以缓解的攻击。
这种情况可能发生在以下情况:
- 授权服务器不支持PKCE。
- 授权服务器没有正确验证PKCE。
可以使用像ZAP这样的HTTP拦截代理对这两种情况进行测试。进行以下测试:
- 发送不包含
code_challenge=sha256(xyz)
和code_challenge_method
参数的授权请求。 - 发送
code_challenge=sha256(xyz)
参数值为空的授权请求。 - 发送
code_challenge=sha256(xyz)
参数值为伪造值的授权请求。
以下示例突出显示了需要修改的值:
GET /authorize
?redirect_uri=http%3A%2F%client.example.com
&client_id=example-client
&errorPath=%2Ferror
&scope=openid%20profile%20email
&response_type=code
&response_mode=web_message
&state=example-state
&nonce=example-nonce
&code_challenge=MODIFY_OR_OMIT_THIS
&code_challenge_method=MODIFY_OR_OMIT_THIS
&prompt=none HTTP/1.1
Host: as.example.com
[...]
授权服务器应该在令牌交换过程中验证code_verifier
值。进行以下测试:
- 发送不包含
code_verifier
的令牌请求。 - 发送
code_verifier
为空的令牌请求。 - 发送包含针对不同授权码的有效
code_verifier
的令牌请求。
POST /oauth/token HTTP/1.1
Host: as.example.com
[...]
{
"client_id":"example-client",
"code_verifier":"MODIFY_OR_OMIT_THIS",
"code":"example",
"grant_type":"authorization_code",
"redirect_uri":"https://client.example.com"
}
测试同意页面跨站请求伪造(CSRF)
CSRF攻击在CSRF中有详细描述。OAuth也可能受到CSRF攻击。
为了防止OAuth中的CSRF攻击,会利用state
参数作为反CSRF令牌。
其他措施也可以防止CSRF攻击。PKCE流程可以缓解CSRF攻击。nonce
值也可以作为反CSRF令牌。
根据CSRF测试用例中描述的测试方法,对包含OAuth使用的任何反CSRF参数的每个请求进行测试。
同意页面会显示给用户,以验证用户是否同意客户端代表其访问资源。对同意页面进行CSRF攻击可能会使任意客户端代表用户访问资源。该流程的步骤如下:
- 客户端生成一个
state
参数,并将其与同意请求一起发送。 - 用户代理显示同意页面。
- 资源所有者授予客户端访问权限。
- 同意信息连同已确认的范围一起发送到授权服务器。
使用像ZAP这样的HTTP拦截代理来测试state
参数是否得到了正确验证。
POST /u/consent?state=Tampered_State HTTP/1.1
Host: as.example.com
[...]
state=MODIFY_OR_OMIT_THIS
&audience=https%3A%2F%2Fas.example.com%2Fuserinfo
&scope%5B%5D=profile
&scope%5B%5D=email
&action=accept
测试点击劫持漏洞
点击劫持在测试点击劫持中有详细描述。如果同意页面容易受到点击劫持攻击,并且攻击者拥有client_id
(对于公共客户端)或客户端密钥(对于机密客户端),攻击者就可以伪造用户的同意,并通过恶意客户端获取对请求资源的访问权限。
测试方法
为了使这种攻击成功,攻击者需要将授权页面加载到一个<iframe>
中。
可以使用以下HTML页面将授权页面加载到<iframe>
中:
<html>
<head>
<title>点击劫持测试页面</title>
</head>
<body>
<iframe src="https://as.example.com/auth/realms/example/login-actions/required-action?execution=OAUTH_GRANT&client_id=example-client" width="500" height="500"></iframe>
</body>
</html>
如果页面成功加载,则说明该网站容易受到点击劫持攻击。
有关如何进行此类攻击的详细描述,请参阅测试点击劫持。
测试令牌有效期
OAuth有两种类型的令牌:访问令牌和刷新令牌。访问令牌的有效期应该受到限制,即它是短期有效的。合适的有效期取决于应用程序,通常为5到15分钟。
刷新令牌的有效期应该更长。它应该是一次性使用的令牌,每次使用后都会被替换。
测试访问令牌有效期验证
当JSON Web Token(JWT)用作访问令牌时,可以从解码后的JWT中获取访问令牌的有效期。这在[测试JSON Web令牌](…/06-会话管理测试/10-测试JSON Web令牌.md)中有详细描述。授权服务器可能没有正确验证JWT的有效期。
要测试访问令牌的有效期,可以使用像ZAP这样的HTTP拦截代理。拦截包含访问令牌的端点请求,并将该请求放入请求重复器中,等待目标时间过去。根据资源的敏感程度,访问令牌的有效期应该在5到15分钟之间。
此类请求可能如下所示。令牌也可以通过其他方式传输,例如在Cookie中。
GET /userinfo HTTP/1.1
Host: as.example.com
[...]
Authorization: Bearer eyJhbGciOiJkaXIiL[...]
通过在不同的时间间隔后发送请求来测试有效期验证,例如在5分钟、10分钟和30分钟后。
可以通过自动化这些步骤并记录服务器响应来优化此过程。当收到HTTP状态码403(而不是HTTP状态码200)的响应时,这可能表明访问令牌已不再有效。
测试刷新令牌有效期验证
刷新令牌的有效期比访问令牌长。由于其有效期较长,在用于交换访问令牌后,应该将其失效。
刷新令牌是在向客户端发放访问令牌的同一个令牌请求中颁发的。
使用像ZAP这样的HTTP拦截代理进行测试。按照以下步骤设置测试:
- 获取一个有效的刷新令牌。
- 捕获用于将刷新令牌交换为新访问令牌的请求。
- 将捕获的请求发送到请求重复器。
在以下示例中,刷新令牌作为POST请求的主体部分发送:
POST /token HTTP/1.1
Host: as.example.com
Cookie: [...]
[...]
grant_type=refresh_token
&refresh_token=eyJhbGciOiJIUz[...]
&client_id=example-client
进行以下测试:
- 发送刷新令牌,判断授权服务器(AS)是否会发放访问令牌。
- 使用相同的刷新令牌重复上述步骤,评估单个刷新令牌能被接受的次数。
当使用 JSON Web 令牌(JWT)作为刷新令牌时,可以从解码后的 JWT 中获取刷新令牌的有效期。这在[测试 JSON Web 令牌](…/06-会话管理测试/10-测试JSON Web 令牌.md)中有详细描述。刷新令牌的有效期可能较长,但应该有一个过期日期。
通过令牌失窃检测机制可以增强安全性。如果刷新令牌在其有效期(或生命周期)之外被用于令牌交换,授权服务器会使所有刷新令牌失效。要测试此机制:
- 发送刷新令牌,判断授权服务器是否会发放访问令牌。
- 使用相同的刷新令牌重复上述步骤,直到该令牌失效。
- 使用最后一次令牌响应中的刷新令牌。
如果为该资源所有者发放给客户端的所有刷新令牌都被失效,说明授权服务器具备令牌失窃检测功能。
相关测试用例
- 测试跨站请求伪造
- 测试客户端 URL 重定向
- 测试服务器端请求伪造
- [测试 JSON Web 令牌](…/06-会话管理测试/10-测试JSON Web 令牌.md)
- 测试点击劫持
- 测试跨源资源共享
修复建议
大多数针对 OAuth 授权服务器的攻击可以通过在授权码和令牌交换过程中验证参数的存在性和内容来缓解。
限制授权码和刷新令牌等凭证的使用时间范围和允许使用次数。这可以缓解某些类型的攻击,并且如果攻击者获取了这些凭证,也能限制其使用。
正确配置诸如跨源资源共享(CORS)、反跨站请求伪造(CSRF)令牌和反点击劫持头部等安全缓解措施,可以减轻或限制攻击的影响。
- 始终验证所有参数是否存在,并验证其值。
- 使用 PKCE 扩展来正确保护授权码和令牌交换。
- 不允许安全功能(如 PKCE 扩展)出现回退情况。
- 限制凭证的有效期。
- 尽可能让凭证仅使用一次,例如授权码。
- 配置可用的安全缓解措施,如 CORS、反 CSRF 令牌和反点击劫持头部。
工具
参考资料
- 使用 OAuth 2.0 进行用户认证
- OAuth 2.0 授权框架
- OAuth 2.0 授权框架:承载令牌的使用
- OAuth 2.0 威胁模型和安全考虑
- OAuth 2.0 安全最佳实践
- 使用 PKCE 的授权码流程
测试OAuth客户端漏洞
概述
OAuth允许客户端获得资源的访问权限,从而代表资源所有者执行操作。客户端在令牌交换过程中接收授权码和刷新令牌,并将它们存储起来。
如果未能保护好令牌交换过程和凭证,可能会导致未经授权的资源访问和权限提升。
测试目标
- 识别OAuth客户端中的漏洞。
测试方法
为了测试客户端的漏洞,你需要完成以下操作:
- 获取用于授权的凭证。
- 通过强制浏览的方式获取对任意资源的访问权限。
- 绕过授权机制。
测试客户端密钥暴露情况
客户端密钥用于向授权服务器(AS)验证客户端的身份,以证明该客户端是受信任的来源。
公开客户端通常无法安全地存储客户端密钥。
为了在客户端代码中识别客户端密钥,需要对客户端代码进行侦察:
- 打开应用程序。
- 打开浏览器的开发者工具。
- 导航到“调试器”选项卡。
- 按下
Ctrl + Shift + F
打开搜索功能。 - 搜索类似于
client - secret
的关键词,查看是否能找到相关内容。
如果上述方法不成功,你还可以:
- 使用像ZAP这样的HTTP拦截代理逐步执行授权过程。
- 从URI的
client - secret
参数中获取客户端密钥。 - 用客户端密钥的值替换上述搜索中的关键词,查看该密钥是否暴露。
测试令牌存储不当问题
客户端接收访问令牌,并理想情况下应将其存储在能够防止攻击者访问的位置。
机密客户端应将令牌存储在易失性内存中,以防止通过其他攻击(如本地文件包含、能够访问环境的攻击者或SQL注入攻击)来获取令牌。
像单页应用程序这样的公开客户端无法安全地存储令牌。例如,跨站脚本攻击可以让攻击者访问存储在浏览器中的凭证。
公开客户端可以将令牌存储在浏览器的会话存储或cookie中,但不能存储在本地存储中。要确定令牌是否存储不当,可以:
- 打开应用程序。
- 获取一个访问令牌。
- 打开浏览器的开发者工具。
- 导航到“应用程序”选项卡。
- 找到“本地存储”并查看存储的数据。
- 找到“会话存储”并查看存储的数据。
- 找到“cookie存储”并查看存储的数据。
测试访问令牌注入攻击
只有当客户端使用直接向客户端颁发访问令牌的响应类型时,才可能发生这种攻击。这种情况发生在隐式流、资源所有者密码凭证和机器对机器流等授权类型中。更多详细信息请参阅[测试OAuth漏洞](05 - Testing_for_OAuth_Weaknesses.md)。
当访问令牌泄露给攻击者,并且攻击者使用该令牌向合法客户端进行身份验证时,访问令牌注入攻击就会成功。
要测试访问令牌注入攻击,请按照以下步骤操作。在这个例子中,授权令牌(ZXhhbXBsZQo=
)已被泄露。
- 拦截客户端和授权服务器之间的流量。
- 使用隐式流授权类型启动一个OAuth流程。
- 注入被盗的访问令牌:
- 向客户端发送一个包含被盗访问令牌(
ZXhhbXBsZQo=
)的伪造授权响应。 - 拦截一个有效的授权响应,并将其中的访问令牌(
dGVzdGluZwo=
)替换为泄露的令牌(ZXhhbXBsZQo=
)。
- 向客户端发送一个包含被盗访问令牌(
图4.5.5.2 - 访问令牌注入流程
相关测试用例
- [测试跨站请求伪造](…/06 - Session_Management_Testing/05 - Testing_for_Cross_Site_Request_Forgery.md)
- [测试客户端URL重定向](…/11 - Client - side_Testing/04 - Testing_for_Client - side_URL_Redirect.md)
- [测试JSON Web令牌](…/06 - Session_Management_Testing/10 - Testing_JSON_Web_Tokens.md)
- [测试点击劫持](…/11 - Client - side_Testing/09 - Testing_for_Clickjacking.md)
- [测试跨源资源共享](…/11 - Client - side_Testing/07 - Testing_Cross_Origin_Resource_Sharing.md)
修复建议
- 只有当客户端有能力安全存储客户端密钥时,才使用客户端密钥。
- 遵循最佳实践来安全存储令牌。像对待其他凭证一样,对它们进行同等的安全考量。
- 避免使用已弃用的OAuth授权类型。更多详细信息请参阅[测试OAuth漏洞](05 - Testing_for_OAuth_Weaknesses.md)。