分享

为Hessian加入加密签名的安全机制

 老年图书馆 2012-09-21
Hessian是轻量级的RMI实现使用起来非常的方便,同时与SPRING也结合的非常好。但是在系统中有个比较大的缺陷就是Hessian自身没有解决安全问题。
我在项目的开发中为了解决Hessian的安全问题,在HTTP头中加入了签名信息。
首先要继承HessianProxyFactory在HTTP头中加入时间戳和签名
Java代码  收藏代码
  1. /** 
  2.  * @author Buffon 
  3.  *  
  4.  */  
  5. public class YeatsHessianProxyFactory extends HessianProxyFactory {  
  6.   
  7.     private long connectTimeOut = 0;  
  8.   
  9.     private String signature;  
  10.   
  11.     private long timeStamp;  
  12.   
  13.     /** 
  14.      * @return signature 
  15.      */  
  16.     public String getSignature() {  
  17.         return signature;  
  18.     }  
  19.   
  20.     /** 
  21.      * @param signature 
  22.      *            要设置的 signature 
  23.      */  
  24.     public void setSignature(String signature) {  
  25.         this.signature = signature;  
  26.     }  
  27.   
  28.     /** 
  29.      * @return connectTimeOut 
  30.      */  
  31.     public long getConnectTimeOut() {  
  32.         return connectTimeOut;  
  33.     }  
  34.   
  35.     /** 
  36.      * @param connectTimeOut 
  37.      *            要设置的 connectTimeOut 
  38.      */  
  39.     public void setConnectTimeOut(long connectTimeOut) {  
  40.         this.connectTimeOut = connectTimeOut;  
  41.     }  
  42.   
  43.     public URLConnection openConnection(URL url) throws IOException {  
  44.         URLConnection conn = super.openConnection(url);  
  45.   
  46.         if (connectTimeOut > 0) {  
  47.             try {  
  48.                 // only available for JDK 1.5  
  49.                 Method method = conn.getClass().getMethod("setConnectTimeout",  
  50.                         new Class[] { int.class });  
  51.   
  52.                 if (method != null)  
  53.                     method.invoke(conn, new Object[] { new Integer(  
  54.                             (int) connectTimeOut) });  
  55.             } catch (Throwable e) {  
  56.             }  
  57.         }  
  58.         if (!StringUtil.isEmptyOrWhitespace(this.signature)) {  
  59.             conn.setRequestProperty("Yeats-Signature"this.signature);  
  60.         }  
  61.         if (this.timeStamp > 0) {  
  62.             conn.setRequestProperty("Yeats-Timestamp", Long  
  63.                     .toString(this.timeStamp));  
  64.         }  
  65.         return conn;  
  66.   
  67.     }  
  68.   
  69.     /** 
  70.      * @return timeStamp 
  71.      */  
  72.     public long getTimeStamp() {  
  73.         return timeStamp;  
  74.     }  
  75.   
  76.     /** 
  77.      * @param timeStamp 
  78.      *            要设置的 timeStamp 
  79.      */  
  80.     public void setTimeStamp(long timeStamp) {  
  81.         this.timeStamp = timeStamp;  
  82.     }  
  83.   
  84. }  

