ice world

          There is nothing too difficult if you put your heart into it.
          posts - 104, comments - 103, trackbacks - 0, articles - 0

          Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)

          Posted on 2012-06-04 17:36 IceWee 閱讀(32931) 評論(22)  編輯  收藏 所屬分類: JavaTomcat
          SSL——Secure Sockets Layer

          雙向認(rèn)證(個人理解):
          客戶端認(rèn)證:
          客戶端通過瀏覽器訪問某一網(wǎng)站時,如果該網(wǎng)站為HTTPS網(wǎng)站,瀏覽器會自動檢測系統(tǒng)中是否存在該網(wǎng)站的信任證書,如果沒有信任證書,瀏覽器一般會拒絕訪問,IE會有一個繼續(xù)訪問的鏈接,但地址欄是紅色,給予用戶警示作用,即客戶端驗證服務(wù)端并不是強制性的,可以沒有服務(wù)端的信任證書,當(dāng)然是否繼續(xù)訪問完全取決于用戶自己。如何去除地址欄的紅色警告呢?后續(xù)會介紹導(dǎo)入服務(wù)端證書到瀏覽器的方法。

          服務(wù)端認(rèn)證:
          服務(wù)端需要獲取到客戶端通過瀏覽器發(fā)送過來的認(rèn)證證書,該證書在服務(wù)端的證書庫中已存在,僅僅是個匹配過程,匹配成功即通過認(rèn)證,可繼續(xù)訪問網(wǎng)站資源,反之則無法顯示網(wǎng)頁,后續(xù)有截圖。

          基本邏輯:
          1、生成服務(wù)端密鑰庫并導(dǎo)出證書;
          2、生成客戶端密鑰庫并導(dǎo)出證書;
          3、根據(jù)服務(wù)端密鑰庫生成客戶端信任的證書;
          4、將客戶端證書導(dǎo)入服務(wù)端密鑰庫;
          5、將服務(wù)端證書導(dǎo)入瀏覽器。

          構(gòu)建演示系統(tǒng)
          演示環(huán)境:
          JDK:1.6.0_32
          Tomcat:apache-tomcat-7.0.27
          開發(fā)工具:MyEclipse 10
          瀏覽器:Internet Explorer 9

          一、生成密鑰庫和證書
          可參考以下密鑰生成腳本,根據(jù)實際情況做必要的修改,其中需要注意的是:服務(wù)端的密鑰庫參數(shù)“CN”必須與服務(wù)端的IP地址相同,否則會報錯,客戶端的任意。
          key.script
          1、生成服務(wù)器證書庫

          keytool
          -validity 365 -genkey -v -alias server -keyalg RSA -keystore E:\ssl\server.keystore -dname "CN=127.0.0.1,OU=icesoft,O=icesoft,L=Haidian,ST=Beijing,c=cn" -storepass 123456 -keypass 123456


          2、生成客戶端證書庫

          keytool
          -validity 365 -genkeypair -v -alias client -keyalg RSA -storetype PKCS12 -keystore E:\ssl\client.p12 -dname "CN=client,OU=icesoft,O=icesoft,L=Haidian,ST=Beijing,c=cn" -storepass 123456 -keypass 123456


          3、從客戶端證書庫中導(dǎo)出客戶端證書

          keytool
          -export -v -alias client -keystore E:\ssl\client.p12 -storetype PKCS12 -storepass 123456 -rfc -file E:\ssl\client.cer


          4、從服務(wù)器證書庫中導(dǎo)出服務(wù)器證書

          keytool
          -export -v -alias server -keystore E:\ssl\server.keystore -storepass 123456 -rfc -file E:\ssl\server.cer


          5、生成客戶端信任證書庫(由服務(wù)端證書生成的證書庫)

          keytool
          -import -v -alias server -file E:\ssl\server.cer -keystore E:\ssl\client.truststore -storepass 123456


          6、將客戶端證書導(dǎo)入到服務(wù)器證書庫(使得服務(wù)器信任客戶端證書)

          keytool
          -import -v -alias client -file E:\ssl\client.cer -keystore E:\ssl\server.keystore -storepass 123456


          7、查看證書庫中的全部證書

          keytool
          -list -keystore E:\ssl\server.keystore -storepass 123456


          二、Tomat配置
          使用文本編輯器編輯${catalina.base}/conf/server.xml
          找到Connector port="8443"的標(biāo)簽,取消注釋,并修改成如下:
          <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true"
                         maxThreads
          ="150" scheme="https" secure="true"
                         clientAuth
          ="true" sslProtocol="TLS"
                         keystoreFile
          ="${catalina.base}/key/server.keystore" keystorePass="123456"
                         truststoreFile
          ="${catalina.base}/key/server.keystore" truststorePass="123456"/>

          備注:
          keystoreFile:指定服務(wù)器密鑰庫,可以配置成絕對路徑,如“D:/key/server.keystore”,本例中是在Tomcat目錄中創(chuàng)建了一個名稱為key的文件夾,僅供參考。
          keystorePass:密鑰庫生成時的密碼
          truststoreFile:受信任密鑰庫,和密鑰庫相同即可
          truststorePass:受信任密鑰庫密碼

          三、建立演示項目
          項目結(jié)構(gòu)圖:
          項目名稱:SSL(隨意)


          SSLServlet.java
          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(
          "校驗結(jié)果:" + verifyCertificate(certs[--i]));
                          out.println(
          "證書詳細(xì):\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;
              }


          }


          web.xml
          說明:該演示項目強制使用了SSL,即普通的HTTP請求也會強制重定向為HTTPS請求,配置在最下面,可以去除,這樣HTTP和HTTPS都可以訪問。
          <?xml version="1.0" encoding="UTF-8"?>
          <web-app version="3.0"
              xmlns
          ="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi
          ="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation
          ="http://java.sun.com/xml/ns/javaee
              http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
          >
               
          <display-name>Secure Sockets Layer</display-name>   
             
             
          <servlet>
                 
          <servlet-name>SSLServlet</servlet-name>
                 
          <servlet-class>com.icesoft.servlet.SSLServlet</servlet-class>
             
          </servlet>
             
          <servlet-mapping>
                 
          <servlet-name>SSLServlet</servlet-name>
                 
          <url-pattern>/sslServlet</url-pattern>
             
          </servlet-mapping>
             
             
          <welcome-file-list>
               
          <welcome-file>index.jsp</welcome-file>
             
          </welcome-file-list>

             
          <!-- 強制SSL配置,即普通的請求也會重定向為SSL請求 --> 
             
          <security-constraint>
                 
          <web-resource-collection>
                     
          <web-resource-name>SSL</web-resource-name>
                     
          <url-pattern>/*</url-pattern><!-- 全站使用SSL -->
                 
          </web-resource-collection>
                 
          <user-data-constraint>
                     
          <description>SSL required</description>
                     
          <!-- CONFIDENTIAL: 要保證服務(wù)器和客戶端之間傳輸?shù)臄?shù)據(jù)不能夠被修改,且不能被第三方查看到 -->
                     
          <!-- INTEGRAL: 要保證服務(wù)器和client之間傳輸?shù)臄?shù)據(jù)不能夠被修改 -->
                     
          <!-- NONE: 指示容器必須能夠在任一的連接上提供數(shù)據(jù)。(即用HTTP或HTTPS,由客戶端來決定)-->
                     
          <transport-guarantee>CONFIDENTIAL</transport-guarantee>
                 
          </user-data-constraint>
             
          </security-constraint>
          </web-app>


          index.jsp
          <%@ page language="java" pageEncoding="UTF-8"%>

          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
          <html>
          <head>
          <title>客戶端證書上傳</title>
          <meta http-equiv="pragma" content="no-cache">
          <meta http-equiv="cache-control" content="no-cache">
          <meta http-equiv="expires" content="0">   
          </head>
          <body>
          <form action="${pageContext.request.contextPath}/sslServlet" method="post">
             
          <input type="submit"  value="提交證書"/>
          </form>
          </body>
          </html>


          四、演示及配置
          發(fā)布演示項目,通過瀏覽器訪問:http://127.0.0.1:8080/SSLhttps://127.0.0.1:8443/SSL,得到相同的結(jié)果,如圖:






          得到如上結(jié)果的原始是因為客戶端沒有通過服務(wù)端的安全認(rèn)證,接下來將服務(wù)端給客戶端頒發(fā)的證書導(dǎo)入到瀏覽器中:
          雙擊“client.p12”



          彈出窗口,下一步



          默認(rèn),下一步



          輸入生成密鑰時的密碼“123456”,下一步



          下一步



          完成



          成功



          再次訪問http://127.0.0.1:8080/SSLhttps://127.0.0.1:8443/SSL,彈出提示框:



          點擊確定后,IE瀏覽器自動阻止了繼續(xù)訪問,并給予警告提示,原因是瀏覽器中未導(dǎo)入該網(wǎng)站的可信證書





          點擊“繼續(xù)瀏覽此網(wǎng)站”,彈出提示,點擊確定



          哇!鮮紅的地址欄,夠醒目吧!你訪問的網(wǎng)站不安全那,親!



          點擊“提交證書”按鈕,返回正確結(jié)果!



          可以看出,客戶端并沒有服務(wù)端那么嚴(yán)格,只要未通過驗證就甭想訪問,下面將服務(wù)端生成的信任證書導(dǎo)入到瀏覽器的根證書中,這樣紅色的地址欄就會消失了!
          開始導(dǎo)入服務(wù)端信任證書,不能雙擊“server.cer”,需要手動導(dǎo)入到受信任的根證書機構(gòu)中去。



          瀏覽器Internet選項-內(nèi)容-證書



          點擊“受信任的根證書頒發(fā)機構(gòu)”



          點擊“導(dǎo)入”



          下一步



          手動選擇“server.cer”,下一步






          下一步



          完成



          點“是”




          成功





          可以看到我們剛剛導(dǎo)入的根證書



          把所有瀏覽器窗口都關(guān)掉,再次訪問網(wǎng)站,發(fā)現(xiàn)鮮紅色已經(jīng)逝去



          點擊“提交證書”按鈕,一切正常了,雙向認(rèn)證的DEMO結(jié)束了!





          全文完!

          Feedback

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2012-08-18 17:54 by 愛學(xué)習(xí)的豬
          你好!我是這篇文章的讀者,我也是按照上面的方法配置好了tomcat,當(dāng)我再次訪問http://127.0.0.1:8080/SSL或https://127.0.0.1:8443/SSL,彈出提示框,點擊確定后,不是進(jìn)入的IE瀏覽器自動阻止了繼續(xù)訪問頁面,而是進(jìn)入了網(wǎng)頁無法訪問頁面,這是怎么了呢?謝謝解答

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2012-09-07 10:04 by Jakey
          請問第5步中生成的 client.truststore 這個文件有什么用?

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2012-09-07 18:13 by IceWee
          @愛學(xué)習(xí)的豬
          你的瀏覽器沒有導(dǎo)入證書,所以直接就被拒絕了,客戶端不信任服務(wù)端,被瀏覽器自動阻止了

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2012-09-07 18:13 by IceWee
          @Jakey
          讓客戶端信任服務(wù)端的證書

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2012-11-20 17:50 by redocde
          看了N多的雙向配置SSL的教程,都是抄襲來抄襲去的,還是樓主的可用,一次成功.thanks

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2012-11-20 17:57 by redocde
          第五步是必須的嗎?將服務(wù)端證書導(dǎo)入到信任庫中,沒看懂什么意思.

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2012-11-21 09:59 by IceWee
          @redocde
          是的,并不是必須的,只是會有警示提示而已

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2012-12-24 21:30 by Francis
          你好,我照著你的這個做,成功了,表示感謝。
          不過我有一些問題,你在最開始提到的服務(wù)器和客戶端發(fā)來的證書做匹配,如果匹配不成功則不顯示頁面,這點沒見你的demo里面有,請問這點您做到了嗎?是在程序里面做還是修改服務(wù)器的一些配置?這點很好奇,如有結(jié)果希望您能答復(fù)一下

          另外還有一個小問題,就是客戶端的證書可以和IP綁定嗎?如果安全措施周全點的話會希望客戶端的證書只能是在指定IP上面使用,并不是所有客戶端都可以用一個證書。
          603005981@qq.com

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)[未登錄]  回復(fù)  更多評論   

          2013-04-12 14:16 by cc
          您好:
          樓主的語文水平真是高. 思路清晰、講解到位。肯定是大師級任務(wù)。
          請教老師一個問題:按照你演示demo操作配置 ,如果有了證書,以后的客戶端和服務(wù)端的數(shù)據(jù)交互就是安全的嗎?
          qq: 752184245@qq.com

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)[未登錄]  回復(fù)  更多評論   

          2013-05-20 16:31 by Sam
          最近在做一個需要證書和account&password共同驗證的一個功能,看了你的文章表示懂了很多,但還是有很多疑問,大師能加我QQ嗎?我相信以后我也會寫一篇類似文章去幫助更多的人。謝謝了。QQ:176128341

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2013-07-20 21:24 by 炮哥
          非常不錯。非常感謝

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2013-08-04 20:20 by landor
          非常詳細(xì),完全copy就通過,非常感謝!

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2013-11-21 16:43 by sfw
          你好,按照您的方式確實能成功,但是我現(xiàn)在想改成用IP地址訪問,是不是只要修改服務(wù)端證書的CN=127.0.0.1為本機IP地址?我改為CN=192.168.0.11后測試不成功,彈出兩次確認(rèn)證書界面后,直接跳到網(wǎng)頁無法訪問的界面

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2013-11-21 17:17 by sfw
          找到問題了,把IE重置就可以了,估計是之前有做過設(shè)置@sfw

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2013-12-16 10:56 by 張國印
          數(shù)據(jù)在傳輸過程中用的什么加密算法,如何查看呢?如果用的是對稱加密算法,加密秘鑰存儲在哪里呢?

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)[未登錄]  回復(fù)  更多評論   

          2014-04-24 18:16 by deng
          按照你的方法,果然成功了!非常感謝!

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2014-06-05 23:01 by jianzao
          你好,按照您的文章能看懂這個SSL配置,只是按你的測試項目運行時,進(jìn)入servlet里,X509Certificate[] certs = (X509Certificate[]) request.getAttribute(ATTR_CER); certs的值總是為null,真不知道是什么原因.
          跪求解救!

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2014-09-06 11:49 by 1111
          技術(shù)貼,大贊一個

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)[未登錄]  回復(fù)  更多評論   

          2015-03-24 16:16 by liu
          @jianzao
          tomcat 里的server.xml有一個屬性clientAuth="false" 改為true

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)  回復(fù)  更多評論   

          2015-12-12 17:11 by shiguang0122
          步驟清除,講解清晰,常見錯誤解釋明白。
          由于以前不成功的嘗試,頁面總是打不開,后來看評論,重置瀏覽器,就可以了。

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)[未登錄]  回復(fù)  更多評論   

          2016-04-06 11:27 by luo
          牛掰,謝謝啦,辛苦了

          # re: Java Tomcat SSL 服務(wù)端/客戶端雙向認(rèn)證(一)[未登錄]  回復(fù)  更多評論   

          2016-04-28 17:31 by su
          謝謝分享
          主站蜘蛛池模板: 定南县| 子洲县| 波密县| 竹溪县| 宁安市| 大悟县| 平凉市| 乌恰县| 长治县| 都兰县| 斗六市| 安阳市| 徐汇区| 会宁县| 琼结县| 临沂市| 泽普县| 怀宁县| 会理县| 繁峙县| 会同县| 印江| 福安市| 开江县| 新闻| 安吉县| 东兰县| 察雅县| 任丘市| 积石山| 漠河县| 天长市| 青岛市| 韶山市| 慈利县| 汶上县| 靖宇县| 青海省| 北碚区| 新泰市| 阿巴嘎旗|