Multipart 数据的安全处理
如果注入请求参数时,总是尝试Multipart解析(根据上下文类型识别);并且,如果有人恶意通过Multipart上传一个超大文件。服务进程的内存可能会激增。
1、两种处理策略
如果不触发解析,则不会占用内存。故采用两种策略,“便利”且“按需”处理。
- 自动处理(当 Action 有 UploadedFile 参数时;自动进行解析)
- 显示申明
@Controller
public class DemoController{
//文件上传
@Post
@Mapping("/upload")
public String upload(UploadedFile file) {
return file.name;
}
//通过 multipart 提交的数据,且不带 UploadedFile 参数;须加 multipart 申明
@Post
@Mapping(path="/upload1", multipart=true)
public String upload(String user) {
return user;
}
}
当 ctx.autoMultipart() = true 是(出于便利考虑,默认为 true),会自动解析。出于安全考虑,最好关掉自动处理或者通过路径特径进行控制。(关掉自动处理后,获取 multipart 数据参考上面的做法)
public class DemoApp {
public static void main(String[] args) {
Solon.start(DemoApp.class, args, app -> {
app.filter(-1, (ctx, chain) -> {
if(ctx.path().contains("/upload")) {
//只给需要的路径加 autoMultipart = true
ctx.autoMultipart(true);
}else{
ctx.autoMultipart(false);
}
chain.doFilter(ctx);
});
});
}
}
最好再限制一下上传文件大小
设定最大的上传文件大小
server.request.maxFileSize: 20mb #kb,mb (默认使用 maxBodySize 配置值)
如果文件很大,可以使用临时文件模式节省内存
#设定上传使用临时文件(v2.7.2 后支持)
server.request.useTempfile: true //默认 false
2、顺带,也放一下文件下载的示例:
public class DemoController{
@Mapping("down/f1")
public DownloadedFile down() {
InputStream stream = new ByteArrayInputStream("{code:1}".getBytes(StandardCharsets.UTF_8));
//使用 InputStream 实例化
return new DownloadedFile("text/json", stream, "test.json");
}
@Mapping("down/f2")
public DownloadedFile down12() {
byte[] bytes = "test".getBytes(StandardCharsets.UTF_8);
//使用 byte[] 实例化
return new DownloadedFile("text/json", bytes, "test.txt");
}
@Mapping("down/f3")
public File down2() {
return new File("...");
}
@Mapping("down/f4")
public void down3(Context ctx) throws IOException {
File file = new File("...");
ctx.outputAsFile(file);
}
}