HttpClient使用过程中的安全隐患

开发 后端
HttpClient使用过程中的安全隐患,这个有些标题党。因为这本身不是HttpClient的问题,而是使用者的问题。

HttpClient使用过程中的安全隐患,这个有些标题党。因为这本身不是HttpClient的问题,而是使用者的问题。

安全隐患场景说明:

一旦请求大数据资源,则HttpClient线程会被长时间占有。即便调用了org.apache.commons.httpclient.HttpMethod#releaseConnection()方法,也无济于事。

如果请求的资源是应用可控的,那么不存在任何问题。可是恰恰我们应用的使用场景是,请求资源由用户自行输入,于是乎,我们不得不重视这个问题。

我们跟踪releaseConnection代码发现:

org.apache.commons.httpclient.HttpMethodBase#releaseConnection()

 

  1. public   void  releaseConnection() {  
  2.       try  {  
  3.           if  ( this .responseStream  !=   null ) {  
  4.               try  {  
  5.                    //  FYI - this may indirectly invoke responseBodyConsumed.   
  6.                   this .responseStream.close();  
  7.              }  catch  (IOException ignore) {  
  8.              }  
  9.          }  
  10.      }  finally  {  
  11.           ensureConnectionRelease();  
  12.      }  
  13.  }  

 

org.apache.commons.httpclient.ChunkedInputStream#close()

 

  1. public   void  close()  throws  IOException {  
  2.        if  ( ! closed) {  
  3.            try  {  
  4.                if  ( ! eof) {  
  5.                  exhaustInputStream( this );  
  6.               }  
  7.          }  finally  {  
  8.               eof  =   true ;  
  9.               closed  =   true ;  
  10.           }  
  11.       }  
  12.   }  

 

org.apache.commons.httpclient.ChunkedInputStream#exhaustInputStream(InputStream inStream)

 

  1. static   void  exhaustInputStream(InputStream inStream)  throws  IOException {  
  2.       //  read and discard the remainder of the message   
  3.       byte  buffer[]  =   new   byte [ 1024 ];  
  4.       while  (inStream.read(buffer)  >=   0 ) {  
  5.          ;  
  6.       }  
  7.  }  

 

看到了吧,所谓的丢弃response,其实是读完了一次请求的response,只是不做任何处理罢了。

想想也是,HttpClient的设计理念是重复使用HttpConnection,岂能轻易被强制close呢。

怎么办?有朋友说,不是有time out设置嘛,设置下就可以下。

我先来解释下Httpclient中两个time out的概念:

1.public static final String CONNECTION_TIMEOUT = "http.connection.timeout";

即创建socket连接的超时时间:java.net.Socket#connect(SocketAddress endpoint, int timeout)中的timeout

2.public static final String SO_TIMEOUT = "http.socket.timeout";

即read data过程中,等待数据的timeout:java.net.Socket#setSoTimeout(int timeout)中的timeout

而在我上面场景中,这两个timeout都不满足,确实是由于资源过大,而占用了大量的请求时间。

问题总是要解决的,解决思路如下:

1.利用DelayQueue,管理所有请求

2.利用一个异步线程监控,关闭超长时间的请求

