java基础总结(三十二)--Https协议的使用--服务器端和客户端

说明

1:本文介绍了两个知识模块,一个是Tomcat配置SSL另外一个是客户端绕过证书验证实现https

2:本文参考的是https://blog.csdn.net/xiaoxian8023/article/details/49865335这个博客。而原博客中tomcat配置ssl是一篇博客

客户端绕过证书验证实现https又是另外一篇博客。

为了方便我把原来博客中的tomcat配置ssl是一篇博客客户端绕过证书验证实现https转载到我自己的csdn博客中

tomcat配置ssl:https://blog.csdn.net/lsx2017/article/details/86710102

客户端绕过证书验证实现https:

文章内容

1.Web服务器(tomcat)端配置 
2.客户端(HttpClient)实现(Get/Post)

1.Web服务器(tomcat)端配置

1.1.服务器证书生成 

java基础总结(三十二)--Https协议的使用--服务器端和客户端

使用keytool按照提示创建一个证书,如果以后真正在产品环境中使用肯定要去证书提供商去购买,证书认证一般都是由VeriSign认证,中文官方网站:http://www.verisign.com/cn/,需要注意一下几点: 
1.**库口令 
2.名字为网站域名(后面通过修改host转发)


命令: 
keytool -genkey -alias aaronweb -keyalg RSA -keystore d:/keys/aaronweb

1.2.导出证书 
导出的证书可以给响应的客户端使用 

java基础总结(三十二)--Https协议的使用--服务器端和客户端

 

命令: 
keytool -export -file d:/keys/waaronweb.crt -alias aaronweb -keystore D:/keys/aaronweb

1.3.创建私钥(pem)(用于tomcat apr模式) 

java基础总结(三十二)--Https协议的使用--服务器端和客户端

java基础总结(三十二)--Https协议的使用--服务器端和客户端

 

命令: 
keytool -importkeystore -srckeystore D:\keys\aaronweb -destkeystore D:\keys\aaronweb.p12 -deststoretype PKCS12

openssl pkcs12 -in D:\keys\aaronweb.p12 -out D:\keys\aaronweb.pem -nodes
 

 

1.2.修改hosts文件 
修改host使得在访问域名aaron.web.com时实际访问的是本地主机; 
目录:C:\Windows\System32\drivers\etc\hosts 
添加:127.0.0.1 aaron.web.com

1.3.Web服务器创建和配置 
1.在Eclipse中配置好Tomcat环境,添加一个新的Web服务器; 
java基础总结(三十二)--Https协议的使用--服务器端和客户端

 

2.修改服务器配置 

java基础总结(三十二)--Https协议的使用--服务器端和客户端

修改Server.xml配置: 
添加SSLCertificateFile(导出证书crt文件地址),SSLCertificateKeyFile(生成的私钥pem文件地址)

java基础总结(三十二)--Https协议的使用--服务器端和客户端

3.服务器测试 
通过Eclipse导入一个Web项目到先添加的tomcat服务器上,启动服务器,在浏览器中测试;

 

注意端口地址8443或自定义 
浏览器需要添加例外(证书不是公共平台认证的)

java基础总结(三十二)--Https协议的使用--服务器端和客户端

2.客户端(HttpClient)实现(Get/Post)

2.0.准备

应为需要测试Get、Post两种方式,需要在web项目中添加测试用的servlet,比如:

public class HelloWorldServlet extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {
        PrintWriter out = res.getWriter();
        out.println("Hello, Brave new World!");
        out.close();
    }
}

 

2.1.忽略认证Https客户端的实现
在很多情况下我们并不希望验证服务器的证书信息,而需要忽略验证的结果,特别是在接口调用上,所以,首先实现忽略验证的Https客户端,主要实现常用的Get和Post方法;

下面是具体的步骤: 
(对于其中涉及到的相关概念可以参考之前的文章:http://blog.csdn.net/villare/article/details/75045496)

1.首先我们继承默认的HttpClient父类,为了实现对上层的透明性,通过重写类的构造方法,完成对HttpClient的配置;
 

public class SSLClient extends DefaultHttpClient{
    public SSLClient() throws Exception{
        super();
    }
}

2.由于Https为有状态的连接,所以首先需要设置上下文环境(Context),用于维护连接过程中的状态;Java提供与Https相关的Context类;

SSLContext ctx = SSLContext.getInstance("TLS");

3.由于我们需要忽略对证书的检查,所以需要实现X509TrustManager(证书信任管理器),重写器中的主要验证方法,达到忽略证书验证的目的;并配置到Context中

X509TrustManager tm = new X509TrustManager() { 
            //该方法检查客户端的证书,若不信任该证书则抛出异常 
            @Override  
            public void checkClientTrusted(X509Certificate[] chain,  
                    String authType) throws CertificateException {  
            }  
            //该方法检查服务器的证书,若不信任该证书同样抛出异常
            @Override  
            public void checkServerTrusted(X509Certificate[] chain,  
                    String authType) throws CertificateException {  
            }  
            //返回受信任的X509证书数组
            @Override  
            public X509Certificate[] getAcceptedIssuers() {  
                return null;  
            }  
        };  
//初始化Context
ctx.init(null, new TrustManager[]{tm}, null); 

4.由于Https的数据传输为加密传输,一般的socket传输不考虑数据是否加密,当然HttpClient提供了相关的实现,只需要创建对应的SocketFactory对象,并绑定对应的Context;

SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  

5.在当前HttpClient中注册Https模式,并绑定对应的SocketFactory;至此,通过此HttpCLient发送的Https请求就会使用当前SocketFactory和Context(包括其中的认证管理器);

ClientConnectionManager ccm = this.getConnectionManager();  
SchemeRegistry sr = ccm.getSchemeRegistry();  
sr.register(new Scheme("https", 8443, ssf)); 

6.在使用重写的SSLClient时,与普通的HttpClient一样;

HttpClient httpClient = new SSLClient(); 

2.2.检查认证Https客户端的实现
和忽略的方式唯一不同的是:证书认证管理器,如果忽略认证,我们在checkClientTrusted、checkServerTrusted和getAcceptedIssuers中都没有包含具体的验证逻辑或直接返回默认值;所以,如果需要验证证书,只需要在其中实现相应的逻辑即可,如果认证不通过,直接抛出CertificateException 异常即可,由于,证书不同,验证的方式也不同,具体的问题具体分析;