关键之处就在于openConnection方法覆盖了HessianProxyFactory的openConnection方案在原有的openConnection方法基础上加入了链接超时的设置,及时间戳和签名。
继承HessianProxyFactoryBean使proxyFactory设置为上面的子类实现
Java代码  收藏代码
  1. /** 
  2.  * @author Buffon 
  3.  *  
  4.  */  
  5. public class YeatsHessianProxyFactoryBean extends HessianProxyFactoryBean {  
  6.     private YeatsHessianProxyFactory proxyFactory = new YeatsHessianProxyFactory();  
  7.   
  8.     private long readTimeOut;  
  9.   
  10.     private long connectTimeOut;  
  11.   
  12.     private String crypt;  
  13.   
  14.     private DSA dsaService;  
  15.   
  16.     /** 
  17.      * @return crypt 
  18.      */  
  19.     public String getCrypt() {  
  20.         return crypt;  
  21.     }  
  22.   
  23.     /** 
  24.      * @param crypt 
  25.      *            要设置的 crypt 
  26.      */  
  27.     public void setCrypt(String crypt) {  
  28.         this.crypt = crypt;  
  29.     }  
  30.   
  31.     /** 
  32.      * @return connectTimeOut 
  33.      */  
  34.     public long getConnectTimeOut() {  
  35.         return connectTimeOut;  
  36.     }  
  37.   
  38.     /** 
  39.      * @param connectTimeOut 
  40.      *            要设置的 connectTimeOut 
  41.      */  
  42.     public void setConnectTimeOut(long connectTimeOut) {  
  43.         this.connectTimeOut = connectTimeOut;  
  44.     }  
  45.   
  46.     /** 
  47.      * @return readTimeOut 
  48.      */  
  49.     public long getReadTimeOut() {  
  50.         return readTimeOut;  
  51.     }  
  52.   
  53.     /** 
  54.      * @param readTimeOut 
  55.      *            要设置的 readTimeOut 
  56.      */  
  57.     public void setReadTimeOut(long readTimeOut) {  
  58.         this.readTimeOut = readTimeOut;  
  59.     }  
  60.   
  61.     public void afterPropertiesSet() {  
  62.         proxyFactory.setReadTimeout(readTimeOut);  
  63.         proxyFactory.setConnectTimeOut(connectTimeOut);  
  64.         long timeStamp = new Date().getTime();  
  65.         proxyFactory.setTimeStamp(timeStamp);  
  66.         try {  
  67.             proxyFactory.setSignature(this.createSignature(timeStamp,  
  68.                     this.crypt));  
  69.   
  70.         } catch (Exception e) {  
  71.   
  72.         }  
  73.         setProxyFactory(proxyFactory);  
  74.   
  75.         super.afterPropertiesSet();  
  76.     }  
  77.   
  78.     private String createSignature(long timeStamp, String crypt)  
  79.             throws Exception {  
  80.         if (timeStamp <= 0 || StringUtil.isEmptyOrWhitespace(crypt)) {  
  81.             throw new Exception("timestamp or crypt is invalied");  
  82.         }  
  83.         StringBuilder sb = new StringBuilder();  
  84.         sb.append("{");  
  85.         sb.append(timeStamp);  
  86.         sb.append("},{");  
  87.         sb.append(crypt);  
  88.         sb.append("}");  
  89.         return dsaService.sign(sb.toString());  
  90.     }  
  91.   
  92.     /** 
  93.      * @return dsaService 
  94.      */  
  95.     public DSA getDsaService() {  
  96.         return dsaService;  
  97.     }  
  98.   
  99.     /** 
  100.      * @param dsaService 要设置的 dsaService 
  101.      */  
  102.     public void setDsaService(DSA dsaService) {  
  103.         this.dsaService = dsaService;  
  104.     }  
  105.   
  106. }  

dsaService的实现请参考我的另一篇文章《java加入DSA签名》,createSignature方法中签名的明文组成形式是“{时间戳},{密码字符串}”
继承HessianServiceExporter对签名进行校验
Java代码  收藏代码
  1. /** 
  2.  * @author Buffon 
  3.  *  
  4.  */  
  5. public class YeatsHessianServiceExporter extends HessianServiceExporter {  
  6.     private static final Log log = LogFactory.getLog(YeatsHessianServiceExporter.class);  
  7.     private DSA dsaService;  
  8.   
  9.     private String crypt;  
  10.   
  11.     private long timeValve;  
  12.   
  13.     public void handleRequest(HttpServletRequest request,  
  14.             HttpServletResponse response) throws ServletException, IOException {  
  15.         String signature = request.getHeader("Yeats-Signature");  
  16.         String timestamp = request.getHeader("Yeats-Timestamp");  
  17.         if (StringUtil.isEmptyOrWhitespace(signature)) {  
  18.             log.error("Can't get signature");  
  19.             throw new ServletException("Can't get signature");  
  20.         }  
  21.         if (StringUtil.isEmptyOrWhitespace(timestamp)) {  
  22.             log.error("Cant't get timestamp");  
  23.             throw new ServletException("Cant't get timestamp");  
  24.         }  
  25.         long now = new Date().getTime();  
  26.         long range = now - Long.parseLong(timestamp);  
  27.         if (range < 0) {  
  28.             range = -range;  
  29.         }  
  30.         if (range > timeValve) {  
  31.             log.error("Timestamp is timeout");  
  32.             throw new ServletException("Timestamp is timeout");  
  33.         }  
  34.   
  35.         StringBuilder sb = new StringBuilder();  
  36.         sb.append("{");  
  37.         sb.append(timestamp);  
  38.         sb.append("},{");  
  39.         sb.append(crypt);  
  40.         sb.append("}");  
  41.   
  42.         try {  
  43.             if (dsaService.verify(signature, sb.toString())) {  
  44.                 super.handleRequest(request, response);  
  45.             } else {  
  46.                 log.error("No permission");  
  47.                 throw new ServletException("No permission");  
  48.             }  
  49.         } catch (Exception e) {  
  50.             log.error("Failed to process remote request!", e);  
  51.             throw new ServletException(e);  
  52.         }  
  53.     }  
  54.   
  55.     /** 
  56.      * @return dsaService 
  57.      */  
  58.     public DSA getDsaService() {  
  59.         return dsaService;  
  60.     }  
  61.   
  62.     /** 
  63.      * @param dsaService 
  64.      *            要设置的 dsaService 
  65.      */  
  66.     public void setDsaService(DSA dsaService) {  
  67.         this.dsaService = dsaService;  
  68.     }  
  69.   
  70.     /** 
  71.      * @return crypt 
  72.      */  
  73.     public String getCrypt() {  
  74.         return crypt;  
  75.     }  
  76.   
  77.     /** 
  78.      * @param crypt 
  79.      *            要设置的 crypt 
  80.      */  
  81.     public void setCrypt(String crypt) {  
  82.         this.crypt = crypt;  
  83.     }  
  84.   
  85.     /** 
  86.      * @return timeValve 
  87.      */  
  88.     public long getTimeValve() {  
  89.         return timeValve;  
  90.     }  
  91.   
  92.     /** 
  93.      * @param timeValve 
  94.      *            要设置的 timeValve 
  95.      */  
  96.     public void setTimeValve(long timeValve) {  
  97.         this.timeValve = timeValve;  
  98.     }  
  99.   
  100. }  

覆盖handleRequest方法,在验证通过后再调用父类的handleRequest方法。timeValve为时间戳的校验范围,如果请求到达时间大于这个范围,此请求被认为是非法请求不会再做处理
客户端SPRING配置
Xml代码  收藏代码
  1. <bean id="searchService"  
  2.         class="com.yeatssearch.remote.hessian.YeatsHessianProxyFactoryBean">  
  3.         <property name="serviceUrl"  
  4.             value="http://localhost:8080/Test/remoting/TestService" />  
  5.         <property name="serviceInterface"  
  6.             value="com.yeatssearch.test.TestService" />  
  7.         <property name="readTimeOut" value="30000"/>  
  8.         <property name="connectTimeOut" value="5000"/>  
  9.         <property name="crypt" value="sdfsfdsfsdfsdfsdf"/>  
  10.         <property name="dsaService" ref="dsaService"></property>  
  11.     </bean>  

服务器端SPRING配置
Xml代码  收藏代码
  1. <bean name="/TestService"  
  2.         class="com.yeatssearch.remote.hessian.YeatsHessianServiceExporter">  
  3.         <property name="service" ref="testService" />  
  4.         <property name="serviceInterface"  
  5.             value="com.yeatssearch.test.TestService" />        
  6.         <property name="timeValve" value="30000"/>  
  7.         <property name="crypt" value="sdfsfdsfsdfsdfsdf"/>  
  8.         <property name="dsaService" ref="dsaService"/>  
  9.     </bean>  
分享到:

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多