一、數字簽名
1.1 數字簽名和非對稱加密的關係
實際上,數字簽名和非對稱加密有着非常緊密的聯繫,簡而言之,數字簽名就是通過將非對稱加密 “反過來用” 而實現的。下面我們來將密鑰的使用方式總結成一張表:
私鑰 | 公鑰 | |
---|---|---|
非對稱加密 | 接收者解密時使用 | 發送者加密時使用 |
數字簽名 | 簽名者生成簽名時使用 | 驗證着驗證簽名時使用 |
持有者 | 個人持有 | 任何人都可以持有 |
1.2 數字簽名的兩種方式
- 方式一:直接對消息簽名
由於非對稱加密算法本來就非常慢,所以使用方式一對消息進行加密會非常耗時,不推薦使用。 - 方式二:對消息散列值簽名
使用方式二,不必再對整個消息進行加密,而是隻要先用單向散列函數求出消息的散列值,然後再將散列值進行加密即可。無論消息多長,生成的散列值的長度都是固定不變得,因此在實際應用中推薦使用第二種方式。
1.3 數字簽名的使用步驟
這裏還是使用Alice和Bob的故事爲例,假設Alice向Bob發起匯款(如下圖)。
第一步:Alice使用單向散列函數計算出消息的散列值;
第二步:Alice用自己的私鑰對散列值進行加密(簽名);
第三步:Alice將消息和簽名發送給Bob;
第四步:Bob使用Alice公鑰將接收到的簽名進行解密,得到散列值1;
第五步:Bob使用單向散列函數對接收到的消息計算出散列值2;
第六步:Bob將散列值1和散列值2進行對比。如果兩個散列值相同,代表消息是由Alice發出;如果兩個散列值不相同,代表消息不是由Alice發出;
1.4 通過RSA實現數字簽名
-
數字簽名的實現步驟:
第一步:生成祕鑰對,保存到磁盤上;
第二步:準備原始數據;
第三步:其進行哈希運算,最終生成一個散列值;
第四步:使用非對稱加密的私鑰對散列值進行加密,這個加密過程就稱爲簽名;
第五步:把簽名和原始內容發送給對方; -
數據驗證的實現步驟:
第一步:接收原始數據和數字簽名;
第二步:對原始數據進行哈希運算,等到一個新的散列值;
第三步:使用公鑰對簽名進行解密,最終得到一個散列值;
第四步:比較兩個散列值,如果相等,則代表發送數據沒有被改動過;
示例代碼:
// 生成私鑰和公鑰
func generateKey() {
//============== 生成私鑰 =============
// 1.使用rsa中的GenerateKey方法生成私鑰
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
panic(err)
}
// 2.通過x509標準將得到的ras私鑰序列化爲ASN.1 的 DER編碼字符串
derText := x509.MarshalPKCS1PrivateKey(privateKey)
// 3.將私鑰字符串設置到pem格式塊中
block := pem.Block{
Type: "rsa private key",
Bytes: derText,
}
// 4.通過pem將設置好的數據進行編碼, 並寫入磁盤文件中
file, err := os.Create("private.pem")
if err != nil {
panic(err)
}
defer file.Close()
pem.Encode(file, &block)
//============== 生成公鑰 =============
// 1.從得到的私鑰對象中將公鑰信息取出
publicKey := privateKey.PublicKey
// 2.通過x509標準將得到 的rsa公鑰序列化爲字符串
derText, err = x509.MarshalPKIXPublicKey(&publicKey)
if err != nil {
panic(err)
}
// 3.將公鑰字符串設置到pem格式塊中
block = pem.Block {
Type: "rsa public key",
Bytes: derText,
}
// 4.通過pem將設置好的數據進行編碼, 並寫入磁盤文件
file, err = os.Create("public.pem")
if err != nil {
panic(err)
}
defer file.Close()
pem.Encode(file, &block)
}
// 讀取密鑰文件內容
func ReadKeyFile(keyFile string) []byte {
file, err := os.Open(keyFile)
if err != nil {
panic("公鑰文件不存在!")
}
defer file.Close()
fileInfo, err := file.Stat()
if err != nil {
panic("file.Stat err!")
}
buf := make([]byte, fileInfo.Size())
file.Read(buf)
return buf
}
// RSA簽名
func SignatureRSA(plainText []byte, priKeyFile string) []byte {
// 計算簽名內容進行哈希運算,得到一個散列值
res := sha512.Sum512(plainText)
// 讀取私鑰文件中的內容
buf := ReadKeyFile(priKeyFile)
// 使用pem解碼,得到pem.Block結構體
block, _ := pem.Decode(buf)
// 使用x509將數據解析成私鑰結構體,得到私鑰
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
panic("x509.ParsePKCS1PrivateKey err!")
}
// 使用rsa中的函數對散列值簽名
sigText, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA512, res[0:len(res)])
if err != nil {
panic("rsa.SignPKCS1v15 err!")
}
return sigText
}
// 簽名驗證
func VerifyRSA(plainText, sigText []byte, pubKeyFile string) bool {
// 對原始數據進行哈希運算,等到一個新的散列值
res := sha512.Sum512(plainText)
// 打開磁盤公鑰文件,將公鑰文件內容讀取出來
buf := ReadKeyFile(pubKeyFile)
// 使用pem解碼,得到pem.Block結構體
block, _ := pem.Decode(buf)
// 使用x509對pem.Block的bytes變量數據進行解析,得到一個接口
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic("x509.ParsePKIXPublicKey err!")
}
//進行類型斷言,得到公鑰
publicKey, ok := pub.(*rsa.PublicKey)
if !ok {
panic("pub is not a public key!")
}
// 通過rsa.VerifyPKCS1v15函數進行簽名認證
err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA512, res[:], sigText)
// 比較散列值
return err == nil
}
1.5 通過橢圓曲線實現數字簽名
橢圓曲線(英語:Elliptic curve cryptography,縮寫爲 ECC)在密碼學中的使用是在1985年由Neal Koblitz和Victor Miller分別獨立提出的。ECC的主要優勢是在某些情況下,它比其他加密算法使用更小的密鑰,提供更高的安全級別。ECC 164位的密鑰相當於RSA 1024位密鑰提供的保密強度,而且計算量更少,處理速度更快。目前我國居民二代身份證正在使用 256 位的橢圓曲線密碼,虛擬貨幣比特幣也選擇ECC作爲加密算法。
美國FIPS186-2標準, 推薦使用5個素域上的橢圓曲線, 這5個素數模分別是:
P192 = 2192 - 264 - 1
P224 = 2224 - 296 + 1
P256 = 2256 - 2224 + 2192 - 296 -1
P384 = 2384 - 2128 - 296 + 232 -1
P512 = 2512 - 1
- ECC簽名的實現步驟:
第一步:讀取私鑰;
第二步:使用pem進行解碼;
第三步:使用x509對私鑰進行還原,得到PrivateKey結構體對象;
第四步:對原始數據進行哈希計算,得到散列值;
第五步:使用私鑰對散列值進行簽名;
/**
* ECC簽名
* 參數1:需要簽名的數據
* 參數2:私鑰文件
* 返回值:橢圓曲線的座標
* /
func EccSignature(plainText []byte, priKeyFile string) (rText, sText []byte) {
// 1.打開私鑰文件,讀取私鑰
buf := ReadKey(priKeyFile)
// 2.使用pem進行解碼
block, _ := pem.Decode(buf)
// 3.使用x509對私鑰進行還原
privateKey, err := x509.ParseECPrivateKey(block.Bytes)
if err != nil {
panic("x509.ParseECPrivateKey err!")
}
// 4.對原始數據進行哈希計算,得到散列值
hashText := sha1.Sum(plainText)
// 5.進行數字簽名
r, s, err := ecdsa.Sign(rand.Reader, privateKey, hashText[:])
if err != nil {
panic("ecdsa.Sign err!")
}
// 6.對r,s進行格式化
rText, err = r.MarshalText()
if err != nil {
panic("r.MarshalText err!")
}
sText, err = s.MarshalText()
if err != nil {
panic("s.MarshalText err!")
}
return
}
- ECC驗證的實現步驟:
第一步:讀取公鑰;
第二步:使用pem進行解碼;
第三步:使用x509對公鑰還原,得到公鑰結構體對象;
第四步:對原始數據進行哈希運算,得到散列值;
第五步:執行簽名驗證;
/**
* ECC簽名驗證
* 參數1:認證的數據
* 參數2和參數3:格式化後的橢圓曲線座標
* 參數4:公鑰文件
* 返回值:驗證結果,true代表驗證成功,false代表驗證失敗
* /
func E
func EccVerify(plainText, rText, sText []byte, pubKeyFile string) bool {
// 1.打開公鑰文件,讀取公鑰
buf := ReadKey(pubKeyFile)
// 2.pem解碼
block, _ := pem.Decode(buf)
// 3.使用x509對公鑰還原
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic("x509.ParsePKIXPublicKey err!")
}
publicKey, ok := key.(*ecdsa.PublicKey)
if !ok {
panic("key is not a ecdsa public key.")
}
// 4.對原始數據進行哈希運算
hashText := sha1.Sum(plainText)
// 5.簽名認證
var r, s big.Int
// 把rText、sText轉換成big.Int數據
r.UnmarshalJSON(rText)
s.UnmarshalJSON(sText)
return ecdsa.Verify(publicKey, hashText[:], &r, &s)
}
測試:
func GenerateKey() {
//---------------- 生成私鑰 --------------
// 1.使用ecdsa生成密鑰對
privateKey, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
if err != nil {
panic("ecdsa.GenerateKey err!")
}
// 2.使用x509進行序列化
derText, err := x509.MarshalECPrivateKey(privateKey)
if err != nil {
panic("x509.MarshalECPrivateKey err!")
}
// 3.將derText寫入pem.Block塊中
block := pem.Block{
Type: "ecdsa private key",
Bytes: derText,
}
// 4.使用pem編碼
file, err := os.Create("ecc_private.pem")
if err != nil {
panic("os.Create err!")
}
defer file.Close()
pem.Encode(file, &block)
//---------------- 生成公鑰 --------------
// 1.得到公鑰
publicKey := privateKey.PublicKey
// 2.使用x509對公鑰進行序列化
derText, err = x509.MarshalPKIXPublicKey(&publicKey)
if err != nil {
panic("x509.MarshalPKIXPublicKey err!")
}
// 3.將derText放入pem.Block塊中
block = pem.Block{
Type : "ecdsa public key",
Bytes : derText,
}
// 4.使用pem編碼
file, err = os.Create("ecc_public.pem")
if err != nil {
panic("os.Create err!")
}
defer file.Close()
pem.Encode(file, &block)
}
// 讀取密鑰文件內容
func ReadKey(keyFile string) []byte {
file, err := os.Open(keyFile)
if err != nil {
panic("文件不存在!")
}
defer file.Close()
fileInfo, err := file.Stat()
if err != nil {
panic("file.Stat err!")
}
buf := make([]byte, fileInfo.Size())
file.Read(buf)
return buf
}
// 測試
func main() {
GenerateKey()
src := []byte("hello world")
rText, sText := EccSignature(src, "ecc_private.pem")
isSucc := EccVerify(src, rText, sText, "ecc_public.pem")
fmt.Printf("簽名認證是否成功:%t\n", isSucc)
}
二、證書
正確使用數字簽名的一大前提是用於驗證簽名的公鑰必須屬於真正的發送者。即便數字簽名算法再強大,如果你得到的公鑰是僞造的,那麼數字簽名也會完全失效。爲了能夠確認自己得到的公鑰是否合法,我們需要使用證書。
2.1 什麼是證書
所謂證書,就是將公鑰當作一條消息,由一個可信的第三方(比如ca)對其簽名後所得到的文件。可以這樣理解:
證書與駕照很相似,裏面記有姓名、組織、郵箱地址等個人信息,以及屬於此人的公鑰,並由認證機構(比如ca)施加數字簽名。只要看到證書,我們就可以知道認證機構認定該公鑰的確屬於此人。
可能很多人都沒聽說過認證機構,認證機構就是能夠認定 “公鑰確實屬於此人",並能夠生成數字簽名的個人或者組織。認證機構中有國際性組織和政府所設立的組織,也有通過提供認證服務來盈利的一般企業。其中,全球最大的PKI/CA運營商是世界上最早出現的數字證書認證機構。
2.2 證書的應用場景
下圖展示了Alice向Bob發送密文的場景,在生成密文時所使用的Bob的公鑰是通過認證機構獲取的。
第一步:Bob生成祕鑰對;
第二步:Bob在認證機構Trent註冊自己的公鑰;
第三步:認證機構Trent用自己的私鑰對Bob的公鑰施加數字簽名,並生成證書;
第四步:Alice下載證書,證書裏面包含了Trent認證機構的數字簽名和Bob的公鑰;
第五步:Alice使用認證機構的公鑰驗證數字簽名,確認Bob的公鑰的合法性;
第六步:Alice用Bob的公鑰加密消息得到密文後,把密文發送給Bob;
第七步:Bob使用自己的私鑰對密文進行解密,得到Alice發送的消息;
2.3 證書標準規範x.509
X.509是密碼學裏公鑰證書的格式標準,它是由ITU(國際電信聯盟)和ISO(國際標準化組織)共同制定的規範。X.509 證書己應用在包括TLS/SSL在內的衆多 Internet協議裏,同時它也在很多非在線應用場景裏使用,比如電子簽名服務。一份X.509證書是一些標準字段的集合,這些字段包含有關用戶或設備及其相應公鑰的信息。X.509標準定義了證書中應該包含哪些信息,並描述了這些信息的數據格式。一般來說,一個數字證書內容可能包括基本數據(版本、序列號) 、所簽名對象信息( 簽名算法類型、簽發者信息、有效期、被簽發人、簽發的公開密鑰)、CA的數字簽名等等。
2.3.1 證書規範
目前X.509有不同的版本,例如 X.509 V2和x.509 v3都是目前比較新的版本,它們都是在原有版本(X.509 V1)的基礎上進行功能的擴充。其中每一個版本都必須包含以下信息:
-
版本號:
用來區分X.509的不同版本號。 -
序列號:
CA給每個證書分配的唯一的編號,用來追蹤和撤銷證書。只要擁有簽發者信息和序列號,就可以唯一標識一個證書,最大不能過20個字節。 -
簽名算法:
用來指定用CA簽發證書時所使用的簽名算法(如sha256-with-RSA-Encryption、ccdsa-with-SHA2S6)。 -
頒發者:
發證書單位的標識信息。 -
有效期:
證書有效的時間包括兩個日期:證書開始生效期和證書失效的日期和時間。在所指定的這兩個時間之間有效。 -
主體:
證書擁有者的標識信息。如 “C=CN,ST=Beijing, L=Beijing, O=org.example.com,CN=ca.org。example.com ”。 -
主體的公鑰信息:
包括被證明有效的公鑰和使用這個公鑰的方法名稱。 -
頒發者的唯一號:
代表頒發者的唯一信息,僅2、3版本支持。 -
主體的唯一號
代表擁有證書實體的唯一信息,僅2,3版本支持。 -
x.509的擴展:
- Subject Key Identifier:實體的祕鑰標識符,區分實體的多對祕鑰;
- Basic Constraints:指明是否屬於CA;
- Authority Key Identifier:證書頒發者的公鑰標識符;
- CRL Distribution Points:撤銷文件的頒發地址;
- Key Usage:證書的用途或功能信息。
此外,證書的頒發者還需要對證書內容利用自己的私鑰添加簽名, 以防止別人對證書的內容進行篡改。
2.3.2 證書格式
X.509規範中一般推薦使用PEM(Privacy Enhanced Mail)格式來存儲證書相關的文件。證書文件的文件名後綴一般爲 .crt 或 .cer 。對應私鑰文件的文件名後綴一般爲 .key。證書請求文件的文件名後綴爲 .csr 。有時候也統一用pem作爲文件名後綴。
下面展示一個pem格式的證書文件內容:
-----BEGIN CERTIFICATE-----
MIIDyjCCArKgAwIBAgIQdZfkKrISoINLporOrZLXPTANBgkqhkiG9w0BAQsFADBn
MSswKQYDVQQLDCJDcmVhdGVkIGJ5IGh0dHA6Ly93d3cuZmlkZGxlcjIuY29tMRUw
EwYDVQQKDAxET19OT1RfVFJVU1QxITAfBgNVBAMMGERPX05PVF9UUlVTVF9GaWRk
bGVyUm9vdDAeFw0xNzA0MTExNjQ4MzhaFw0yMzA0MTExNjQ4MzhaMFoxKzApBgNV
BAsMIkNyZWF0ZWQgYnkgaHR0cDovL3d3dy5maWRkbGVyMi5jb20xFTATBgNVBAoM
DERPX05PVF9UUlVTVDEUMBIGA1UEAwwLKi5iYWlkdS5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDX0AM198jxwRoKgwWsd9oj5vI0and9v9SB9Chl
gZEu6G9ZA0C7BucsBzJ2bl0Mf6qq0Iee1DfeydfEKyTmBKTafgb2DoQE3OHZjy0B
QTJrsOdf5s636W5gJp4f7CUYYA/3e1nxr/+AuG44Idlsi17TWodVKjsQhjzH+bK6
8ukQZyel1SgBeQOivzxXe0rhXzrocoeKZFmUxLkUpm+/mX1syDTdaCmQ6LT4KYYi
soKe4f+r2tLbUzPKxtk2F1v3ZLOjiRdzCOA27e5n88zdAFrCmMB4teG/azCSAH3g
Yb6vaAGaOnKyDLGunW51sSesWBpHceJnMfrhwxCjiv707JZtAgMBAAGjfzB9MA4G
A1UdDwEB/wQEAwIEsDATBgNVHSUEDDAKBggrBgEFBQcDATAWBgNVHREEDzANggsq
LmJhaWR1LmNvbTAfBgNVHSMEGDAWgBQ9UIffUQSuwWGOm+o74JffZJNadjAdBgNV
HQ4EFgQUQh8IksZqcMVmKrIibTHLbAgLRGgwDQYJKoZIhvcNAQELBQADggEBAC5Y
JndwXpm0W+9SUlQhAUSE9LZh+DzcSmlCWtBk+SKBwmAegbfNSf6CgCh0VY6iIhbn
GlszqgAOAqVMxAEDlR/YJTOlAUXFw8KICsWdvE01xtHqhk1tCK154Otci60Wu+tz
1t8999GPbJskecbRDGRDSA/gQGZJuL0rnmIuz3macSVn6tH7NwdoNeN68Uj3Qyt5
orYv1IFm8t55224ga8ac1y90hK4R5HcvN71aIjMKrikgynK0E+g45QypHRIe/z0S
/1W/6rqTgfN6OWc0c15hPeJbTtkntB5Fqd0sfsnKkW6jPsKQ+z/+vZ5XqzdlFupQ
29F14ei8ZHl9aLIHP5s=
-----END CERTIFICATE-----
PEM格式採用文本方式進行存儲。一般包括首尾標記和內容塊,內容塊採用Base64進行編碼。
通過對證書數據還原,可以得到以下內容:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
10:e6:fc:62:b7:41:8a:d5:00:5e:45:b6
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA-SHA256-G2
Validity
Not Before: Nov 21 08:00:00 2016 GMT
Not After : Nov 22 07:59:59 2017 GMT
Subject: C=US, ST=California, L=San Francisco, O=Wikimedia Foundation, Inc., CN=*.wikipedia.org
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:c9:22:69:31:8a:d6:6c:ea:da:c3:7f:2c:ac:a5:
af:c0:02:ea:81:cb:65:b9:fd:0c:6d:46:5b:c9:1e:
ed:b2:ac:2a:1b:4a:ec:80:7b:e7:1a:51:e0:df:f7:
c7:4a:20:7b:91:4b:20:07:21:ce:cf:68:65:8c:c6:
9d:3b:ef:d5:c1
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Agreement
Authority Information Access:
CA Issuers - URI:http://secure.globalsign.com/cacert/gsorganizationvalsha2g2r1.crt
OCSP - URI:http://ocsp2.globalsign.com/gsorganizationvalsha2g2
X509v3 Certificate Policies:
Policy: 1.3.6.1.4.1.4146.1.20
CPS: https://www.globalsign.com/repository/
Policy: 2.23.140.1.2.2
X509v3 Basic Constraints:
CA:FALSE
X509v3 CRL Distribution Points:
Full Name:
URI:http://crl.globalsign.com/gs/gsorganizationvalsha2g2.crl
X509v3 Subject Alternative Name:
DNS:*.wikipedia.org, DNS:*.m.mediawiki.org, DNS:*.m.wikibooks.org, DNS:*.m.wikidata.org, DNS:*.m.wikimedia.org, DNS:*.m.wikimediafoundation.org, DNS:*.m.wikinews.org, DNS:*.m.wikipedia.org, DNS:*.m.wikiquote.org, DNS:*.m.wikisource.org, DNS:*.m.wikiversity.org, DNS:*.m.wikivoyage.org, DNS:*.m.wiktionary.org, DNS:*.mediawiki.org, DNS:*.planet.wikimedia.org, DNS:*.wikibooks.org, DNS:*.wikidata.org, DNS:*.wikimedia.org, DNS:*.wikimediafoundation.org, DNS:*.wikinews.org, DNS:*.wikiquote.org, DNS:*.wikisource.org, DNS:*.wikiversity.org, DNS:*.wikivoyage.org, DNS:*.wiktionary.org, DNS:*.wmfusercontent.org, DNS:*.zero.wikipedia.org, DNS:mediawiki.org, DNS:w.wiki, DNS:wikibooks.org, DNS:wikidata.org, DNS:wikimedia.org, DNS:wikimediafoundation.org, DNS:wikinews.org, DNS:wikiquote.org, DNS:wikisource.org, DNS:wikiversity.org, DNS:wikivoyage.org, DNS:wiktionary.org, DNS:wmfusercontent.org, DNS:wikipedia.org
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Key Identifier:
28:2A:26:2A:57:8B:3B:CE:B4:D6:AB:54:EF:D7:38:21:2C:49:5C:36
X509v3 Authority Key Identifier:
keyid:96:DE:61:F1:BD:1C:16:29:53:1C:C0:CC:7D:3B:83:00:40:E6:1A:7C
Signature Algorithm: sha256WithRSAEncryption
8b:c3:ed:d1:9d:39:6f:af:40:72:bd:1e:18:5e:30:54:23:35:
...
2.3.3 CA證書
CA是Certificate Authority的縮寫,也叫“證書授權中心”,它是負責管理和簽發證書的第三方機構。一般來說,CA必須是所有行業和所有公衆都信任的、認可的。因此它必須具有足夠的權威性。
2.3.3.1 CA證書
CA 證書,顧名思義,就是CA頒發的證書。任何人都可以找工具製作證書。但是自己製作的證書不具有權威性,因此不會得到別人的認可。
2.3.3.2 證書信任鏈
多個證書之間可以建立信任關係。比如說,通過一個證書可以證明另一個證書也是真實可信的。而且,證書之間的信任關係是可以嵌套的。比如C 信任 A和B,A 信任 A1和A2,B 信任B1和B2,以此類推,這個叫做證書的信任鏈(如下圖)。
處於最頂端的證書稱爲“根證書”。除了根證書,其它證書都要依靠上一級的證書來證明自己是可靠的。根證書是整個證書體系安全的根本。如果某個證書體系中的根證書出了問題,那麼被根證書所信任的其它證書,也就不再可信了。
2.3.3.3 證書的作用
-
驗證網站是否可信
通常,我們如果訪問某些敏感的網頁(比如用戶登錄的頁面),其協議都會使用 HTTPS 而不是 HTTP。HTTPS 協議除了有加密的機制,還有一套證書的機制。通過證書來確保,某個站點確實就是某個站點。有了證書之後,當你的瀏覽器在訪問某個 HTTPS 網站時,會驗證該站點上的 CA 證書(類似於驗證介紹信的公章)。如果瀏覽器發現該證書沒有問題(證書被某個根證書信任、證書上綁定的域名和該網站的域名一致、證書沒有過期),那麼頁面就直接打開;否則的話,瀏覽器會給出一個警告,告訴你該網站的證書存在某某問題。 -
驗證某個文件是否可信
通過證書來製作文件的數字簽名可以用來驗證某個文件是否被篡改。
2.4 公鑰基礎設施(PKI)
僅制定證書的規範還不足以支持公鑰的實際運用,我們還需要很多其他的規範,例如證書應該由誰來頒發,如何頒發,私鑰泄露時應該如何作廢證書,計算機之間的數據交換應採用怎樣的格式等。
2.4.1 什麼是公鑰基礎設施
公鑰基礎設施(Public-Key Infrastructure,簡稱KPI)是爲了能夠更有效地運用公鑰而制定的一系列規範的總稱。例如,RSA公司所制定的PKCS系列規範也是PKI的一種,而互聯網規格RFC中也有很多與PKI相關的文檔。此外,X.509這樣的規範也是PKI的一種。在開發PKI程序時所使用的由各個公司編寫的API接口和規格設計書也是PKI的相關規格。
國家、地方政府、醫院、圖書館等公共組織和團體可以成立認證機構來實現PKI,公司也可以出於業務需要在內部實現PKI,甚至個人也可以以實驗爲目的來構建PKI。
2.4.2 PKI的組成
PKI的組成要素如下圖所示:
- 用戶:使用PKI的人。用戶包含兩種:一種是希望使用PKI註冊自己的公鑰的人(如bob);另外一種是希望使用已註冊的公鑰的人(如Alice);
- 認證機構CA:對證書進行管理的人(如Trent);
- 倉庫:倉庫也叫作證書目錄,是一個保存證書的數據庫,PKI用戶在需要的時候可以從倉庫裏面獲取證書;
三、SSL/TLS
SSL(Secure Socket Layer)與TLS(Transport Layer Security)是世界上應用最廣泛的密碼通信方法。使用SSL/TLS可以對通信對象進行認證,還可以確保通信內容的機密性。比如說在網上銀行中輸人銀行卡的賬號時,瀏覽器就會使用SSL/TLS進行密碼通信。
SSL/TLS中綜合運用了之前所學習過的對稱密碼、消息認證碼、公鑰密碼、數字簽名、僞隨機數生成器等密碼技術。嚴格來說,SSL與TLS是不同的,TLS相當於是SSL的後續版本。但是大部分時候SSL和TLS是兼備的,因此通常統一寫作SSL/TLS。
3.1 SSL/TLS的主要作用
- 認證用戶和服務器,保證各自的數據都發送到正確的位置上去;
- 對發送的數據進行加密,保護數據;
- 保證數據在發送過程中的完整性;
3.2 http和https協議
SSL/TLS是建立在數據傳輸層上的一層加密,它能夠保證上層信息傳輸的安全。我們知道HTTP是不安全的,瀏覽器通過HTTP協議向服務端發送數據,數據是通過明文方式直接發送給服務端。於是,我們可以使用SSL/TLS作爲對通信進行加密的協議,然後在此之上承載HTTP(如下圖)。
通過將兩種協議進行疊加,我們就可以對HTTP的通信進行加密,從而防止竊聽。通過SSL/TLS進行通信時,URL不是以http://開頭,而是以https://開頭。
SSL/TLS除了可以承載HTTP通信以外,還可以承載其他許多協議。例如,發送郵件時使用的SMTP和接收郵件時使用的POP3都可以用SSL/TLS進行承載。在這樣的情況下,SSL/TLS就可以對收發的郵件進行保護。用SSL/TLS承載HTTP、SMTP和POP3的結構如下圖所示:
3.3 https的傳輸過程
第一步:客戶端發起https請求,連接到服務端的443端口;
第二步:服務器將公鑰和數字簽名(證書)發送給客戶端;
第三步:客戶端開始解析證書,並對證書的合法性進行校驗(比如公鑰是否有效,證書是否過期等);
第四步:如果證書沒有問題,那麼客戶端則通過隨機數生成器,通過證書對生成的隨機數進行非對稱加密,並將加密後的密文發送給服務器;
第五步:服務器使用私鑰對其進行非對稱解密後,得到隨機數;
第六步:服務器把響應數據通過該隨機數進行對稱加密後,發送給客戶端;
第七步:客戶端用之前生成的隨機數對響應數據局進行解密後,得到明文;
3.4 http和https的區別
- http不需要證書,而https協議需要到ca申請證書,一般免費證書較少,因而需要一定費用;
- http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl/tls加密傳輸協議;
- http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,後者是443;
- http的連接很簡單,是無狀態的;HTTPS協議是由SSL/TLS+HTTP協議構建的可進行加密傳輸;
3.5 https的優缺點
- https的優點:
- 使用https協議能夠確保數據發送到正確的客戶端或服務器;
- https協議是由ssl+http協議所構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全,可防止數據在傳輸過程中不被竊取、改變,確保數據的完整性;
- https是現行架構下最安全的解決方案,雖然不是絕對安全,但它大幅增加了中間人攻擊的成本;
- 權值相同的站點,採用https協議的頁面更加安全,排名上會優先對待。
- https的缺點:
- https協議握手階段比較費時,會延長頁面的加載時間;
- https連接緩存不如http高效;
- ssl/tls證書需要錢,功能越強大的證書費用越高;
- ssl/tls證書通常需要綁定IP,不能在同一IP上綁定多個域名;
- https協議的加密範圍也比較有限,在黑客攻擊、拒絕服務攻擊、服務器劫持等方面幾乎起不到什麼作用。還有一點,ssl證書的信用鏈體系並不安全,特別是在某些國家可以控制ca根證書的情況下,中間人攻擊一樣可行;