Chapter12-API testing
1.APIs
Application Programming Interfaces,APIs,应用程序编程接口使软件系统和应用程序能够进行通信和共享数据。
API测试很重要,因为API中的漏洞可能破坏网站核心功能的机密性、完整性、可用性。
所有的动态网站都是由API组成的,所以向SQLi这种经典的Web漏洞可以归类为API测试。
1.1 API reconnaissance(API探测)
API测试的第一步,尽可能找出更多的有关API的信息,扩大攻击面。
- 首先,应该识别API端点。这些locations是API在服务器上接收特定资源请求的位置。例如:
这个请求的API端点为 /api/books。这会触发与API的交互,从图书馆检索图书列表。另一个API端点可能是 /api/books/mystery,检索推理书。GET /api/books HTTP/1.1 Host:example.com
- 确定了API端点后,需要分析如何与API交互。这样就能构造有效的HTTP请求来测试API。例如,应该查找如下信息:
- API处理的输入数据,包括强制参数和可选参数
- API接受的请求类型,包括HTTP方法和媒体格式
- 速率限制和身份验证机制。
1.2 API文档
API通常都有文档,以便开发人员知道如何使用和集成它们。
API文档可以是用户可读的形式,也可以是机器可读的形式。
用户可读的文档是为开发人员理解如何使用API而设计的。它可能包括详细的解释、示例和使用场景。
机器可读的文档被设计成由软件处理,以实现API集成和验证等自动化任务。它是用JSON或XML等结构化格式编写的。
API文档通常是公开的,特别是当API打算供外部开发人员使用时。如果是这样,可以从查看文档开始API探测。
- 用户可读文档示例
## 用户登录接口 **URL**: `POST /login` **请求参数**(JSON格式): { "username": "string(必填)", "password": "string(必填)" }
- 机器可读文档示例,由于结构清晰,人类也能轻松理解
paths:/login:post:requestBody:content:application/json:schema:type: objectproperties:username: { type: string }password: { type: string }
1.2.1 发现API文档
即使API文档不是公开可用的,仍然可以通过访问使用该API的Web应用程序来访问它。
查找可能引用API文档的端点,例如
/api/swagger/index.html/openai.json
如果找到了某个资源(如API接口、文件路径等)的访问端点,需要进一步检查其基础路径。
端点:通常指完整URL,用于API接口、静态资源等。
基础路径:端点的公共前缀,通常是某个API版本或服务入口的根路径。
例如,发现了一个资源端点 /api/swagger/v1/users/123,那么应该调查:
/api/swagger/v1/api/swagger/api
可以通过Burpsuite Intruder,以及插件辅助搜索隐藏的API文档或接口。
1.2.2 机器可读的文档
可以使用一系列自动化工具来分析找到的任何机器可读的API文档。
Burpsuite的插件OpenAPI Parser,能够帮助将API解析为可直接利用的URL。
记录的端点,可以用Postman、SoapUI等专门用来测试API端点的工具。
2.API的测试
2.1 识别API端点
即使能直接访问API文档,也建议实际浏览使用该API的Web应用程序(如网页或移动端)来收集更多信息。因为文档可能过时或者不够准确。
在浏览应用程序时,关注URL中的API特征,例如 /api/ 。还要注意JavaScript文件。这些js文件可能包含一些对API端点的引用,而且不能通过web浏览器直接触发。
2.1.1 与API端点交互
一旦确认了API端点,就可以使用Burpsuite的Repeater和Intruder预期交互。这样能够观察API的行为并发现额外的攻击面。例如,可以研究API如何响应变更的HTTP方法和媒体类型。
与API端点交互时,需要仔细检查错误消息和其他响应。有时,这些信息包括可用于构造有效HTTP请求的信息。
2.1.1.1 识别支持的HTTP方法
HTTP方法指定了对资源的操作,例如:
- GET,从资源中检索数据
- PATCH,对资源进行部分修改
- OPTIONS,可以在资源上使用的请求方法的类型
API端点可能支持不同的HTTP方法。因此,在调查API端点时,测试所有可能的方法非常重要。这可能够识别额外的端点功能,从而打开更多的攻击面。
例如:
端点 /api/tasks
GET /api/tasks 检索任务列表
POST /api/tasks 创建新任务
Burpsuite Intruder内置了HTTP vers各种请求方法。
值得一提的是,RFC标准只定义了九种请求方法,但可以通过扩展定义任意方法。但是不具有通用性。HTTP的扩展协议WebDAV也定义了一些方法,但不属于HTTP核心协议。
HTTP方法测试一共以低优先级对象为目标,避免造成以外的后果
2.1.1.2 识别支持的内容类型
API端点通常需要特定格式的数据。因此,根据请求中提供的数据的内容类型,它们的行为可能会有所不同。尝试更改内容类型,可能:
- 触发错误,泄露有用的信息
- 绕过有缺陷的防御
- 利用处理逻辑上的差异。例如,API可能处理JSON是安全的,但处理XML会被攻击。
修改请求包攻击时,也要注意参数类型。
2.1.1.3 找到隐藏的端点
一旦确定了一些起始API端点,就可以使用Inturder来发现隐藏的端点。例如,某个用于更新用户信息的API端点:
PUT /api/user/update
可以使用 Intruder寻找具有相同结构的其他资源。如,将update替换为其它常用函数列表,如delete 和 add等。
寻找隐藏端点时,使用基于常见API命名约定和行业术语的字典。
2.2 发现隐藏参数
在进行API探测时,可能会发现API支持的未记录参数。可以尝试使用它们来更改应用程序的行为。
- 基于初始探测,添加相关行业术语、常用参数名称到列表种,使用Intruder自动搜寻隐藏的参数
- Param miner插件能够在每个请求自动猜测至多65535个参数名。参数挖掘机能够根据来自目标域名的信息,自动猜测与Web应用相关的名称。
- engagement->discover content 能够从可以浏览到的可见内容(包括参数)中发现未链接的内容
2.2.1 API批量赋值漏洞(Mass assignment vulnerabilities)
批量赋值、批量分配(也称为自动绑定)可能会无意中创建隐藏参数。当软件框架自动将请求参数绑定到内部对象的字段时,就会发生这种情况。
因此,自动绑定可能导致应用程序支持开发者从未打赏处理的参数(开发者没有预料到前端传参改变了某些参数)。
例如:
POST /api/users HTTP/1.1
Content-Type: application/json{"username": "attacker","email": "attacker@example.com"
}
如果添加了isAdmin:true。开发者未预期的字段,可能导致攻击者获得管理员权限。
2.2.1.1 识别隐藏参数
由于批量赋值从对象字段创建参数,因此通常可以通过手动检查API返回的对象来识别隐藏的参数。
例如:一个修改用户邮箱功能
请求包:
{"username": "wiener","email": "wiener@example.com",
}
响应包:
{"id": 123,"name": "John Doe","email": "john@example.com","isAdmin": "false"
}
这可能说明存在隐藏的参数 id 、 isAdmin与更新的用户名和邮箱参数一起绑定到内部用户对象。
2.2.1.2 测试自动绑定漏洞
判断是否可以成功修改isAdmin的值,可以尝试发送两个PATCH(假设支持该方法)请求:
isAdmin有效参数值:
{"username": "wiener","email": "wiener@example.com","isAdmin": false,
}
无效参数值:
{"username": "wiener","email": "wiener@example.com","isAdmin": "foo",
}
如果应用程序的行为不同,这可能表明无效值会影响查询逻辑,但有效值不会。这可能表明用户可以成功地更新参数。
然后,可以发送 PATCH 请求,并将 isAdmin 参数值设置为 true ,尝试利用该漏洞。
如果isAdmin参数未经充分的验证和处理就绑定到用户对象,那么用户wiener可能被赋予管理员权限。
- 触发最后一个功能才发现潜在的API泄露,一定要访问网页所有功能。
- 每个参数都有可能存在漏洞
3.如何防范APIs漏洞
从设计API开始,就考虑安全性,特别的,要确保:
- 如果不打算允许API公开访问,请保护好API文档。
- 确保API文档保持最新,以便合法的测试人员能够完全了解API的攻击面。
- 对允许的HTTP方法使用白名单
- 验证每个请求或响应所期望的内容类型
- 使用通用错误消息来避免泄露可能对攻击者有用的信息
- 对API的所有版本使用保护措施,而不仅仅是当前的生产版本
4.服务端参数污染
有些系统不能从互联网直接访问内部的API。当网站将用户输入嵌入到服务器端请求中,而没有进行适当的编码时,就会发生服务器端参数污染。这意味着攻击者能够操纵或注入参数,导致:
- 覆盖现有参数
- 修改Web应用行为
- 访问未授权的数据
可以测试任何用户输入的任意类型的参数污染。例如,查询参数、表单字段、headers、URL路径参数,都有可能是有漏洞的。
- 这个漏洞有时也被称为HTTP参数污染,但这个术语也用于形容WAF绕过技术。为了区分,这里称呼为服务端参数污染。
- 尽管名称相似,服务端参数污染和服务端原型污染没有联系
4.1 测试查询字符串中的服务器端参数污染
要测试查询字符串中的服务器端参数污染,请放置查询语法字符,如 # , & 和 =
在您的输入,并观察应用程序如何响应。
考虑一个易受攻击的应用程序,它允许根据用户名搜索其他用户。当搜索一个用户 peter 时,的浏览器会发出以下请求:
GET /userSearch?name=peter&back=/home
为了检索用户信息,服务器使用以下请求,查询一个内部API:
GET /users/search?name=peter&publicProfile=true
4.1.1 截断查询字符串(#
,%23)
添加 # 可以尝试截断服务器端请求。可以在 # 字符后添加一个字符串,有助于分析响应,如:
GET /userSearch?name=peter%23foo&back=/home
前端将尝试访问如下URL:
GET /users/search?name=peter#foo&publicProfile=true
必须对#进行URL编码(%23),否则前端应用会将其解析为片段标识符,而不是传递给内部API
查看响应,寻找查询是否被截断的线索。
- 如果响应返回用户 peter ,则服务器端查询可能已被截断。
- 如果返回 Invalid name 错误消息,则应用程序可能将 foo 作为用户名的一部分处理。这表明服务器端请求可能没有被截断。
如果能够截断服务器端请求,那么就不需要将 publicProfile 字段设置为true。可以利用这一点来返回非公共用户配置文件。
4.1.2 注入无效参数(&
,%26)
可以使用url编码的 & 字符来尝试向服务器端请求添加第二个参数。
例如,将查询字符串修改为
GET /userSearch?name=peter%26foo=xyz&back=/home
服务器会发起API请求;
GET /users/search?name=peter&foo=xyz&publicProfile=true
查看响应以获取有关如何解析附加参数的线索。例如,如果响应没有改变,这可能表明参数被成功注入,但被应用程序忽略了。
为了获取更多的信息,需要进一步测试。
4.1.3 注入有效参数(&
,%26)
如果能够修改查询字符串,那么可以尝试向服务器端请求添加第二个有效参数。
有效参数的发现,与API隐藏参数发现相同。尽可能访问多的功能点,查看是否有泄露参数信息。
假设已经确认了 email 参数,可以将其添加到查询字符串中,如:
GET /userSearch?name=peter%26email=foo&back=/home
服务器会向API发出如下的请求:
GET /users/search?name=peter&email=foo&publicProfile=true
查看响应以获取有关如何解析附加参数的线索。
4.1.4 重写现有参数(&
,%26)
要确认应用程序是否容易受到服务器端参数污染的影响,可以尝试覆盖原始参数。通过注入第二个具有相同名称的参数来实现这一点。
例如,可以将查询字符串修改如下:
GET /userSearch?name=peter%26name=carlos&back=/home
服务器会对内部API请求:
GET /users/search?name=peter&name=carlos&publicProfile=true
内部API会解析两个 name 参数。如何响应取决于Web应用如何处理第二个参数。在不同的Web技术中有所不同,如:
- PHP只解析最后一个参数。这将导致用户搜索 carlos 。
- ASP.NET拼接两个参数。这将导致用户搜索 peter,carlos。可能导致 invalid username报错
- Node.js / express 直解析第一个参数。这将导致用户搜索 peter。结果不变
如果能够覆盖原始参数,就可以进行利用。例如,可以加上 name=administrator 到请求。这可能使您能够以管理员用户身份登录。
案例:第一步永远是基准测试,在找回密码接口发现了有隐藏的参数
Step2:尝试注入无效参数,API将其作为独立参数解析,而不是用户名的一部分
Step3:尝试重写现有参数,API只解析第一个用户名
Step4:尝试截断后续字符,报错Filed没有指定。说明截断成功
Step5:指定field,提示无效field。这个报错和无效username是一样的格式,因此推断,field是可以传入的,并且会被解析覆盖默认值。
尝试使用Burpsuite Intruder自带的Server-side variable names爆破。username和email返回200状态码。
Step6:使用email、username替换field,分别返回对应的响应。
Step7:查看API,有个/static/js/forgotPassword.js文件,判断其泄露了部分逻辑。其中出现的参数有username,reset-token。页面跳转href,尝试用reset-token替换field。返回一个token字符串。
Step8:在地址栏中,输入该参数
/forgot-password?reset-token=cjx8pjonurazlimwkpc41kyo9ne0ou68
成功进入页面,修改密码。
API的测试,除了关注api字样的信息,也要当选.js文件泄露信息。
4.2 测试REST paths中的服务端参数污染
RESTful API可以将参数名称和值放在URL路径中,而不是放在查询字符串中。例如:
GET /api/users/123
该URL可以分解为:
- /api,是根API端点(root API endpoint)
- /users,是一个资源,例子中的users
- /123,是一个参数,在这里是特定用户的id
考虑一个根据用户名编辑用户配置文件的应用程序。请求被发送到以下端点:
GET /edit_profile.php?name=peter
这将导致服务器发出请求:
GET /api/private/users/peter
攻击者可能能够操纵服务器端URL路径参数来利用该API。添加路径遍历序列来修改参数并观察应用程序如何响应来测试该漏洞。
例如,提交 peter/…/admin作为 name 参数值
GET /edit_profile.php?name=peter%2f..%2fadmin
可能导致服务器发出如下查询:
GET /api/private/users/peter/../admin
后端API可能将其规范化后,解析/api/private/users/admin
也可以将其看为是API测试中的路径穿越。
案例:
- 研究服务端行为
Step1:基准测试,关注api路径、返回JSON的请求(隐藏参数)、js文件(隐藏参数、隐藏路径)
Step2:注入有效参数、无效参数、重写现有参数、截断,测试是否存在参数污染。结果分别是:(1)注入参数被当作字符串拼接到username
(2)重写参数取第二个解析
(3)截断后,报错Invalid route. Please refer to the API definition。这表明成功截断,可能是缺少参数导致的路径不匹配。
截断成功意味着:服务端将请求参数放入url中进行API查询>Step4:将username参数修改为
administrator?
。同样报错Invalid Route。这表明输入可以放在url路径中,因为 ? 表示查询字符串的开始。同样也可以作为路径或查询字符串的分隔符,等价于路径截断#
Step5:测试路径穿越./ 与../
,第一个结果不变,第二个返回Invalid route,表明请求访问了无效的URL
以上证明了查询字符会被拼接到路径中,并向API发出请求,并且可路径穿越。
-
导航到API definition
Invalid route. Please refer to the API definition。客户端请求的URL路径不符合服务端API的预期规则。
Step6:不断添加..%2f
尝试能否到达API根目录
Step7:在API根目录,尝试访问一些常见API定义文件(API definition),当访问openapi.json时
该端点指示URL路径包含一个field参数 -
漏洞利用
Step8:尝试注入username=administrator%2ffield%2fx%23,提示field只支持email
Step9:username=administrator%2ffield%2femail%23,返回正常响应。
尝试username=administrator%2ffield%2fpasswordResetToken%23。field不支持(passwordResetToken是.js文件泄露的参数)
This version of API不支持,openapi v3不支持,我们尝试回到API root,使用v1版本
Step10:返回API root根目录,将username修改为…/…/v1/users/administrator/field/passwordResetToken%23
Step11:利用.js文件泄露的路径,成功修改密码
以上的分析可以推广到其它漏洞挖掘:
- 分析行为,尝试各种注入点,尝试true、false的响应
- 根据异常行为,分析其逻辑,并尝试获取一些有用的信息。
- 发现端倪后,进行漏洞利用
4.3 测试结构化数据格式中的服务端参数污染
攻击者可能能够操纵参数来利用服务器处理其他结构化数据格式(如JSON或XML)中的漏洞。要对此进行测试,请在用户输入中注入意外的结构化数据,并查看服务器如何响应。
考虑一个允许用户编辑其概要文件的应用程序,然后将其更改与请求一起应用到服务器端API。当编辑你的名字时,你的浏览器会发出以下请求:
POST /myaccountname=peter
这将导致服务器发出如下请求:
PATCH /users/7312/update{"name":"peter"}
可以尝试在请求中添加 access_level参数,如:
POST /myaccountname=peter","access_level":"administrator
如果将用户输入添加到服务器端JSON数据而没有进行充分的验证或清理,则会导致以下服务器端请求:
PATCH /users/7312/update
{name="peter","access_level":"administrator"}
这可能导致用户 peter 被授予管理员访问权限。
这是注入隐藏参数的另一种形式,前提仍然是获取隐藏参数。
考虑一个类似的示例,但其中客户端用户输入是JSON数据。当你编辑你的名字时,你的浏览器会发出以下请求:
POST /myaccount
{"name": "peter"}
服务器请求:
PATCH /users/7312/update
{"name":"peter"}
可以尝试在请求中添加 access_level 参数,如下所示:
POST /myaccount
{"name": "peter\",\"access_level\":\"administrator"}
此时,如果后端对用户输入逻辑是输入->转义->转码
,然后将其添加到JSON数据中。那么可能会导致如下请求:
PATCH /users/7312/update
{name="peter","access_level":"administrator"}
结构化格式注入也可以出现在响应中。
例如,如果用户输入安全地存储在数据库中,然后在没有进行适当编码的情况下从后端API嵌入到JSON响应中。
此时,可能绕过前端校验或XSS漏洞(存储型XSS)。
服务端参数污染可以发生在任何结构化数据格式。XML格式的注入可参考XXE的XInclude部分。
4.4 自动化测试工具
Burp的插件 Backslash Powered Scanner可以扫描服务端注入漏洞。
5.防止服务端参数污染
- 使用白名单定义不需要编码的字符
- 确保所有用户输入在进行服务器请求前正确编码或参数化处理
- 确保所有输入符合预期的格式和结构
总结
-
如何检查API隐藏参数
访问所有功能点,检查API返回的对象 -
API测试关注的点,在HTTP history主要关注:
- .js文件,可能泄露路径信息(路径可能是隐藏的查询参数
客户端提交参数->服务端将其拼接到路径
) - api相关信息,可能会直接泄露api路径
- 返回对象,响应包可能显示隐藏的参数
- .js文件,可能泄露路径信息(路径可能是隐藏的查询参数
-
判断Web网站是否会受到服务端参数污染的影响,可以尝试:
- 截断查询字符串(判断①是否仍有其它隐藏参数;②是否被拼接到查询路径中)
- 注入无效参数(判断是否当作独立参数处理)
- 注入有效参数(能否覆盖原有默认参数)
- 重写现有参数
扩展
Media Formats、MIME Type、Content-Type区别
- 媒体格式,指文件存储或传输时的数据组织方式。包括编码方式、文件结构等,如 .mp3、.png、.pdf等
- MIME类型,是互联网标准,用于标识数据的类型和子类型(告知服务器如何处理接收到的数据)。如image/jpeg、application/octet-stream等
- Content-Type,是HTTP协议头部字段,用于在Web通信中声明数据的MIME类型。
常见MIME类型与其对应的媒体格式
WebDAV: 是一种基于 HTTP/HTTPS 的扩展协议,允许用户通过Web直接远程编辑和管理服务器上的文件(如同本地文件系统)。它最初由 IETF 在 RFC 4918 中标准化,主要用于协作办公、文件共享和版本控制。
特性 | WebDAV | HTTP |
---|---|---|
文件操作 | 支持完整文件操作(增删改查) | 仅支持基础GRUD |
方法 | 新增PROPPATCH、MOVE等方法 | 9种标准方法 |
元数据支持 | 可管理文件属性(如作者、权限) | 无 |
适用场景 | 文件共享、协同编辑 | 网页浏览、API交互 |