AppScan 在 API 安全测试中的实例介绍
在本项目中,API 遵循标准的的 REST 架构和背端服务器进行通信。针对 API 的功能测试由两部分组成:一部分是用一个 Web 的测试页面直接实现的,另一部分,由于 Web 页面的局限性(比如不能任意修改 HTTP header),所以是通过 Shell 脚本调用 curl 实现的。 并且这个 API 的测试环境没有固定的域名和 IP 地址。针对 Web 应用的安全测试采用 AppScan Standard。项目实施过程中面临这样几个问题:
- 针对 Web 页面的非 REST API 测试,AppScan Standard 可以很好的胜任工作,但对于 API 部分,由于浏览器下的页面的 HTTP 请求的局限性,API 测试页面本身的对 API 的覆盖率就不够。所以通过 AppScan 扫描调用 API 的页面,也难以保证覆盖率。
- 系统没有固定的域名或 IP 地址, 导致每次要重新录制和创建测试任务。一个扫描后的 scan 文件内 Starting URL 也是一个只读属性如图 1 所示。
图 1 .导出 Starting URL
在开始介绍解决方法之前,先介绍一下 AppScan 的录制文件。用户通过普通的 Web 程序进行 AppScan 的测试,可以通过 Manual Explorer 录制收集信息。 这样会生成一个 manualExplore_1.exd 的文件在 AppScan 的扫描文件.scan 压缩包里,scan 文件是通过 Deflate 压缩打包的,所以您可以使用一个解压工具查看 scan 文件里的结构和文件。在这里用户可以通过点击菜单栏中的 File-> Export -> Recorded Manual Explore 可以把 manualExplore_1.exd 文件导出,如图 2 所示。
图 2 .导出 manualExplore_1.exd 文件
而当需要时可以通过重新导入这个文件,将之前录制的信息重新导入一个新的 scan 任务。而当测试者要测试某个同样的 Web 实例时,当实例的域名或 IP 各不相同,并且测试者已经对其中一个进行了录制,这样就可以通过简单修改这个 exd 文件然后分别 import 到不同的测试实例中。
这个文件本身是一个 XML 文件,这个文件大体结构,如清单 1。
清单 1 .exd 文件结构
<?xml version="1.0" encoding="utf-16"?> <!--Automatically created by AppScan at 1/16/2014 11:20:26 AM--> <!--Do NOT Edit!--> <requests> <request> ... </request> ... </requests> <!--Number of Requests in file = 100-->
从注释中我们也可以看出,这个文件是 AppScan 自动产生的文件,因此修改时要特别注意,因为错误的修改可能使 AppScan 会无法识别录制的 HTTP 请求,或者错误的识别 HTTP 的请求。最后一行的注释表明里这里记录了多少个 HTTP 的请求。
这些请求会都放在<requests>里,一个 request 的录制信息结构,如清单 2。
清单 2 .request 的录制结构
<request scheme="https" host="www.ibm.com" path="/" port="443" method="GET" SessionRequestType="Login" ordinal="15"> <raw encoding="none"> </raw> <cookie name="JSESSIONID" value="XXX" path="/" domain="www.ibm.com" secure="False" expires="1/1/0001 12:00:00 AM" /> <parameter name="XXX" captureIndex="0" value="" type="QUERY" linkParamType="simplelink" separator="&" operator="=" reportName="XXX" /> <sessionCookies> <cookie name="JSESSIONID" value="XXX path="/" domain="www.ibm.com" secure="False" expires="1/1/0001 12:00:00 AM" /> </sessionCookies> </request>
其中<raw>部分是原始的请求数据,包括 HTTP Header 和 body 部分的全部数据。 而其他的是从这个原始数据中结构化出来的一些数据,熟悉的 HTTP 的应该对这个结构化的数据并不陌生。比如 scheme 是请求的协议,session 是 HTTP header 里的 session 部分,parameter 是 URL 里的参数。在这里 ordinal 是对 request 在这个录制文件内的一个计数。
熟悉了文件的结构我们就可以对其进行修改或添加自己的 HTTP 录制的信息。来提高测试的覆盖率。
下面介绍一下如何解决前面提到的两个问题。
针对问题一,这里举一个简单的例子:现有一个针对数据库查询的请求,有两个参数分别是 parm1 和 parm2,并且已经有对这个 API 的扫描的 exd 文件如下:
清单 3 .已有的录制信息
<request scheme="https" host="www.site1.com" path="/test/API1" port="443" method="POST" SessionRequestType="Login" ordinal="146"> <raw encoding="none">POST /test/API1 HTTP/1.1 Host: www.site1.com User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.7,ja;q=0.3 Connection: keep-alive Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Referer: https://www.site1.com/ Content-Length: 83 Cookie: JSESSIONID=0000F7u3iiCtkF0SIR4G9viBIQr:156f4da9-0cc6-4460-9ac9-f791e0aac903 Pragma: no-cache Cache-Control: no-cache parm1=test1&parm2=test2</raw> <cookie name="JSESSIONID" value="0000F7u3iiCtkF0SIR4G9viBIQr:156f4da9-0cc6-4460-9ac9-f791e0aac903" path="/" domain="www.site1.com" secure="False" expires="1/1/0001 12:00:00 AM" /> <parameter name="parm1" captureIndex="0" value="test1" type="BODY" linkParamType="simplelink" separator="&" operator="=" reportName="parm1" /> <parameter name="parm2" captureIndex="0" value="test2" type="BODY" linkParamType="simplelink" separator="&" operator="=" reportName="parm2" /> <sessionCookies> <cookie name="JSESSIONID" value="0000F7u3iiCtkF0SIR4G9viBIQr:156f4da9-0cc6-4460-9ac9-f791e0aac903" path="/" domain="www.site1.com" secure="False" expires="1/1/0001 12:00:00 AM" /> </sessionCookies> </request>
现在由于接口的更改,其中一个参数的 name 由原来的 parm1 改为新的 newparm。如果按照常规的流程,我们还需要对整个结构的测试页面进行扫描。而其实我们只用改掉文档里相应的部分,将原来的 exd 的参数部分改成如清单 4。
清单 4 .修改后的 exd 文件
<request scheme="https" host="www.site1.com" path="/test/API1" port="443" method="POST" SessionRequestType="Login" ordinal="146"> <raw encoding="none">POST /test/API1 HTTP/1.1 ... Content-Length: 23 newparm=test1&parm2=test2</raw> ... <parameter name="newparm" captureIndex="0" value="test1" type="BODY" linkParamType="simplelink" separator="&" operator="=" reportName="newparm" /> ... </request>
针对第二个问题,使用上面提到的方法,将 exd 文件导出,并修改补充后存档备份。当有新的不同域名或 IP 的任务时,可以通过新建 scan 任务,完成任务配置后,复制一份已经存档的 exd 文件,将文件里所有的域名或 IP 替换成新的域名或 IP 并保存,然后再新建的 scan 文件内导入这个录制文件就可以了。
通过上面的方法,项目的问题很好的得到了解决,即保证了测试覆盖率,又确保了测试灵活性。
回页首
总结
随着 API 的广泛应用,API 安全测试变得越来越重要,本文介绍的 AppScan Standard 在 API 安全测试中的应用方法,是一个简单而有效的方法,可以很好的提高 API 安全测试效率,提高测试覆盖率。