Solon v2.7.5

Multipart 数据的安全处理

</> markdown

如果注入请求参数时,总是尝试Multipart解析(根据上下文类型识别);并且,如果有人恶意通过Multipart上传一个超大文件。服务进程的内存可能会激增。

1、几个插件的情况

框架上传文件的情况说明
solon.boot.jlhttp基于内存处理,适合小文件高频上传
solon.boot.jdkhttp基于内存处理,适合小文件高频上传
solon.boot.smarthttp基于内存处理,适合小文件高频上传
solon.boot.jetty基于内存处理,适合小文件高频上传
solon.boot.undertow基于本地硬件的临时文件处理,适合大文件上传中低频上传

2、两种处理策略

如果不触发解析,则不会占用内存。故采用两种策略,“便利”且“按需”处理。

  • 自动处理(当 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 配置值)

3、顺带,也放一下文件下载的示例:

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);
    }
}