import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
public class MyX509TrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// TODO Auto-generated method stub
// 检查客户端证书
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// TODO Auto-generated method stub
// 检查服务器端证书
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
// 返回受信任的X509证书数组
return null;
}
}
X509证书信任管理器类
public static String httpPostUtil(String pathUrl, JSONObject content) {
boolean isHttps = true;
String strResult = "";
DataOutputStream out = null;
BufferedReader reader = null;
if(pathUrl.toLowerCase().startsWith("https:")){
isHttps = true;
}else{
isHttps = false;
}
if(isHttps){
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] { new MyX509TrustManager() }, new SecureRandom());
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
SSLSocketFactory ssf = ctx.getSocketFactory();
HttpsURLConnection httpsConn = null;
try{
URL url = new URL(pathUrl);
httpsConn = (HttpsURLConnection) url.openConnection();
httpsConn.setSSLSocketFactory(ssf);
httpsConn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
httpsConn.setRequestMethod("POST");
httpsConn.setDoInput(true);
httpsConn.setDoOutput(true);
httpsConn.setConnectTimeout(6000);
httpsConn.setReadTimeout(6000);
httpsConn.setRequestProperty("Connection", "keep-alive"); //设置连接的状态
httpsConn.setRequestProperty("Transfer-Encoding", "chunked");//设置传输编码
httpsConn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
out = new DataOutputStream(httpsConn.getOutputStream());
out.write(content.toString().getBytes("UTF-8"));
out.flush();
out.close();
StringBuffer stringbuffer = new StringBuffer();
if (httpsConn.getResponseCode()==200){
reader = new BufferedReader(new InputStreamReader(httpsConn.getInputStream()));
String line="";
while ((line = reader.readLine()) != null) {
stringbuffer.append(line);
}
strResult = stringbuffer.toString();
reader.close();
}else{
}
httpsConn.disconnect();
}catch (Exception e) {
// TODO: handle exception
if(httpsConn!=null){
httpsConn.disconnect();
}
}
}else{
URL postUrl = null;
HttpURLConnection connection = null;
try {
postUrl = new URL(pathUrl);
connection = (HttpURLConnection) postUrl.openConnection();
connection.setDoOutput(true);// http正文内,因此需要设为true, 默认情况下是false;
connection.setDoInput(true);
connection.setConnectTimeout(6000);
connection.setReadTimeout(6000);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "keep-alive");
connection.setRequestProperty("Transfer-Encoding", "chunked");
connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
out = new DataOutputStream(connection.getOutputStream());
out.write(content.toString().getBytes("UTF-8"));
out.flush();
out.close();
StringBuffer stringbuffer = new StringBuffer();
if (connection.getResponseCode()==200){
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line="";
while ((line = reader.readLine()) != null) {
stringbuffer.append(line);
}
strResult = stringbuffer.toString();
reader.close();
}else{
}
connection.disconnect();
} catch (MalformedURLException e4) {
// TODO Auto-generated catch block
e4.printStackTrace();
if(connection!=null){
connection.disconnect();
}
}catch (IOException e3) {
e3.printStackTrace();
if(connection!=null){
connection.disconnect();
}
}
}
logger.info("strResult="+strResult);
return strResult;
}
生成证书
1:什么是HTTPS?
HTTPS其实是有两部分组成:HTTP + SSL / TLS,
也就是在HTTP上又加了一层处理加密信息的模块,并且会进行身份的验证。
问题:
Firebug和postman之类的浏览器调试工具,为什么获取到的是明文?
解答:
SSL是对传输的数据进行加密,针对的是传输过程的安全。
firebug之类的浏览器调试工具,
因为他们得到的是客户端加密之前/解密之后的数据,因此是明文的。
2:什么是自签名证书?
就是自己生成的证书,并不是官方生成的证书。
除非是很正式的项目,否则使用自己签发的证书即可,因为官方生成证书是要花钱滴。
使用JDK自带工具KeyTool 生成自签发证书!
第一步:为服务器生成证书
需要使用jdk自带的keytool来生成证书,如果已配置java环境变量,在任何目录启动命令行输入以下命令即可,若未配置java环境变量,则需要到jdk安装目录bin文件夹下启动命令行;
使用keytool命令生成证书:
keytool
-genkey
-alias tomcat(别名)
-keypass 123456(别名密码)
-keyalg RSA(算法)
-keysize 1024(密钥长度)
-validity 365(有效期,天单位)
-keystore c:/tomcat.keystore(指定生成证书的位置和证书名称)
-storepass 123456(获取keystore信息的密码)
C:\Program Files\Java\jdk1.7.0_75\bin>keytool -genkey -alias appsys -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -keystore c:/cer/appsys.keystore -storepass 123456
您的名字与姓氏是什么?
[Unknown]: test
您的组织单位名称是什么?
[Unknown]: test
您的组织名称是什么?
[Unknown]: test
您所在的城市或区域名称是什么?
[Unknown]: sz
您所在的省/市/自治区名称是什么?
[Unknown]: gd
该单位的双字母国家/地区代码是什么?
[Unknown]: china
CN=webcm, OU=webcm, O=webcm, L=sz, ST=gd, C=china是否正确?
[否]: y
第二步:为客户端生成证书
为浏览器生成证书,以便让服务器来验证它。
为了能将证书顺利导入至IE和Firefox,证书格式应该是PKCS12,
因此,使用如下命令生成:
keytool
-genkey
-alias client
-keypass 123456
-keyalg RSA
-storetype PKCS12
-keypass 123456
-storepass 123456
-keystore c:/client.p12
C:\Program Files\Java\jdk1.7.0_75\bin>keytool -genkey -alias appclient -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -storetype PKCS12 -keystore c:/cer/appclient.p12 -storepass 123456
您的名字与姓氏是什么?
[Unknown]: test
您的组织单位名称是什么?
[Unknown]: test
您的组织名称是什么?
[Unknown]: test
您所在的城市或区域名称是什么?
[Unknown]: sz
您所在的省/市/自治区名称是什么?
[Unknown]: gd
该单位的双字母国家/地区代码是什么?
[Unknown]: china
CN=webcm, OU=webcm, O=webcm, L=sz, ST=gd, C=china是否正确?
[否]: y
第三步:让服务器信任客户端证书
1、
由于不能直接将PKCS12格式的证书库导入,
必须先把客户端证书导出为一个单独的CER文件,使用如下命令:
keytool -export -alias appclient -keystore c:/cer/appclient.p12 -storetype PKCS12 -keypass 123456 -file c:/cer/appclient.cer
注意:
Keypass:指定CER文件的密码,但会被忽略,而要求重新输入
2、
将该文件导入到服务器的证书库,添加为一个信任证书:
keytool -import -v -file c:/cer/appclient.cer -keystore c:/cer/appsys.keystore -storepass 123456
完成之后通过list命令查看服务器的证书库,
可以看到两个证书,一个是服务器证书,一个是受信任的客户端证书:
keytool -list -v -keystore c:/cer/appsys.keystore
第四步:让客户端信任服务器证书
1、
由于是双向SSL认证,客户端也要验证服务器证书,
因此,必须把服务器证书添加到浏览器的“受信任的根证书颁发机构”。
由于不能直接将keystore格式的证书库导入,
必须先把服务器证书导出为一个单独的CER文件,使用如下命令:
keytool -keystore c:/cer/appsys.keystore -export -alias appsys -file c:/cer/appserver.cer
2、
双击appserver.cer文件,按照提示安装证书,
将证书填入到“受信任的根证书颁发机构”。
填入方法:
打开浏览器 - 工具 - internet选项-内容- 证书-把中级证书颁发机构里的www.localhost.com(该名称即时你前面生成证书时填写的名字与姓氏)证书导出来-再把导出来的证书导入 受信任的根颁发机构 就OK了。
步骤五:配置Tomcat服务器
<Connector port="8081" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true"
scheme="https" secure="true" clientAuth="false" sslProtocol="TLS"
keystoreFile="/home/apache-tomcat/te.keystore" keystorePass="123456"
truststoreFile="/home/apache-tomcat/te.keystore"
truststorePass="123456" connectionTimeout="20000"
redirectPort="8443" useBodyEncodingForURI="true" URIEncoding="UTF-8" />
属性说明:
clientAuth:设置是否双向验证,默认为false,设置为true代表双向验证
keystoreFile:服务器证书文件路径
keystorePass:服务器证书密码
truststoreFile:用来验证客户端证书的根证书,此例中就是服务器证书
truststorePass:根证书密码
注意:
① 设置clientAuth属性为True时,需要手动导入客户端证书才能访问。
② 要访问https请求 需要访问8443端口,访问http请求则访问Tomcat默认端口(你自己设置的端口,默认8080)即可。
同时也支持http需要再加上下面配置:
<Connector
port="8082"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" useBodyEncodingForURI="true" URIEncoding="UTF-8" />
然后重启tomcat,使用http,https访问成功。
小知识:
强制 https 访问
在 tomcat /conf/web.xml 中的 </welcome- file-list> 后面加上这
<login-config>
<!-- Authorization setting for SSL -->
<auth-method>CLIENT-CERT</auth-method>
<realm-name>Client Cert Users-only Area</realm-name>
</login-config>
<security-constraint>
<!-- Authorization setting for SSL -->
<web-resource-collection >
<web-resource-name >SSL</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
完成以上步骤后,在浏览器中输入http的访问地址也会自动转换为https
如不能访问,先查看端口是否被禁用了。
注:浏览器不能同时访问HTTP,HTTPS,需要关闭浏览器后再访问另地址。