`

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

    博客分类:
  • java
阅读更多
Hessian是轻量级的RMI实现使用起来非常的方便,同时与SPRING也结合的非常好。但是在系统中有个比较大的缺陷就是Hessian自身没有解决安全问题。
我在项目的开发中为了解决Hessian的安全问题,在HTTP头中加入了签名信息。
首先要继承HessianProxyFactory在HTTP头中加入时间戳和签名
/**
 * @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设置为上面的子类实现
/**
 * @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对签名进行校验
/**
 * @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配置
<bean id="searchService"
		class="com.yeatssearch.remote.hessian.YeatsHessianProxyFactoryBean">
		<property name="serviceUrl"
			value="http://localhost:8080/Test/remoting/TestService" />
		<property name="serviceInterface"
			value="com.yeatssearch.test.TestService" />
		<property name="readTimeOut" value="30000"/>
		<property name="connectTimeOut" value="5000"/>
		<property name="crypt" value="sdfsfdsfsdfsdfsdf"/>
		<property name="dsaService" ref="dsaService"></property>
	</bean>

服务器端SPRING配置
<bean name="/TestService"
		class="com.yeatssearch.remote.hessian.YeatsHessianServiceExporter">
		<property name="service" ref="testService" />
		<property name="serviceInterface"
			value="com.yeatssearch.test.TestService" />		
		<property name="timeValve" value="30000"/>
		<property name="crypt" value="sdfsfdsfsdfsdfsdf"/>
		<property name="dsaService" ref="dsaService"/>
	</bean>
分享到:
评论
5 楼 yeshucheng 2008-08-05  
<p>建议楼主看看hessian源代码,</p>
<p>其实是有的: </p>
<p>X509Signature extends HessianEnvelope</p>
<p> X509Encryption extends HessianEnvelope</p>
4 楼 melin 2008-08-05  
认证好像是通过http basice的方式。加密没有使用过
3 楼 general 2008-08-05  
hessian内置的加密和认证如何使用呢?经过多方搜索无果。
2 楼 davis_854 2008-06-30  
别扯了,hessian的加密和认证都有的
1 楼 guzhan 2008-03-11  
问题是要实现通讯数据的加密而不是简单的调用认证啊

相关推荐

Global site tag (gtag.js) - Google Analytics