为Hessian加入加密签名的安全机制
博客分类:java
SpringXMLJDK
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
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
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代码
class="com.yeatssearch.remote.hessian.YeatsHessianProxyFactoryBean">
value="http://localhost:8080/Test/remoting/TestService" />
value="com.yeatssearch.test.TestService" />
服务器端SPRING配置
Xml代码
class="com.yeatssearch.remote.hessian.YeatsHessianServiceExporter">
value="com.yeatssearch.test.TestService" />
分享到:
为Hessian加入加密签名的安全机制
博客分类:java
SpringXMLJDK
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
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
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代码
class="com.yeatssearch.remote.hessian.YeatsHessianProxyFactoryBean">
value="http://localhost:8080/Test/remoting/TestService" />
value="com.yeatssearch.test.TestService" />
服务器端SPRING配置
Xml代码
class="com.yeatssearch.remote.hessian.YeatsHessianServiceExporter">
value="com.yeatssearch.test.TestService" />
分享到: