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

 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. }  
/**
 * @author Buffon
 * 
 */
public class YeatsHessianProxyFactory extends HessianProxyFactory {

    private long connectTimeOut = 0;

    private String signature;

    private long timeStamp;

    /**
     * @return signature
     */
    public String getSignature() {
        return signature;
    }

    /**
     * @param signature
     *            要设置的 signature
     */
    public void setSignature(String signature) {
        this.signature = signature;
    }

    /**
     * @return connectTimeOut
     */
    public long getConnectTimeOut() {
        return connectTimeOut;
    }

    /**
     * @param connectTimeOut
     *            要设置的 connectTimeOut
     */
    public void setConnectTimeOut(long connectTimeOut) {
        this.connectTimeOut = connectTimeOut;
    }

    public URLConnection openConnection(URL url) throws IOException {
        URLConnection conn = super.openConnection(url);

        if (connectTimeOut > 0) {
            try {
                // only available for JDK 1.5
                Method method = conn.getClass().getMethod("setConnectTimeout",
                        new Class[] { int.class });

                if (method != null)
                    method.invoke(conn, new Object[] { new Integer(
                            (int) connectTimeOut) });
            } catch (Throwable e) {
            }
        }
        if (!StringUtil.isEmptyOrWhitespace(this.signature)) {
            conn.setRequestProperty("Yeats-Signature", this.signature);
        }
        if (this.timeStamp > 0) {
            conn.setRequestProperty("Yeats-Timestamp", Long
                    .toString(this.timeStamp));
        }
        return conn;

    }

    /**
     * @return timeStamp
     */
    public long getTimeStamp() {
        return timeStamp;
    }

    /**
     * @param timeStamp
     *            要设置的 timeStamp
     */
    public void setTimeStamp(long timeStamp) {
        this.timeStamp = timeStamp;
    }

}

关键之处就在于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. }  
/**
 * @author Buffon
 * 
 */
public class YeatsHessianProxyFactoryBean extends HessianProxyFactoryBean {
    private YeatsHessianProxyFactory proxyFactory = new YeatsHessianProxyFactory();

    private long readTimeOut;

    private long connectTimeOut;

    private String crypt;

    private DSA dsaService;

    /**
     * @return crypt
     */
    public String getCrypt() {
        return crypt;
    }

    /**
     * @param crypt
     *            要设置的 crypt
     */
    public void setCrypt(String crypt) {
        this.crypt = crypt;
    }

    /**
     * @return connectTimeOut
     */
    public long getConnectTimeOut() {
        return connectTimeOut;
    }

    /**
     * @param connectTimeOut
     *            要设置的 connectTimeOut
     */
    public void setConnectTimeOut(long connectTimeOut) {
        this.connectTimeOut = connectTimeOut;
    }

    /**
     * @return readTimeOut
     */
    public long getReadTimeOut() {
        return readTimeOut;
    }

    /**
     * @param readTimeOut
     *            要设置的 readTimeOut
     */
    public void setReadTimeOut(long readTimeOut) {
        this.readTimeOut = readTimeOut;
    }

    public void afterPropertiesSet() {
        proxyFactory.setReadTimeout(readTimeOut);
        proxyFactory.setConnectTimeOut(connectTimeOut);
        long timeStamp = new Date().getTime();
        proxyFactory.setTimeStamp(timeStamp);
        try {
            proxyFactory.setSignature(this.createSignature(timeStamp,
                    this.crypt));

        } catch (Exception e) {

        }
        setProxyFactory(proxyFactory);

        super.afterPropertiesSet();
    }

    private String createSignature(long timeStamp, String crypt)
            throws Exception {
        if (timeStamp <= 0 || StringUtil.isEmptyOrWhitespace(crypt)) {
            throw new Exception("timestamp or crypt is invalied");
        }
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        sb.append(timeStamp);
        sb.append("},{");
        sb.append(crypt);
        sb.append("}");
        return dsaService.sign(sb.toString());
    }

    /**
     * @return dsaService
     */
    public DSA getDsaService() {
        return dsaService;
    }

    /**
     * @param dsaService 要设置的 dsaService
     */
    public void setDsaService(DSA dsaService) {
        this.dsaService = dsaService;
    }

}

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. }  
/**
 * @author Buffon
 * 
 */
public class YeatsHessianServiceExporter extends HessianServiceExporter {
    private static final Log log = LogFactory.getLog(YeatsHessianServiceExporter.class);
    private DSA dsaService;

    private String crypt;

    private long timeValve;

    public void handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        String signature = request.getHeader("Yeats-Signature");
        String timestamp = request.getHeader("Yeats-Timestamp");
        if (StringUtil.isEmptyOrWhitespace(signature)) {
            log.error("Can't get signature");
            throw new ServletException("Can't get signature");
        }
        if (StringUtil.isEmptyOrWhitespace(timestamp)) {
            log.error("Cant't get timestamp");
            throw new ServletException("Cant't get timestamp");
        }
        long now = new Date().getTime();
        long range = now - Long.parseLong(timestamp);
        if (range < 0) {
            range = -range;
        }
        if (range > timeValve) {
            log.error("Timestamp is timeout");
            throw new ServletException("Timestamp is timeout");
        }

        StringBuilder sb = new StringBuilder();
        sb.append("{");
        sb.append(timestamp);
        sb.append("},{");
        sb.append(crypt);
        sb.append("}");

        try {
            if (dsaService.verify(signature, sb.toString())) {
                super.handleRequest(request, response);
            } else {
                log.error("No permission");
                throw new ServletException("No permission");
            }
        } catch (Exception e) {
            log.error("Failed to process remote request!", e);
            throw new ServletException(e);
        }
    }

    /**
     * @return dsaService
     */
    public DSA getDsaService() {
        return dsaService;
    }

    /**
     * @param dsaService
     *            要设置的 dsaService
     */
    public void setDsaService(DSA dsaService) {
        this.dsaService = dsaService;
    }

    /**
     * @return crypt
     */
    public String getCrypt() {
        return crypt;
    }

    /**
     * @param crypt
     *            要设置的 crypt
     */
    public void setCrypt(String crypt) {
        this.crypt = crypt;
    }

    /**
     * @return timeValve
     */
    public long getTimeValve() {
        return timeValve;
    }

    /**
     * @param timeValve
     *            要设置的 timeValve
     */
    public void setTimeValve(long timeValve) {
        this.timeValve = timeValve;
    }

}

覆盖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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值