1. 程式人生 > >數字證書在WEB應用中實現登陸

數字證書在WEB應用中實現登陸

1數字證書登入認證的優點

作為企業資訊系統的第一道大門,身份認證是確保企業資訊資源只能被合法使用者所訪問的重要保障。 傳統的口令認證方式雖然簡單,但是由於其易受到竊聽、重放等攻擊的安全缺陷,使其已無法滿足當前複雜網路環境下的安全認證需求。 傳統賬號+口令登入的弊端: 1.         口令易被猜測。由於有的使用者為了方便記憶,使用非常簡單的口令,比如“1234”、“abcd”等這些非常容易被猜測的口令。 2.         口令易被竊聽。大家都知道,WEB應用在網際網路上是基於TCP/IP協議的,該協議本身並不負責資料傳輸的安全性,使用者口令在網際網路上的傳輸,需要經過很多個網路節點(比如路由器),可以在這任意一個網路節點去竊聽到使用者的口令。 3.         口令記憶麻煩。使用者在不同的WEB應用上建立不同的帳戶,需要記憶不同的口令,記憶這麼多的口令形成使用者很大的負擔,於是有的使用者把不同WEB應用的口令設定成相同的口令,這樣又引入了新的安全隱患,只需破解使用者的一個WEB口令,就等於破解了該使用者別的WEB應用口令。 4.         可以從伺服器攻擊客戶口令。WEB應用服務上,由於需要校驗使用者的口令,所以需要保留使用者的口令或口令的摘要值。若這個使用者口令表被黑客非法獲取,整個WEB應用的使用者認證將形同虛設。 5.         無法確定使用者的真實身份。正因為口令的脆弱性,使得口令很容易被竊用。 隨著PKI技術體系的成熟,擁有強有力的理論基礎和眾多國際標準的CA數字證書身份認證技術,在法律上得到了國家的大力支援。電子簽名法的頒佈實施以及數字加密和數字簽名技術所具有的保密性、完整性、真實性、不可否認性等特點,使得CA數字證書身份認證正在被廣泛採用。 作為個人數字證書及其對應私鑰的儲存介質的USBkey、IC卡等,在此統稱為eKey(電子金鑰),自帶CPU,內嵌加密演算法,可進行加密運算,其中的私密資訊不可複製。因此,eKey以其安全可靠、易於攜帶、使用方便、成本低廉、價效比高等特點,在身份認證領域也正發揮著越來越多的作用,成為身份認證技術的一個重要發展方向和趨勢。 引進eKey+數字證書登入帶來的好處: 1.         安全。雙因子認證。使用者在使用eKey之前,需要輸入PIN碼驗證;驗證通過後再呼叫eKey裡的私鑰作用於身份認證用的簽名運算。這樣就等於設定了2道門,都通過後才能最終進入。 2.         方便。使用者只需隨身攜帶一個eKey,就可不限時間、不限地點的證明自己的身份。可以用同一個eKey登入不同的Web站點而不怕安全問題。 3.         使用者身份具有法律保障。使用者的數字證書由權威的CA簽發。使用者的登入認證可以保留日誌用於以後追溯,即可防偽造又可防抵賴。    2身份認證原理
2.1數字簽名 signature 數字簽名的產生和驗證過程: 1.         Alice產生檔案的單向雜湊值。 2.         Alice用她的私人金鑰對雜湊加密,以此表示對檔案的簽名。 3.         Alice將檔案和雜湊簽名送給Bob。 4.         Bob用Alice傳送的檔案產生檔案的單向雜湊值,同時用Alice的公鑰對簽名的雜湊解密。如果簽名的雜湊值與自己產生的雜湊值匹配,簽名是有效的。 數字簽名具有以下特性: 1.         完整性。因為它提供了一項用以確認電子檔案完整性的技術和方法,可認定檔案為未經更改的原件。 2.         可驗證性。可以確認電子檔案之來源.由於發件人以私鑰產生的電子簽章惟有與發件人的私鑰對應的公鑰方能解密,故可確認檔案之來源。 3.         不可否認性。由於只有發文者擁有私鑰,所以其無法否認該電子檔案非由其所傳送。   2.2身份認證
流程如下: authenticate   在實際的部署中,認證伺服器的功能可以在應用伺服器實現。 步驟說明: 1.         瀏覽器開啟應用登入頁面,裡面包含一個被簽名的隨機數,隨機數在應用伺服器端產生,記作RS 2.         瀏覽器呼叫Ekey對RS進行簽名 3.         Ekey返回對RS的簽名,記作SS2_C(RS) 4.         瀏覽器提交表單,裡面包含使用者證書SCertC和簽名SS2_C(RS),並用PKCS#7的SignedData封裝 5.         應用伺服器把RS和SignedData交給認證伺服器驗證 6.         認證伺服器解開SignedData裡面的簽名內容、使用者證書和資料簽名,比較簽名內容是否和RS相同,證書是否有效,簽名是否有效,若都有效,再查詢該證書對應的使用者ID。返回驗證成功訊息及使用者賬號 7.         應用伺服器返回登入成功頁面,給以該使用者賬號使用應用服務 該流程的優點是: l         挑戰-響應機制:客戶端在發起認證請求時,伺服器端首先產生並返回一個隨機數(挑戰);客戶端在提交認證請求時,將數字簽名後的隨機數傳送到伺服器端(響應),由伺服器端比較本地的隨機數和收到的隨機數,以校驗認證請求的有效性,從而有效防止截獲和重放攻擊。 l         數字簽名機制:客戶端提交的認證請求,均由客戶端認證元件呼叫eKey進行簽名處理。eKey隨身攜帶,其中的私鑰不可複製,保證了私鑰的唯一性,由於數字簽名不可偽造和篡改,伺服器端通過校驗客戶端使用者證書和數字簽名的有效性,並結合認證資料庫鑑別使用者身份。   3數字證書登入認證的實現
以下討論如何實現數字證書在Web應用中作登入認證。 3.1SSL方式 SSL在握手過程中,服務端接受客戶端證書 SSL的使用者端認證: ssl   CertificateRequest訊息指示客戶端要進行客戶端認證,並就伺服器願意接受的認證型別提供指導: struct{        ClientCertificateType certificate_types<1..2^8-1>;        DistinguishedName certificate_authorities<3..2^16-1>; }CertificateRequest; enmu{        rsa_sign(1),dss_sign(2),rsa_fixed_db(3),dss_fixed_dh(4),        (255) }ClientCertificateType; opaque DistinguishedName<1..2^16-1>; certificate_types指示支援哪種型別的客戶端證書。certificate_authorities指示伺服器願意接受哪些CA簽發的客戶端證書。 Certificate訊息是客戶端向服務端提交的表明身份的數字證書鏈,證書鏈的第一個證書就是表明使用者身份的數字證書。 struct{        ASN.1Cert certificate_list<1..2^4-1> }Certificate;   opaque ASN.1Cert<2^24-1>; CertificateVerify訊息用於真正的客戶端認證。它包含由客戶端私鑰簽名的訊息,簽名內容為自ClientHello到本訊息(不包含本訊息)所收發的所有握手訊息。且由於這些握手訊息帶有匯出主金鑰(master_secret)的隨機數,所以本訊息可以防止被重放。 struct {        Signature signature; } CertificateVerify; select (SignatureAlgorithm) {        case anonymous: struct { };        case rsa:               digitally-signed struct {                      opaque md5_hash[16];                      opaque sha_hash[20];               };        case dsa:               digitally-signed struct {                      opaque sha_hash[20];               }; } Signature; CertificateVerify.signature.md5_hash=MD5(handshake_messages); CertificateVerify.signature.sha_hash=SHA(handshake_messages);   3.1.1WEB伺服器設定 WEB伺服器設定成需要客戶端認證。 iis 需要首先在服務端和客戶端都安裝CA證書鏈,可以通過MMC控制檯對計算機帳戶受信任根證書進行新增 iis   tomcat 需要首先在服務端和客戶端都安裝CA證書鏈,可以在JDK目錄下的cacerts進行新增 修改c:/tomcat/conf/server.xml,新增如下內容: <Connector port="8443" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true" acceptCount="100" debug="0" scheme="https" secure="true" clientAuth="true" sslProtocol="TLS" keystoreFile="c:/server_keystore" keystorePass="changeit" truststoreFile="c:/trustcacerts_keystore" truststorePass="changeit" /> 3.1.2得到客戶端證書 當WEB伺服器設定成需要客戶端認證時,客戶端在建立SSL連結時會提交使用者證書鏈,證書鏈的第一個即是表明使用者身份的個人證書。 j2ee   <%@ page import="java.security.cert.X509Certificate" %> <% if(request.isSecure())     //判斷是否採用SSL {        final String attname= "javax.servlet.request.X509Certificate";        X509Certificate[] chain= (X509Certificate[])request.getAttribute(attname);//客戶證書鏈        if(chain == null)        {               out.println("沒有客戶端證書鏈");               return;        }        X509Certificate userCert= chain[0];     //客戶證書        …… } %>   .net c# <%@ Page Language="C#" %> <%@ Import Namespace="System.Security.Cryptography.X509Certificates"%> <% if(Request.IsSecureConnection) {     HttpClientCertificate hCert = Request.ClientCertificate;     if (hCert == null)     {            Response.Write("沒有客戶端證書");            return;     }     X509Certificate2 cert = new X509Certificate2();     try     {            cert.Import(hCert.Certificate);     }     catch (Exception e)     {            Response.Write(e.Message);            return;     }     ...... } %> 3.2表單方式 表單方式的原理是:伺服器產生一個隨機數;客戶端用數字證書對應的私鑰隨機數簽名,把隨機數、使用者證書、數字簽名以PKCS#7格式打包傳送到伺服器;伺服器再分析此PKCS#7資料包,得到簽名隨機數、使用者證書和數字簽名,再驗證這3個元素是否有效。 3.2.1客戶端 呼叫CAPICOM的JS指令碼(capicom.js) var CAPICOM_CURRENT_USER_STORE = 2; var CAPICOM_STORE_OPEN_READ_ONLY = 0; var CAPICOM_ENCODE_BASE64 = 0; var CAPICOM_ENCODE_BINARY = 1; var CAPICOM_INFO_SUBJECT_SIMPLE_NAME = 0; var CAPICOM_INFO_ISSUER_SIMPLE_NAME = 1; var CAPICOM_INFO_SUBJECT_EMAIL_NAME = 2; var CAPICOM_INFO_ISSUER_EMAIL_NAME = 3; function SelectMySignCert() {        //cert store        var mystore = new ActiveXObject("CAPICOM.Store");        mystore.Open(CAPICOM_CURRENT_USER_STORE,"My",CAPICOM_STORE_OPEN_READ_ONLY);        var certs= mystore.Certificates;        //myca sign certs //     var mycacerts= certs;        var mycacerts= new ActiveXObject("CAPICOM.Certificates");        for(i=1;i<=certs.Count;i++)        {               //check issuer               var issuer=certs.Item(i).IssuerName;         if(issuer.indexOf("CN=MYCA")<0)     //not myca                      continue;               //check key usage         var ku=certs.Item(i).KeyUsage();         if(!ku.IsDigitalSignatureEnabled)   //not sign cert                      continue;               //add               mycerts.Add(certs.Item(i));          }        if(mycerts.Count==0)        {               if(window.confirm("沒有找到MYCA簽發的證書,/r/n請插入相應的Ekey再按確定")==true)                      return SelectMySignCert();               else                      return null;        }        //select cert        var certsel= mycerts.Select("選擇證書","請選擇證書:",false);        if(certsel==null)return null;        var cert= certsel.Item(1); //     cert.Display();        return cert; } function SignText(strtext) {        //select cert        var mysigncert= SelectMySignCert();        if(mysigncert==null)return null;        //signed data        var signer = new ActiveXObject("CAPICOM.Signer");        signer.Certificate = mysigncert;        var signeddata = new ActiveXObject("CAPICOM.SignedData");        var utils = new ActiveXObject("CAPICOM.Utilities");        signeddata.Content = utils.BinaryStringToByteArray(strtext);        return signeddata.Sign(signer,false,CAPICOM_ENCODE_BASE64); } /* var signature= SignText("hello"); WScript.Echo(signature); */   登入頁面(login.aspx) <%@ Page Language="C#" %> <%        Random rnd = new Random();        byte[] buff = new byte[18];        rnd.NextBytes(buff);        string challenge = Convert.ToBase64String(buff);        Session["challenge"] = challenge; %> <html> <head> <title>登入頁面</title> <meta http-equiv="Content-Type" content="text/html; charset=GBK"> <script src="./capicom.js"></script> <script language="javascript"> function submitform() {        var signature= SignText("<%=challenge%>");        if(signature==null)return;        form1.passport.value= signature;        form1.submit(); } </script>   </head> <body> <object id="oCAPICOM"        codeBase=" http://download.microsoft.com/download/E/1/8/E18ED994-8005-4377-A7D7-0A8E13025B94/capicom.cab #version=2,0,0,3"        classid="clsid:A996E48C-D3DC-4244-89F7-AFA33EC60679"> </object> <form name="form1" action="verify.aspx" method="POST">        <input type="hidden" name="passport" value=""><br />        <input type="button" value="點選提交登入證書." onclick="submitform()"> </form> </body> </html> 3.2.2服務端 JDK1.5中自帶的JCE並不支援PKCS#7,.net framework是支援的。 登入判斷邏輯(verify.aspx) <%@ Page Language="C#" %> <%@ Import Namespace="System.Security.Cryptography.Pkcs"%> <%@ Import Namespace="System.Security.Cryptography.X509Certificates"%> <%        string challenge = (string)Session["challenge"];        Session["challenge"] = null;        if(challenge==null){               Response.Write("沒有隨機數");               return;        }        string p = Request.Form["passport"];        byte[] cmsDer = Convert.FromBase64String(p);        SignedCms cms = new SignedCms();        try{               cms.Decode(cmsDer);               cms.CheckSignature(true);        }catch(Exception e){               Response.Write(e.Message);               return;        }           string challenge2 = Encoding.Default.GetString(cms.ContentInfo.Content);        if (challenge.Equals(challenge2))        {               Response.Write("隨機數不匹配<br/>"); //            Response.Write(challenge + ":" + challenge2);               return;        }        Response.Write("登入成功");        return; %>

3數字證書與現有使用者帳戶的繫結

使用者用數字證書登入後。WEB應用提供一個帳戶繫結頁面,頁面提示使用者輸入原使用者名稱和口令。後臺再驗證使用者提交的使用者名稱和口令,通過驗證後,把該使用者/口令對應的使用者ID和使用者的登入證書摘要寫入到一個數據庫表。流程:

以後使用者使用該證書登入時,可以從資料庫表查詢到該證書對應的使用者ID,系統給以該使用者ID登入。

4一些有用的命令

關閉IIS的CRL檢查:cscript c:/inetpub/adminscripts/adsutil.vbs set /w3svc/certcheckmode 1

KB977377補丁導致IIS的雙向SSL認證失敗