HttpClient使用过程中的安全隐患

HttpClient使用过程中的安全隐患,这个有些标题党。因为这本身不是HttpClient的问题,
首页 新闻资讯 行业资讯 HttpClient使用过程中的安全隐患

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

安全隐患场景说明:

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

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

我们跟踪releaseConnection代码发现:

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

 

复制

public   void  releaseConnection() {        try  {            if  ( this .responseStream  !=   null ) {                try  {                     //  FYI - this may indirectly invoke responseBodyConsumed.                     this .responseStream.close();               }  catch  (IOException ignore) {               }           }       }  finally  {            ensureConnectionRelease();       }   }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

 

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

 

复制

public   void  close()  throws  IOException {         if  ( ! closed) {             try  {                 if  ( ! eof) {                   exhaustInputStream( this );                }           }  finally  {                eof  =   true ;                closed  =   true ;            }        }    }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

 

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

 

复制

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

  • 2.

  • 3.

  • 4.

  • 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.利用一个异步线程监控,关闭超长时间的请求

演示代码如下:

 

复制

public   class  Misc2 {                 private   static   final  DelayQueue < Timeout >  TIMEOUT_QUEUE  =   new  DelayQueue < Timeout > ();                 public   static   void  main(String[] args)  throws  Exception {               new  Monitor().start();  //  超时监控线程                      new  Request( 4 ).start(); //  模拟***个下载                new  Request( 3 ).start(); //  模拟第二个下载               new  Request( 2 ).start(); //  模拟第三个下载          }               /**           * 模拟一次HttpClient请求          *           *  @author  Stone.J 2011-4-9         */           public   static   class  Request  extends  Thread {                   private   long  delay;                   public  Request( long  delay){                  this .delay  =  delay;             }                   public   void  run() {                 HttpClient hc  =   new  HttpClient();                 GetMethod req  =   new  GetMethod( " http://www.python.org/ftp/python/2.7.1/Python-2.7.1.tgz " );                  try  {                     TIMEOUT_QUEUE.offer( new  Timeout(delay  *   1000 , hc.getHttpConnectionManager()));                     hc.executeMethod(req);                 }  catch  (Exception e) {                     System.out.println(e);                 }                 req.releaseConnection();             }              }               /**           * 监工:监控线程,通过DelayQueue,阻塞得到最近超时的对象,强制关闭          *           *  @author  Stone.J 2011-4-9           */           public   static   class  Monitor  extends  Thread {                  @Override             public   void  run() {                  while  ( true ) {                      try  {                         Timeout timeout  =  TIMEOUT_QUEUE.take();                         timeout.forceClose();                     }  catch  (InterruptedException e) {                         System.out.println(e);                     }                 }             }              }               /**           * 使用delay queue,对Delayed接口的实现 根据请求当前时间+该请求允许timeout时间,和当前时间比较,判断是否已经超时          *           *  @author  Stone.J 2011-4-9           */           public   static   class  Timeout  implements  Delayed {                   private   long                   debut;              private   long                   delay;              private  HttpConnectionManager manager;                   public  Timeout( long  delay, HttpConnectionManager manager){                  this .debut  =  System.currentTimeMillis();                  this .delay  =  delay;                  this .manager  =  manager;            }                   public   void  forceClose() {                 System.out.println( this .debut  +   " : "   +   this .delay);                  if  (manager  instanceof  SimpleHttpConnectionManager) {                     ((SimpleHttpConnectionManager) manager).shutdown();                 }                  if  (manager  instanceof  MultiThreadedHttpConnectionManager) {                     ((MultiThreadedHttpConnectionManager) manager).shutdown();                 }             }                  @Override             public   int  compareTo(Delayed o) {                  if  (o  instanceof  Timeout) {                     Timeout timeout  =  (Timeout) o;                      if  ( this .debut  +   this .delay  ==  timeout.debut  +  timeout.delay) {                          return   0 ;                     }  else   if  ( this .debut  +   this .delay  >  timeout.debut  +  timeout.delay) {                          return   1 ;                     }  else  {                          return   - 1 ;                     }                 }                 return   0 ;            }                @Override            public   long  getDelay(TimeUnit unit) {                 return  debut  +  delay  -  System.currentTimeMillis();            }            }        }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

  • 61.

  • 62.

  • 63.

  • 64.

  • 65.

  • 66.

  • 67.

  • 68.

  • 69.

  • 70.

  • 71.

  • 72.

  • 73.

  • 74.

  • 75.

  • 76.

  • 77.

  • 78.

  • 79.

  • 80.

  • 81.

  • 82.

  • 83.

  • 84.

  • 85.

  • 86.

  • 87.

  • 88.

  • 89.

  • 90.

  • 91.

  • 92.

  • 93.

  • 94.

  • 95.

  • 96.

  • 97.

  • 98.

  • 99.

  • 100.

  • 101.

  • 102.

  • 103.

  • 104.

  • 105.

  • 106.

  • 107.

  • 108.

  • 109.

  • 110.

【编辑推荐】

  1. Hibernate批量更新与删除实例浅析

  2. 简述Hibernate Synchronizer学习笔记

  3. Hibernate column属性简介

  4. 概括Hibernate查询语言

  5. Hibernate cartridge学习总结

12    2011-04-13 13:54:03    HttpClient