`
dingjob
  • 浏览: 181011 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Hessian接口调用时的DSA 加密

阅读更多

  我们经常会使用hessian接口,但是hessian接口默认的情况下是不会进行加密的,原来在项目中使用了MD5的加密,这次希望通过DSA 加密解决 C- S的安全通讯,一方面确定客户端是有权限调用的(给出了publicKey),另一方面保证传输的数据安全

 

  基本思路就是采用 新的HessianProxyFactory和 HessianServiceExporter 代替原来的发送和接收端,发送请求时进行私钥加密,接收时进行公钥的解密。

 

  基本逻辑实现如下:

 

/**
 * 实现带加密功能的hessian client
 * 
 * <pre>
 * 结合spring hessian使用,使用DSAHessianProxyFactory替换默认的HessianProxyFactory
 * &lt;bean id=&quot;heessianClient&quot; class=&quot;org.springframework.remoting.caucho.HessianProxyFactoryBean&quot;&gt;
 *      &lt;property name=&quot;proxyFactory&quot;&gt;
 *          &lt;bean class=&quot;com.alibaba.pivot.common.hessian.DSAHessianProxyFactory&quot;&gt;
 *              &lt;property name=&quot;secureKey&quot; value=&quot;xxxxx&quot;/&gt;
 *          &lt;/bean&gt;
 *      &lt;/property&gt;
 * &lt;/bean&gt;
 * </pre>
 * 
 * @author job 2010-01-28 上午10:20:01
 */
public class DSAHessianProxyFactory extends HessianProxyFactory {

    private static final Logger log = LoggerFactory.getLogger(DSAHessianProxyFactory.class);

    private DSAService          dsaService;

    private String     keyPairName;

    /**
     * 固定的加密字符串
     */
    private String              secureKey;

    protected URLConnection openConnection(URL url) throws IOException {
        String signature = null;
        String baseUrl = url.toString();
        StringBuilder queryBuilder = new StringBuilder();
        queryBuilder.append(baseUrl);

        // 生成时间戳
        long timestamp = System.currentTimeMillis();
        // 生成方法签名
        try {
            signature = dsaService.sign(secureKey + "|" + Long.toString(timestamp), keyPairName);
        } catch (NoSuchKeyPairException ne) {
            log.error("error in DSAHessianProxyFactory.openConnection,no such key" + keyPairName, ne);
        } catch (DSAException de) {
            log.error("error in DSAHessianProxyFactory.openConnection,DSA sign error" + keyPairName, de);
        }
        if (!"?".equals(queryBuilder.charAt(queryBuilder.length() - 1))) {
            queryBuilder.append("?");
        }

        queryBuilder.append("sign=");
        if (signature != null) {
            queryBuilder.append(StringEscapeUtil.escapeURL(signature));
        }
        queryBuilder.append("&time=");
        queryBuilder.append(timestamp);
        URL secureUrl = new URL(queryBuilder.toString());

        URLConnection conn = secureUrl.openConnection();

        conn.setDoOutput(true);

        if (getReadTimeout() > 0) {
            try {
                conn.setReadTimeout((int) getReadTimeout());
            } catch (Throwable e) {
            }
        }
        // 设置自定义的content-type
        conn.setRequestProperty("Content-Type", "application/octet-stream");

        return conn;
    }

 

 

 

输出时的加密:

 

/**
 * 处理加密的hessian server, 代码来自pivot-p4p
 * 
 * <pre>
 * 1. timeout 设置超时时间,单位秒. (客户端会在每次请求中添加时间戳,如果设置了该值,就会进行对客户端请求时间是否超时进行验证)
 * 2. secureKey 服务端密钥串 (如果设置了该值,就会进行对客户端请求加密串进行验证)
 * 3. allowedClients 客户端IP验证 (如果设置了该值,就会进行对客户端请求IP进行验证)
 * </pre>
 * 
 * @author job 2010-01-28 上午09:53:02
 */
public class DSAHessianServiceExporter extends HessianServiceExporter {

    private static Logger log = LoggerFactory.getLogger(DSAHessianServiceExporter.class);

    /** 请求过期时间 **/
    private long          timeout;
    /** 令牌原文 **/
    private String        secureKey;
    /** 允许访问的客户端 **/
    private String        allowedClients;
    /** dsa 加密服务 **/
    private DSAService    dsaService;
    /** 密钥名称 **/
    private String        keyPairName;

    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException,
                                                                                       IOException {
        // 1.如果设置了允许的IP地址,需要进行客户端IP地址验证
        if (StringUtil.isNotBlank(allowedClients)) {
            String clientIP = getClientIPAddress(request);
            if (!isAllowedClient(clientIP)) {
                log.error("hessian authentication error:" + clientIP + " not in allowedList " + allowedClients);
                return;
            }
        }

        // 2.如果设置了令牌或者过期时间,需要判断时间格式是否合法
        String strTimestamp = request.getParameter("time");
        long timestamp = 0;
        if (timeout > 0 || StringUtil.isNotBlank(secureKey)) {
            if (strTimestamp == null) {
                log.error("hessian authentication error:timestamp not exist!");
                return;
            }
            try {
                timestamp = Long.parseLong(strTimestamp);
            } catch (NumberFormatException e) {
                log.error("hessian authentication error:timestamp is not number!");
                return;
            }
        }

        // 3.如果设置了过期时间,需要判断请求是否过期
        if (timeout > 0) {
            // 判断请求是否过期
            if (isRequestExpired(timestamp)) {
                log.error("hessian authentication error:request is expired!");
                return;
            }
        }

        // 4. 如果设置了令牌,需要进行签名校验
        if (StringUtil.isNotBlank(secureKey)) {
            // 4.1 得到签名
            String signature = request.getParameter("sign");
            if (signature == null) {
                log.error("hessian authentication error:signatures not exist!");
                return;
            }
            try {
                // 4.2 验证签名是否一致
                boolean isRight = dsaService.check(secureKey + "|" + timestamp, signature, keyPairName);
                if (!isRight) {
                    log.error("hessian authentication error:signatures not match!");
                    return;
                }
            } catch (NoSuchKeyPairException ne) {
                log.error("error in DSAHessianServiceExporter.handleRequest,no such key" + keyPairName, ne);
            } catch (DSAException de) {
                log.error("error in DSAHessianServiceExporter.handleRequest,DSA sign error", de);
            }

        }
        // 5. 设置hessian context-type
        response.setContentType("application/octet-stream");
        super.handleRequest(request, response);
    }

 

 

 

 

对于key的产生可以用java自带的工具 keystore产生。

分享到:
评论
1 楼 sunney2010 2010-06-24  
好样的。一直在想这个Hessian问题。试用一下。

相关推荐

Global site tag (gtag.js) - Google Analytics