演示代码如下:

 

  1. public   class  Misc2 {  
  2.       
  3.          private   static   final  DelayQueue < Timeout >  TIMEOUT_QUEUE  =   new  DelayQueue < Timeout > ();  
  4.       
  5.          public   static   void  main(String[] args)  throws  Exception {  
  6.              new  Monitor().start();  //  超时监控线程   
  7.       
  8.              new  Request( 4 ).start(); //  模拟***个下载   
  9.              new  Request( 3 ).start(); //  模拟第二个下载   
  10.             new  Request( 2 ).start(); //  模拟第三个下载   
  11.        }  
  12.      
  13.         /**   
  14.         * 模拟一次HttpClient请求  
  15.         *   
  16.         *  @author  Stone.J 2011-4-9  
  17.        */   
  18.         public   static   class  Request  extends  Thread {  
  19.      
  20.             private   long  delay;  
  21.      
  22.             public  Request( long  delay){  
  23.                 this .delay  =  delay;  
  24.            }  
  25.      
  26.             public   void  run() {  
  27.                HttpClient hc  =   new  HttpClient();  
  28.                GetMethod req  =   new  GetMethod( " http://www.python.org/ftp/python/2.7.1/Python-2.7.1.tgz " );  
  29.                 try  {  
  30.                    TIMEOUT_QUEUE.offer( new  Timeout(delay  *   1000 , hc.getHttpConnectionManager()));  
  31.                    hc.executeMethod(req);  
  32.                }  catch  (Exception e) {  
  33.                    System.out.println(e);  
  34.                }  
  35.                req.releaseConnection();  
  36.            }  
  37.      
  38.        }  
  39.      
  40.         /**   
  41.         * 监工:监控线程,通过DelayQueue,阻塞得到最近超时的对象,强制关闭  
  42.         *   
  43.         *  @author  Stone.J 2011-4-9  
  44.          */   
  45.         public   static   class  Monitor  extends  Thread {  
  46.      
  47.            @Override 
  48.             public   void  run() {  
  49.                 while  ( true ) {  
  50.                     try  {  
  51.                        Timeout timeout  =  TIMEOUT_QUEUE.take();  
  52.                        timeout.forceClose();  
  53.                    }  catch  (InterruptedException e) {  
  54.                        System.out.println(e);  
  55.                    }  
  56.                }  
  57.            }  
  58.      
  59.        }  
  60.      
  61.         /**   
  62.         * 使用delay queue,对Delayed接口的实现 根据请求当前时间+该请求允许timeout时间,和当前时间比较,判断是否已经超时  
  63.         *   
  64.         *  @author  Stone.J 2011-4-9  
  65.          */   
  66.         public   static   class  Timeout  implements  Delayed {  
  67.      
  68.             private   long                   debut;  
  69.             private   long                   delay;  
  70.             private  HttpConnectionManager manager;  
  71.      
  72.             public  Timeout( long  delay, HttpConnectionManager manager){  
  73.                 this .debut  =  System.currentTimeMillis();  
  74.                 this .delay  =  delay;  
  75.                 this .manager  =  manager;  
  76.           }  
  77.      
  78.             public   void  forceClose() {  
  79.                System.out.println( this .debut  +   " : "   +   this .delay);  
  80.                 if  (manager  instanceof  SimpleHttpConnectionManager) {  
  81.                    ((SimpleHttpConnectionManager) manager).shutdown();  
  82.                }  
  83.                 if  (manager  instanceof  MultiThreadedHttpConnectionManager) {  
  84.                    ((MultiThreadedHttpConnectionManager) manager).shutdown();  
  85.                }  
  86.            }  
  87.      
  88.            @Override 
  89.             public   int  compareTo(Delayed o) {  
  90.                 if  (o  instanceof  Timeout) {  
  91.                    Timeout timeout  =  (Timeout) o;  
  92.                     if  ( this .debut  +   this .delay  ==  timeout.debut  +  timeout.delay) {  
  93.                         return   0 ;  
  94.                    }  else   if  ( this .debut  +   this .delay  >  timeout.debut  +  timeout.delay) {  
  95.                         return   1 ;  
  96.                    }  else  {  
  97.                         return   - 1 ;  
  98.                    }  
  99.                }  
  100.                return   0 ;  
  101.           }  
  102.     
  103.           @Override 
  104.            public   long  getDelay(TimeUnit unit) {  
  105.                return  debut  +  delay  -  System.currentTimeMillis();  
  106.           }  
  107.     
  108.       }  
  109.     
  110.   }  

【编辑推荐】

  1. Hibernate批量更新与删除实例浅析
  2. 简述Hibernate Synchronizer学习笔记
  3. Hibernate column属性简介
  4. 概括Hibernate查询语言
  5. Hibernate cartridge学习总结
责任编辑:金贺 来源: ITEYE博客
相关推荐

2010-06-07 16:51:06

rsync 使用

2016-03-23 11:03:40

2009-12-29 14:14:22

2022-02-07 00:10:28

Docker容器开发

2020-07-29 08:03:26

Celery异步项目

2009-11-02 08:56:17

2011-03-04 13:49:38

FileZilla

2011-05-05 18:28:18

2012-07-26 10:10:27

虚拟化安全网络安全

2010-09-17 14:29:23

2012-07-27 10:01:13

虚拟化

2010-07-20 11:05:44

2016-09-29 22:09:26

2012-03-28 14:50:40

2012-06-25 09:18:36

2017-02-24 08:11:09

Docker数据安全容器

2009-07-06 13:38:02

2009-03-17 09:48:00

2013-02-21 10:11:58

2023-12-25 11:55:58

点赞
收藏

51CTO技术栈公众号