[Spring] 为Hessian加入加密签名的安全机制
2011-08-03 01:32
489 查看
Hessian是轻量级的RMI实现使用起来非常的方便,同时与SPRING也结合的非常好。但是在系统中有个比较大的缺陷就是Hessian自身没有解决安全问题。
我在项目的开发中为了解决Hessian的安全问题,在HTTP头中加入了签名信息。
首先要继承HessianProxyFactory在HTTP头中加入时间戳和签名
Java代码
/**
* @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代码
/** * @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代码
/**
* @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代码
<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配置
Xml代码
<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>
我在项目的开发中为了解决Hessian的安全问题,在HTTP头中加入了签名信息。
首先要继承HessianProxyFactory在HTTP头中加入时间戳和签名
Java代码
/**
* @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;
}
}
/** * @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代码
/** * @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; } }
/** * @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代码
/**
* @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;
}
}
/** * @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代码
<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>
<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配置
Xml代码
<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>
相关文章推荐
- Android安全机制--六种核心安全机制-加密、密钥、签名与证书
- SpringCloud系列十:SpringCloudConfig 高级配置(密钥加密处理(JCE)、KeyStore 加密处理、SpringCloudConfig 高可用机制、SpringCloudBus 服务总线)
- android应用安全——签名机制
- WSE3.0构建Web服务安全(2):非对称加密、公钥、密钥、证书、签名的区别和联系以及X.509 证书的获得和管理
- BlackBerry平台加密安全机制(Crypto API)
- Spring配置数据库和shiro安全机制
- Linux安全机制之文件加密解密
- hessian-添加安全机制
- 典型的网络接口安全机制,AES和RSA混合加密
- SpringCloud系列四:Eureka 服务发现框架(定义 Eureka 服务端、Eureka 服务信息、Eureka 发现管理、Eureka 安全配置、Eureka-HA(高可用) 机制、Eureka 服务打包部署)
- 运用Web Services安全机制对SOAP消息加密
- Zigbee Smart Energy安全加密机制
- 四、Android安全机制之数据加密
- 如何写出安全的API接口?接口参数加密签名设计思路
- RSA加密解密和签名验证机制以及其区别和联系
- 签名与加密安全技术基础(一)------哈希算法
- .NET 实战SSL安全加密机制 [转]
- 网络安全——数据的加密与签名,RSA介绍
- 运用基本 Web Services 安全机制对 WebSphere Information Integrator Content Edition SOAP 消息进行加密
- 加密安全和数字签名证书