可以看到一方面是QP编码,另一方面也是支持 filename* ,同样获取值是截取 " 之间的或者没找到就直接截取 = 后面的部分
文章插图
如果是 filename* 后面的处理逻辑就是else分之,可以看出和我们上面分析spring4还是有点区别就是这里只支持 UTF-8/ISO-8859-1/US_ASCII ,编码受限制
int idx1 = value.indexOf(39);int idx2 = value.indexOf(39, idx1 + 1);if (idx1 != -1 && idx2 != -1) {charset = Charset.forName(value.substring(0, idx1).trim());Assert.isTrue(StandardCharsets.UTF_8.equals(charset) || StandardCharsets.ISO_8859_1.equals(charset), "Charset should be UTF-8 or ISO-8859-1");filename = decodeFilename(value.substring(idx2 + 1), charset);} else {filename = decodeFilename(value, StandardCharsets.US_ASCII);}
但其实仔细想这个结果是符合RFC文档要求的文章插图
接着我们继续后面会继续执行 decodeFilename
文章插图
代码逻辑很清晰字符串的解码,如果字符串是否在 RFC 5987 文档规定的Header字符就直接调用baos.write写入
attr-char= ALPHA / DIGIT/ "!" / "#" / "$" / "&" / "+" / "-" / "."/ "^" / "_" / "`" / "|" / "~"; token except ( "*" / "'" / "%" )
如果不在要求这一位必须是 % 然后16进制解码后两位,其实就是url解码,简单测试即可文章插图
"双写"绕过来看看核心部分
public static ContentDisposition parse(String contentDisposition) {List<String> parts = tokenize(contentDisposition);String type = (String)parts.get(0);String name = null;String filename = null;Charset charset = null;Long size = null;ZonedDateTime creationDate = null;ZonedDateTime modificationDate = null;ZonedDateTime readDate = null;for(int i = 1; i < parts.size(); ++i) {String part = (String)parts.get(i);int eqIndex = part.indexOf(61);if (eqIndex == -1) {throw new IllegalArgumentException("Invalid content disposition format");}String attribute = part.substring(0, eqIndex);String value = https://www.isolves.com/it/cxkf/yy/JAVA/2022-07-13/part.startsWith(""", eqIndex + 1) && part.endsWith(""") ? part.substring(eqIndex + 2, part.length() - 1) : part.substring(eqIndex + 1);if (attribute.equals("name")) {name = value;} else if (!attribute.equals("filename*")) {//限制了如果为null才能赋值if (attribute.equals("filename") && filename == null) {if (value.startsWith("=?")) {Matcher matcher = BASE64_ENCODED_PATTERN.matcher(value);if (matcher.find()) {String match1 = matcher.group(1);String match2 = matcher.group(2);filename = new String(Base64.getDecoder().decode(match2), Charset.forName(match1));} else {filename = value;}} else {filename = value;}} else if (attribute.equals("size")) {size = Long.parseLong(value);} else if (attribute.equals("creation-date")) {try {creationDate = ZonedDateTime.parse(value, DateTimeFormatter.RFC_1123_DATE_TIME);} catch (DateTimeParseException var20) {}} else if (attribute.equals("modification-date")) {try {modificationDate = ZonedDateTime.parse(value, DateTimeFormatter.RFC_1123_DATE_TIME);} catch (DateTimeParseException var19) {}} else if (attribute.equals("read-date")) {try {readDate = ZonedDateTime.parse(value, DateTimeFormatter.RFC_1123_DATE_TIME);} catch (DateTimeParseException var18) {}}} else {int idx1 = value.indexOf(39);int idx2 = value.indexOf(39, idx1 + 1);if (idx1 != -1 && idx2 != -1) {charset = Charset.forName(value.substring(0, idx1).trim());Assert.isTrue(StandardCharsets.UTF_8.equals(charset) || StandardCharsets.ISO_8859_1.equals(charset), "Charset should be UTF-8 or ISO-8859-1");filename = decodeFilename(value.substring(idx2 + 1), charset);} else {filename = decodeFilename(value, StandardCharsets.US_ASCII);}}}return new ContentDisposition(type, name, filename, charset, size, creationDate, modificationDate, readDate);}
spring5当中又和spring4逻辑有区别,导致我们又可以"双写"绕过(至于为什么我要打引号可以看看我代码中的注释),因此如果我们先传 filename=xxx 再传 filename*=xxx ,由于没有前面提到的 filename == null 的判断,造成可以覆盖 filename 的值文章插图
同样我们全用 filename* 也可以实现双写绕过,和上面一个道理
推荐阅读
- 通过 Java 技术手段,获取女朋友定位地址...
- Java Post请求工具类,非常实用,建议收藏
- QQ|QQ崩了!N多网友反馈文件收发失败 腾讯尚未回应
- 安卓手机如何打开.ttf文件?
- 特朗普下令解密通俄门文件-特朗普通俄门事件是怎么回事
- Office|被曝自动删除用户文件:WPS重申不会侵犯用户隐私
- 删除|WPS会删除本地文件?我亲自帮你们试了试
- Javascript怎样访问Sqlserver数据库
- JAVA中计算两个日期时间的差值竟然也有这么多门道
- Linux 压缩命令