spring-boot - springboot decode % error 当它在 url 中并且已经被转义
问题描述
版本信息:
服务器版本:Apache Tomcat/9.0.17
服务器构建:2019 年 3 月 13 日 15:55:27 UTC
服务器编号:9.0.17.0
操作系统名称:Windows 8.1
操作系统版本:6.3
架构:amd64
JVM 版本:1.8.0_40-b25
spring-boot-2.1.4
spring-core-5.1.6
我有一个这样的 html 页面: localhost/example/37%.html
(对不起,我不能用 http// 开始 url,因为编辑页面会自动将其更改为链接,并将在 % 后添加 25)
当我访问此 url ,我得到一个错误:HTTP Status 400。
应该是,因为 % 是一个转义字符。
所以我将网址更改为:localhost/example/37%25.html。
这一次,我得到了一个新的错误:
Whitelabel 错误页面
此应用程序没有针对 /error 的显式映射,因此您将其视为后备。
Thu Sep 03 09:25:13 CST 2020
出现意外错误(类型=内部服务器错误,状态=500)。
URLDecoder:转义 (%) 模式中的非法十六进制字符 - 对于输入字符串:“.h”
我检查了tomcat控制台,它输出错误消息:
2020-09-03 09:25:12 [http-nio-8080-exec-3] ERROR
o.s.b.w.s.support.ErrorPageFilter - Forwarding to error page from request [/37%.html] due to exception [URLDecoder: Illegal hex characters in escape (%) pattern - For input string: ".h"]
java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape(%) pattern - For input string: ".h"
at java.net.URLDecoder.decode(URLDecoder.java:194)
at org.springframework.web.servlet.resource.PathResourceResolver.isInvalidEncodedPath(PathResourceResolver.java:285)
at org.springframework.web.servlet.resource.PathResourceResolver.isResourceUnderLocation(PathResourceResolver.java:254)
似乎tomcat(或浏览器)已将%25解码为%,但springboot仍要再次解码%(PathResourceResolver.java)
我不知道这是一个错误问题还是这是 springboot 不允许 % in url 的正确方法
解决方案
我发现了一些有趣的东西。
现在我有两个网页,一个名为 37%.html,另一个名为 37%25.html
按照springboot的逻辑,它会解码%两次,我访问了这个url:
本地主机/示例/37%2525.html
它会显示 37%.html,但是,它会显示 37%25.html。
那么,springboot解码多少次或如何解码%???
然后我在springboot中找到了两个类文件:
ResourceHttpRequestHandler.java
PathResourceResolver.java
它们都有一个名为:isInvalidEncodedPath() 的函数
代码在这里:
ResourceHttpRequestHandler.isInvalidEncodedPath(path)
private boolean isInvalidEncodedPath(String path) {
if(path.contains("%")) {
try {
String decodedPath = URLDecoder.decode(path, "UTF-8");
if(this.isInvalidPath(decodedPath)) {
return true;
}
decodedPath = this.processPath(decodedPath);
if(this.isInvalidPath(decodedPath)) {
return true;
}
} catch (UnsupportedEncodingException | IllegalArgumentException var3) {
;
}
}
return false;
}
PathResourceResolver.isInvalidEncodedPath(resourcePath)
private boolean isInvalidEncodedPath(String resourcePath) {
if(resourcePath.contains("%")) {
try {
String decodedPath = URLDecoder.decode(resourcePath, "UTF-8");
if(decodedPath.contains("../") || decodedPath.contains("..\\")) {
this.logger.warn("Resolved resource path contains encoded \"../\" or \"..\\\": " + resourcePath);
return true;
}
} catch (UnsupportedEncodingException var3) {
;
}
}
return false;
}
看到不一样的东西??他们都做 URLDecoder.decode(resourcePath, "UTF-8"),但捕获不同的异常。
当您访问 url 时,springboot 将按以下顺序调用该函数:
1 ResourceHttpRequestHandler.isInvalidEncodedPath(路径)
2 PathResourceResolver.isInvalidEncodedPath(resourcePath)
所以当点击 /37%25.html 时,在 ResourceHttpRequestHandler.isInvalidEncodedPath(path) 中,它会得到 /37%.html,因为 tomcat(或浏览器)将 %25 解码为 %。然后 URLDecoder.decode("/37%.html", "UTF-8"),触发 IllegalArgumentException,被捕获,但是什么也不做,返回 false。在PathResourceResolver.isInvalidEncodedPath(resourcePath),URLDecoder.decode("/37%.html", "UTF-8")中,触发IllegalArgumentException,没有catced,抛出异常。
当点击 /37%2525.html 时,在 ResourceHttpRequestHandler.isInvalidEncodedPath(path) 中,它得到 /37%25.html, URLDecoder.decode("/37%25.html", "UTF-8"),没问题。在PathResourceResolver.isInvalidEncodedPath(resourcePath),URLDecoder.decode("/37%25.html", "UTF-8"),也没有问题,然后显示37%25.html
如果你只输入 /37%.html,你会得到 400 错误,无效的 URI:isHexDigit。
因此,不幸的是,无法正确访问具有 % char 的 url。
推荐阅读
- laravel - Laravel 刀片中的未定义视图
- javascript - AG-Grid 标题单元格选择
- ios - 在 applicationdidfinishlaunching 中拍摄 ios 启动屏幕的快照
- javascript - 根据 [Slick] 滑块选择加载 div
- javascript - 获得对 CSSMediaRule 的可读访问权限
- parameters - 如何将 alpha(透明度)传递给 seaborn.jointplot?
- java - java.lang.Exception:谁在打电话?通过 PJSUA 拨打电话时
- python - 检查输入时出错:预期 lstm_29_input 的形状为 (None, None, 2) 但得到的数组的形状为 (51, 1, 10)
- dart - Dart 捕获 http 异常
- c# - 在 SaveChangesAsync 之后返回实体是否危险?