數字證書在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.         瀏覽器打開應用登錄頁面,里面包含一個被簽名的隨機數,隨機數在應用服務器端產生,記作R S
2.         瀏覽器調用Ekey對R S進行簽名
3.         Ekey返回對R S的簽名,記作S S2_C(R S)
4.         瀏覽器提交表單,里面包含用戶證書SCert C和簽名S S2_C(R S),並用PKCS#7的SignedData封裝
5.         應用服務器把R S和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認證失敗


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM