少年阿宾

那些青春的岁月

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

https一般来说有单项SSL和双向SSL连接之分。

 

单项SSL连接,也就是只是客户端验证服务器证书。tomcat中clientAuth="false"的时候,HTTPS单向验证如下:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.util.Date;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ClientSendData {
    static Log log = LogFactory.getLog(ClientSendData.class);
    // 客户端信任的证书
    private String sslTrustStore;
    private String sslTrustStorePassword;
    private String Url;

    //初始化数据
    public ClientSendData() {
        sslTrustStore = "D:/ssl/clientTrust.jks";
        sslTrustStorePassword = "123456";
        Url = "https://test.yihaodian.com:8443/ims/feedbackToPingAn_getData.action";
    }

    public String sendData(String data) {
        String receivedData = null;
        try {
            //设置系统参数
            System.setProperty("javax.net.ssl.trustStore", sslTrustStore);
            System.setProperty("javax.net.ssl.trustStorePassword",
                    sslTrustStorePassword);
            receivedData = send(Url, data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return receivedData;
    }

    public static String send(String sendurl, String sendData)
            throws Exception {
        URL url = new URL(sendurl);
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                return true;
            }
        };
        System.setProperty("java.protocol.handler.pkgs","sun.net.www.protocol");
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
        Date current = new Date(System.currentTimeMillis());
        log.info("begint to open connection at " + current);
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        Date end = new Date(System.currentTimeMillis());
        log.info("open connection ok at " + end + ",cost:"+ (end.getTime() - current.getTime()));
        connection.setRequestProperty("Content-Type", "text/xml");
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestMethod("POST");
        connection.setUseCaches(false);
        connection.setReadTimeout(30000);
        byte data[] = sendData.getBytes();
        current = new Date(System.currentTimeMillis());
        log.info("[SSLIX]notifyEai,begint to write data at " + current);
        OutputStream out = connection.getOutputStream();
        out.write(data);
        end = new Date(System.currentTimeMillis());
        log.info("write data ok at " + end + ",cost:"
                + (end.getTime() - current.getTime()));
        StringBuffer receivedData = new StringBuffer();
        current = new Date(System.currentTimeMillis());
        log.info("begint to read data at " + current);
        InputStreamReader inReader = new InputStreamReader(connection
                .getInputStream(), "UTF-8");
        BufferedReader aReader = new BufferedReader(inReader);
        String aLine;
        while ((aLine = aReader.readLine()) != null) {
            receivedData.append(aLine);
        }
        end = new Date(System.currentTimeMillis());
        log.info("read data ok at " + end + ",cost:"
                + (end.getTime() - current.getTime()));

        log.info("开始返回状态码");
        Integer statusCode = connection.getResponseCode();
        log.info("返回状态码:" + statusCode);
        aReader.close();
        connection.disconnect();
        return receivedData.toString();
    }

    public static void main(String[] args) {
        ClientSendData t = new ClientSendData();
        t.sendData("测试SSL单项连接,向服务端发送数据!");
    }
}

单项认证时,只需要设置客户端信任的证书库就行。但是当是双向认证时,还需要设置客户端密钥库密码。

HTTPS双向验证代码如下:

public class ClientSendData {
    static Log log = LogFactory.getLog(EaiChannel.class);
    //客户端密钥库
    private String sslKeyStorePath;
    private String sslKeyStorePassword;
    private String sslKeyStoreType;
    // 客户端信任的证书
    private String sslTrustStore;
    private String sslTrustStorePassword;
    private String eaiUrl;

    //初始化数据
    public ClientSendData() {
        sslKeyStorePath = "D:/ssl/clientKeys.jks";
        sslKeyStorePassword     = "123456";
        sslKeyStoreType = "JKS"; //密钥库类型,有JKS PKCS12等
        sslTrustStore = "D:/ssl/clientTrust.jks";
        sslTrustStorePassword = "123456";
        eaiUrl = "https://test.yihaodian.com:8443/ims/feedbackToPingAn_getData.action";
    }

    public String sendData(String data) {
        String receivedData = null;
        try {
            
             System.setProperty("javax.net.ssl.keyStore", sslKeyStorePath);
             System.setProperty("javax.net.ssl.keyStorePassword",sslKeyStorePassword);
             System.setProperty("javax.net.ssl.keyStoreType", sslKeyStoreType);
            //设置系统参数
            System.setProperty("javax.net.ssl.trustStore", sslTrustStore);
            System.setProperty("javax.net.ssl.trustStorePassword",
                    sslTrustStorePassword);
            receivedData = send(eaiUrl, data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return receivedData;
    }

    public static String send(String sendurl, String sendData)
            throws Exception {
        //和上面一样
    }

    public static void main(String[] args) {
        ClientSendData t = new ClientSendData();
        t.sendData("测试SSL双项连接,向服务端发送数据!");
    }
}


下面来说说可能会遇到的异常:

1. java.security.NoSuchAlgorithmException

 

一般来说是密钥库类型不对,如上面的sslKeyStoreType = "JKS" 却写成PKCS12。

 

也有可能是证书的问题。

 

2. java.net.UnknownHostException

 

服务端地址不对。

 

3.java.net.SocketException: Unexpected end of file from server

 

这个异常和客户端没有关系,说明已经发送成功。是服务端的问题。有可能是防火墙的原因,也可能是服务端没处理客户端的响应。

另外有人说当URL过长时也会发生此错误,当使用URL发送数据时,可以参考此意见。

 

4.java.io.IOException:server returned HTTP response code :500

 

 

这个异常是服务端代码的问题。服务端相应代码执行时抛出了异常。

 

 

最后 如果返回的状态码是200 ,表示成功。


 

 

posted on 2012-09-23 22:31 abin 阅读(9140) 评论(1)  编辑  收藏 所属分类: HTTPS

Feedback

# re: Java Https单向,双向验证 2013-03-18 13:32 suipy
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
return true;
}
};
.....
HttpsURLConnection.setDefaultHostnameVerifier(hv);
.....
博主您好,这样的重写,把HTTPS默认的主机验证给跳过了。
例如,访问百度的登录页面,应该是https://passport.baidu.com/v2/?login
如果在浏览器输入https://123.125.115.81/v2/?login
就会报证书中subject的CN和输入的域名不相符的异常(此时容易遭受中间人攻击)。
重写该方法后,这种验证就被覆盖了,这种异常就不会捕获,会有安全风险。

您看看是不是这样的?  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: