基於SSL的https如何進行雙方驗證?咱們能夠參考 一樣基於SSL的SSH的驗證過程 html
參考百度百科 SSH java
依靠密匙,也就是你必須爲本身建立一對密匙-公鑰,並把公匙放在須要訪問的服務器上。如你要鏈接到SSH服務器上,客戶端軟件就會向服務器發出請求,請求用你的密匙進行安全驗證。服務器收到請求以後,先在該服務器上你的主目錄下尋找你的公用密匙,而後把它和你發送過來的公用密匙進行比較。若是兩個密匙一致,服務器就用公用密匙加密「質詢」(challenge)並把它發送給客戶端軟件。客戶端軟件收到「質詢」以後就能夠用你的私人密匙解密再把它發送給服務器。 web
非對稱加密算法中 公鑰用來加密 私鑰用來解密 算法
首先要 確立幾個概念 apache
keyStore 、證書、密鑰 瀏覽器
keyStore(java鍵庫) 是 由java的keytool命令生成的,鍵庫是一個用來集中存放 私鑰公鑰的地方 tomcat
在keystore裏,包含兩種數據: 安全
(1)密鑰實體(Key entity):密鑰(secret key)又或者是私鑰和配對公鑰(採用非對稱加密)
(2)可信任的證書實體(trusted certificate entries):只包含公鑰,別人的公鑰 服務器
Java KeyStore的類型常見的包括了 JKS, JCEKS, PKCS12, BKS,UBER 測試
JKS是默認的類型
咱們開始動手利用keytool生成相關私鑰和證書了
一、生成服務器證書庫(CN=127.0.0.1 這個 域 須要是server被訪問的地址)
keytool -validity 365 -genkey -v -alias server -keyalg RSA -keystore D:\ssl\server.keystore -dname "CN=127.0.0.1" -storepass 123456 -keypass 123456
二、生成客戶端證書庫
keytool -validity 365 -genkeypair -v -alias client -keyalg RSA -storetype PKCS12 -keystore D:\ssl\client.p12 -dname "CN=client" -storepass 123456 -keypass 123456
三、從客戶端證書庫中導出客戶端證書
keytool -export -v -alias client -keystore D:\ssl\client.p12 -storetype PKCS12 -storepass 123456 -rfc -file D:\ssl\client.cer
4、從服務器證書庫中導出服務器證書
keytool -export -v -alias server -keystore D:\ssl\server.keystore -storepass 123456 -rfc -file D:\ssl\server.cer
5、生成客戶端信任證書庫(由服務端證書生成的證書庫)
keytool -import -v -alias server -file D:\ssl\server.cer -keystore D:\ssl\client.truststore -storepass 123456
6、將客戶端證書導入到服務器證書庫(使得服務器信任客戶端證書)
keytool -import -v -alias client -file D:\ssl\client.cer -keystore D:\ssl\server.keystore -storepass 123456
7、查看證書庫中的所有證書
keytool -list -keystore D:\ssl\server.keystore -storepass 123456
如今咱們來看看咱們生成了哪些文件:
client.p12 (客戶端的keyStore,它的storetype 是 PKCS12) client.truststore(客戶端keyStore 存放了server端的公鑰 server.cer) client.cer (客戶端公鑰)
server.keystore(服務端keyStore 存放了client.cer 和本身的私鑰) server.cer (server 端公鑰)
涉及keytool有幾個關鍵命令參數解釋一下:-genkeypair 生成密鑰對 你能夠理解爲 雖然公鑰私鑰都生成了 可是 list查看 keyStore顯示的是私鑰 你要使用公鑰須要命令 -export 產生 .cer文件,而導出的公鑰須要 -import 命令導入到別人的keyStore裏
簡單的記憶就是keyStore裏存放的是本身的私鑰 和 導入的別人的公鑰 (受信任的別人),從keyStore中也能夠生成本身的公鑰
-storepass 指定了 keyStore的密碼,-keypass 指定了生成的那一條私鑰的密碼
接下來修改 服務器端,實現https與servlet代碼無關,與java web容器有關,以tomcat爲例
修改 {tomcat}/conf/server.xml,找到Connector port="8443"的標籤,取消註釋,並修改
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS" keystoreFile="D:\ssl\server.keystore" keystorePass="123456" truststoreFile="D:\ssl\server.keystore" truststorePass="123456"/>
幾個修改點注意 protocol修改成org.apache.coyote.http11.Http11NioProtocol 避免了配置APR相關
clientAuth="true" 使得 server端 對 client端來的請求進行驗證
sslProtocol="TLS" 指明瞭採用TLS做爲SSL實現的具體協議(參考TLS和SSL的關係)
keystoreFile 和 truststoreFile 指明keyStore
而後編寫servlet代碼例子測試下,其中還額外指明瞭如何獲取證書信息(clientAuth="true" server已經對client進行驗證了,只有被server信任的client才能握手成功)
package com.icesoft.servlet; import java.io.IOException; import java.io.PrintWriter; import java.security.cert.X509Certificate; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * <p> * SSL Servlet * </p> * * @author IceWee * @date 2012-6-4 * @version 1.0 */ public class SSLServlet extends HttpServlet { private static final long serialVersionUID = 1601507150278487538L; private static final String ATTR_CER = "javax.servlet.request.X509Certificate"; private static final String CONTENT_TYPE = "text/plain;charset=UTF-8"; private static final String DEFAULT_ENCODING = "UTF-8"; private static final String SCHEME_HTTPS = "https"; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); response.setCharacterEncoding(DEFAULT_ENCODING); PrintWriter out = response.getWriter(); X509Certificate[] certs = (X509Certificate[]) request.getAttribute(ATTR_CER); if (certs != null) { int count = certs.length; out.println("共檢測到[" + count + "]個客戶端證書"); for (int i = 0; i < count; i++) { out.println("客戶端證書 [" + (++i) + "]: "); out.println("校驗結果:" + verifyCertificate(certs[--i])); out.println("證書詳細:\r" + certs[i].toString()); } } else { if (SCHEME_HTTPS.equalsIgnoreCase(request.getScheme())) { out.println("這是一個HTTPS請求,可是沒有可用的客戶端證書"); } else { out.println("這不是一個HTTPS請求,所以沒法得到客戶端證書列表 "); } } out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } /** * <p> * 校驗證書是否過時 * </p> * * @param certificate * @return */ private boolean verifyCertificate(X509Certificate certificate) { boolean valid = true; try { certificate.checkValidity(); } catch (Exception e) { e.printStackTrace(); valid = false; } return valid; } }
若是咱們給瀏覽器安裝了client.p12,就能經過瀏覽器訪問server了 https://127.0.0.1:8443/ssl
咱們若是須要本身編寫代碼 以https的方式訪問server應該如何實現呢?這裏以apache的http client做爲示例
KeyStore myKey=KeyStore.getInstance("pkcs12"); myKey.load(new FileInputStream("d:/ssl/client.p12"),"123456".toCharArray()); KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType()); myTrustStore.load(new FileInputStream("d:/ssl/client.truststore"),"123456".toCharArray()); SSLContext sslContext = SSLContexts.custom() .useTLS() .loadKeyMaterial(myKey,"123456".toCharArray()) .loadTrustMaterial(myTrustStore) .build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext); CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslsf).build(); HttpGet get = new HttpGet(); get.setURI(new URI("https://127.0.0.1:8443/ssl")); CloseableHttpResponse response = client.execute(get); ByteArrayOutputStream out = new ByteArrayOutputStream(); response.getEntity().writeTo(out); System.out.println(new String(out.toByteArray(),"utf8")); out.close(); response.close();
useTLS 指明瞭所使用的協議類型 、
loadKeyMaterial(myKey,"123456".toCharArray()) 加載client的私鑰,注意這裏的123456不是keyStore的密碼 而是私鑰的密碼 由-keypass 123456指定的 ,也就是keyStore有一個密碼 而這個store內每一條密鑰還能夠指定單獨密碼 、
loadTrustMaterial 加載受信任的證書 包含server的公鑰
整個過程打通,經過https 來實現接口 1,能夠利用http協議自己的成熟簡單 開發成本低。2 https的數據傳輸過程是被保護的,數據不會被截取。3 能夠經過控制 server端的 受信任證書庫 keyStore 添加或刪除 公鑰來控制訪問方的訪問權限
參考
(全程參考)http://www.blogjava.net/icewee/archive/2012/06/04/379947.html
(java keytool命令總結)http://gwh-08.iteye.com/blog/1779667
(TLS和SSL的關係)http://www.360doc.com/content/09/1231/02/495229_12346441.shtml
(不一樣格式的keyStore)http://blog.chinaunix.net/uid-15473693-id-87588.html