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,需要關閉浏覽器後再通路另位址。