反射文件下载(RFD)
简介
反射文件下载(RFD)攻击首次在 Trustwave 2014 年的一篇论文中描述。该攻击类似于 XSS,因为它依赖于输入(例如查询参数、URI 变量)在响应中反射。然而,与在 HTML 中插入 JavaScript 不同,RFD 攻击依赖于浏览器切换到执行下载并根据文件扩展名(例如 .bat, .cmd)将响应视为可执行脚本(如果双击)。RFD,即 Reflected File Download反射型文件下载漏洞,是一个2014年来自BlackHat的漏洞,攻击者可以通过一个URL地址使用户下载一个恶意文件,从而危害用户的终端PC,不过这个漏洞危害上可能接近于self-xss,因为就算浏览器下载了,打开的话也还是需要自己点击打开,并不是自动打开,就比较鸡肋吧,想要利用的难度就比较高
想要实现RFD漏洞,还需要满足如下三个条件
- 输入反射:用户输入被“反射”到响应内容,这个点的话就是说明能够控制文件的内容
- 文件名可控: URL允许并接受用户的其他输入,攻击者将其用于将文件扩展名设置为可执行扩展名,那么后缀名就可以控制,比如sh,bat脚本之类就可以控制运行
- 下载:响应被作为文件里的内容进行下载,这里可以控制Content-Type或者在自己的服务器上创建一个HTML文件,设置download属性,诱导点击下载。
出现形式
在 Spring MVC 中,@ResponseBody 和 ResponseEntity 方法处于风险中,因为它们可以呈现不同的内容类型,客户端可以通过 URL 路径扩展名请求这些内容。然而,请注意,仅禁用后缀模式匹配或禁用用于内容协商的路径扩展名使用不足以防止 RFD 攻击。
防范
为了全面防范 RFD,Spring MVC 在呈现响应体之前添加了 Content-Disposition:inline;filename=f.txt 标头,以建议一个固定且安全的下载文件名。仅当 URL 路径包含一个既不在白名单中也未明确注册用于内容协商的文件扩展名时才会这样做。然而,当 URL 直接输入到浏览器中时,这可能会有副作用。
许多常见的路径扩展名默认情况下被列入白名单。此外,REST API 调用通常不应直接在浏览器中使用。然而,使用自定义 HttpMessageConverter 实现的应用程序可以明确注册文件扩展名用于内容协商,对于这些扩展名将不会添加 Content-Disposition 标头。参见 Section 22.16.6, “Content Negotiation”。
注意 这最初是作为 CVE-2015-5211 的一部分引入的。以下是报告中的其他建议:
- 编码而不是转义 JSON 响应。这也是 OWASP XSS 的建议。有关如何使用 Spring 进行此操作的示例,请参见 spring-jackson-owasp。
- 将后缀模式匹配配置为关闭或限制为仅显式注册的后缀。
- 使用 useJaf 和 ignoreUnknownPathExtensions 属性将内容协商配置为 false,这将导致对于具有未知扩展名的 URL 返回 406 响应。然而,如果 URL 自然地预期在末尾有一个点,这可能不是一个选项。
- 向响应添加 X-Content-Type-Options: nosniff 标头。Spring Security 4 默认执行此操作。
在 Spring MVC 中,@ResponseBody
和 ResponseEntity
方法允许根据请求的 URL 路径扩展名呈现不同的内容类型,这可能会使应用程序面临文件下载欺骗(Reflected File Download,RFD)攻击的风险。以下是一个例子,说明如何通过禁用路径扩展名来防止 RFD 攻击,但仅此操作并不足以完全防止此类攻击。
示例代码
首先,考虑一个简单的控制器,它根据 URL 路径扩展名返回不同的内容类型:
@RestController
public class MyController {
@GetMapping(value = "/file", produces = "application/json")
public ResponseEntity<String> getFileAsJson() {
return ResponseEntity.ok("{\"key\": \"value\"}");
}
@GetMapping(value = "/file", produces = "text/html")
public ResponseEntity<String> getFileAsHtml() {
return ResponseEntity.ok("<html><body><h1>Hello World</h1></body></html>");
}
}
在这个例子中,客户端可以通过请求 /file.json
或 /file.html
来获得不同格式的响应。
禁用路径扩展名
为了禁用路径扩展名匹配,可以在 Spring 配置中进行以下设置:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
}
这段代码禁用了通过路径扩展名进行内容协商。
防止 RFD 攻击的更多措施
虽然禁用路径扩展名可以防止一些类型的 RFD 攻击,但还需要采取其他措施来确保安全:
-
禁用内容协商的路径扩展名:禁用
favorPathExtension
只是一个步骤,确保禁用所有路径扩展名。 -
使用 Content-Disposition 头:确保下载的文件通过设置
Content-Disposition
头来安全处理文件下载。 -
验证输入:严格验证和消毒所有用户输入,包括 URL 路径和查询参数。
使用 Content-Disposition 头
这里是一个更安全的实现,展示了如何使用 Content-Disposition
头:
@RestController
public class SecureController {
@GetMapping("/download")
public ResponseEntity<byte[]> downloadFile() {
byte[] content = "Sample content".getBytes();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", "sample.txt");
return new ResponseEntity<>(content, headers, HttpStatus.OK);
}
}
在这个例子中,/download
端点会返回一个文件下载响应,并且使用 Content-Disposition
头确保内容作为附件下载。
通过这些措施,可以有效降低 RFD 攻击的风险,并确保应用程序的安全性。