您在这里面临的问题是,对 URL 的不同部分进行编码有不同的规则 - 记住,URL 中有 4 个部分具有不同的编码规则。首先,了解为什么在 Java 中需要使用UriBuilder
班级。网址规格将有助于解决具体细节。
现在问题是整个 URL 作为输入
从用户那里,我不能简单地解析出查询参数并
单独清理它们,因为可以创建恶意输入
组合两个查询参数并单独清理它们
在那种情况下不起作用。
这里唯一真正的选择是java.net.URI
.
尝试这个:
URI dirtyURI = new URI("http://example.com/alpha?abc=def&phil=key%3dbdj");
String cleanURIStr = enc.canonicalize( dirtyURI.getPath() );
致电给URI.getPath()
应该给你一个非百分比编码的 URL,如果enc.canonicalize()
在该阶段之后检测到双编码,那么您确实拥有双编码字符串,并且应该通知调用者您将只接受单编码 URL 字符串。这URI.getPath()
足够聪明,可以对 URL 字符串的每个部分使用解码规则。
如果它仍然给您带来一些麻烦,API参考如果您需要对 URL 的不同部分执行不同的操作,还有其他方法可以提取 URL 的其他部分。例如,如果您需要手动解析 GET 请求上的参数,您实际上可以让它返回查询字符串本身 - 并且它会对其进行解码。
=============JUNIT 测试用例============
package org.owasp.esapi;
import java.net.URI;
import java.net.URISyntaxException;
import org.junit.Test;
public class TestURLValidation {
@Test
public void test() throws URISyntaxException {
Encoder enc = ESAPI.encoder();
String input = "http://example.com/alpha?abc=def&phil=key%3dbdj";
URI dirtyURI = new URI(input);
enc.canonicalize(dirtyURI.getQuery());
}
}
================更新问题的答案======================
没有办法解决这个问题:Encoder.canonicalize()
旨在将转义字符序列减少为简化的、原生的 Java 形式。 URL 很可能被视为特殊情况,因此很可能被故意排除在考虑之外。这是我处理你的情况的方式——没有白名单,它将保证你受到保护Encoder.canonicalize()
.
使用上面的代码获取输入的 URI 表示形式。
第 1 步:规范化所有 URI 部分,除了URI.getQuery()
步骤 2:使用库解析器将查询字符串解析为数据结构。我会使用来自 commons 的 httpclient-4.3.3.jar 和 httpcore-4.3.3.jar 。然后你会做这样的事情:
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.List;
import javax.ws.rs.core.UriBuilder;
import org.apache.http.client.utils.URLEncodedUtils;
import org.junit.Test;
import org.owasp.esapi.ESAPI;
import org.owasp.esapi.Encoder;
public class TestURLValidation
{
@Test
public void test() throws URISyntaxException {
Encoder enc = ESAPI.encoder();
String input = "http://example.com/alpha?abc=def&phil=key%3dbdj";
URI dirtyURI = new URI(input);
UriBuilder uriData = UriBuilder.fromUri(enc.canonicalize(dirtyURI.getScheme()));
uriData.path(enc.canonicalize(enc.canonicalize(dirtyURI.getAuthority() + dirtyURI.getPath())));
println(uriData.build().toString());
List<org.apache.http.NameValuePair> params = URLEncodedUtils.parse(dirtyURI, "UTF-8");
Iterator<org.apache.http.NameValuePair> it = params.iterator();
while(it.hasNext()) {
org.apache.http.NameValuePair nValuePair = it.next();
uriData.queryParam(enc.canonicalize(nValuePair.getName()), enc.canonicalize(nValuePair.getValue()));
}
String canonicalizedUrl = uriData.build().toString();
println(canonicalizedUrl);
}
public static void println(String s) {
System.out.println(s);
}
}
我们在这里真正要做的是使用标准库来解析 inputURL(从而减轻我们的所有负担),然后在解析每个部分后对各个部分进行规范化。
请注意,我列出的代码不适用于allurl 类型... URL 的组成部分比方案/权限/路径/查询更多。 (缺少 userInfo 或 port 的可能性,如果您需要这些,请相应地修改此代码。)