一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

理解加密算法(三)——?jiǎng)?chuàng)建CA機(jī)構(gòu),簽發(fā)證書并開(kāi)始TLS通信

 yespon 2017-01-06
章節(jié)目錄

理解加密算法(一)——加密算法分類、理解加密算法(二)——TLS/SSL

1 不安全的TCP通信

普通的TCP通信數(shù)據(jù)是明文傳輸?shù)?,所以存在?shù)據(jù)泄露和被篡改的風(fēng)險(xiǎn),我們可以寫一段測(cè)試代碼試驗(yàn)一下。

TCP Server:

const net=require('net'); const server=net.createServer(); const serverHost='127.0.0.1'; const serverPort=8888; server.on('connection',(clientSocket)=>{ clientSocket.setEncoding('utf8'); clientSocket.on('data',(data)=>{ console.log(`client say:${data}`); }); clientSocket.on('error',()=>{}); }); server.listen({host:serverHost,port:serverPort},()=>{ console.log(`server is listening on port ${8888}`) });

TCP Client:

const net=require('net'); const socket=new net.Socket(); const serverHost='127.0.0.1'; const serverPort=8888; let index=0; socket.on('error',()=>{}); socket.connect({host:serverHost,port:serverPort},()=>{ console.log(`client has connected to host ${serverHost} , port ${serverPort}`); setInterval(()=>{ socket.write(`i love u ${index }`); },3000); });

啟動(dòng)Server和Client后,可以在Server的控制臺(tái)中看到來(lái)自Client的消息:

client say:i love u 0 client say:i love u 1 client say:i love u 2 client say:i love u 3 client say:i love u 4

1.1 數(shù)據(jù)泄露

數(shù)據(jù)在傳輸?shù)倪^(guò)程中是可以被所有人看到的,可以用WireShark抓包測(cè)試一下。由于WireShark無(wú)法直接抓取發(fā)送給本地的TCP包,我將Server部署到了另外一臺(tái)機(jī)器上,需要做如下修改:

  • serverHost都修改為另一臺(tái)機(jī)器的IP。
  • 打開(kāi)Server機(jī)器防火墻的8888端口。

配置好抓取IP:

抓包:

可以看到,表白信息全被別人看了去了 :(

可能有人會(huì)說(shuō):我臉皮厚,隨便看~

但是要注意了,所有http協(xié)議的請(qǐng)求,他們的數(shù)據(jù)都是這樣發(fā)送的!可以認(rèn)為,在一個(gè)使用http協(xié)議而不是https協(xié)議的網(wǎng)站上,你的游戲賬號(hào)、銀行卡密碼,都是這樣赤果果的暴露在別人眼前的!

不僅如此,別人還可以隨意篡改你的數(shù)據(jù)!

1.2 數(shù)據(jù)篡改

我們上網(wǎng)的過(guò)程中,數(shù)據(jù)從我們的電腦到達(dá)目標(biāo)服務(wù)器的過(guò)程中,可能會(huì)經(jīng)過(guò)層層代理和多次路由,最終才到達(dá)目標(biāo)服務(wù)器并不是像上面我們的Demo那樣是直連的!

為了模擬這種情況,我們可以在Demo的Client和Server之間加上一個(gè)耿直的Proxy:

const net=require('net'); const proxyServer=net.createServer(); const proxyHost='127.0.0.1'; const proxyPort=8889; const serverHost='127.0.0.1'; const serverPort=8888; //代理連接到真實(shí)目標(biāo)Server const proxySocket=new net.Socket(); proxySocket.connect({host:serverHost,port:serverPort},()=>{ console.log(`proxy has connected to host ${serverHost} , port ${serverPort}`); }); //啟動(dòng)代理Server proxyServer.on('connection',(clientSocket)=>{ //直接將客戶端的數(shù)據(jù)發(fā)給真實(shí)目標(biāo)Server clientSocket.pipe(proxySocket); }); proxyServer.listen({host:proxyHost,port:proxyPort},()=>{ console.log(`proxy server is listening on port ${8889}`) });

修改Client的連接端口,連到proxy的8889端口而不是真實(shí)目標(biāo)的8888端口,依次啟動(dòng)Server→Proxy→Client,可以看到Server收到了:

client say:i love u 0 client say:i love u 1 client say:i love u 2 client say:i love u 3

需要注意到這一行代碼 clientSocket.pipe(proxySocket),所以說(shuō)這是一個(gè)耿直的代理:)

換一個(gè)不耿直的代理,它會(huì)這樣做:

clientSocket.setEncoding('utf8'); clientSocket.on('data',(data)=>{ data=data.replace(/love/g,'hate'); proxySocket.write(data); });

重新依次啟動(dòng)Server→Proxy→Client,可以看到Server收到了:

client say:i hate u 0 client say:i hate u 1 client say:i hate u 2 client say:i hate u 3 client say:i hate u 4

這下shabi了吧,妹子肯定是追不到了:( 咋辦呢?

2 CA機(jī)構(gòu)

先梳理一下思路:按照之前了解的加密算法原理,我們可以讓Server給Client下發(fā)一份非對(duì)稱加密的公鑰,client用公鑰加密數(shù)據(jù)然后發(fā)送,這樣就不存在數(shù)據(jù)泄露和篡改的風(fēng)險(xiǎn)了。

然而,這個(gè)世界是很險(xiǎn)惡的,會(huì)有人把自己偽裝成Server,給Client下發(fā)他們自己的公鑰,并攔截真實(shí)Server下發(fā)給Client的真實(shí)公鑰。

由于我們沒(méi)辦法判定Client拿到的公鑰是真實(shí)Server還是惡意代理發(fā)過(guò)來(lái)的,所以我們需要一個(gè)可信賴的第三方,來(lái)告訴Client拿到的公鑰到底是不是可信的,這個(gè)第三方就是CA機(jī)構(gòu),Certificate Authority,證書授權(quán)中心。

引入了CA機(jī)構(gòu)后,獲取證書流程如下:

在實(shí)際Client應(yīng)用中,例如瀏覽器中,扮演可信角色——CA機(jī)構(gòu)的實(shí)際上是瀏覽器提前內(nèi)置好的,一部分瀏覽器廠商認(rèn)為可信的CA機(jī)構(gòu)的根證書,下面演示一下如何創(chuàng)辦一家CA機(jī)構(gòu),并為一個(gè)服務(wù)器頒發(fā)CA證書。

2.1 創(chuàng)辦CA機(jī)構(gòu)

我們可以利用開(kāi)源的openssl庫(kù)來(lái)創(chuàng)辦一家私人的CA機(jī)構(gòu),上面的演示Demo目錄結(jié)構(gòu)為:

├─clientclient.js ├─proxyproxy.js └─server server.js

新建一個(gè)CA目錄,創(chuàng)建一家CA機(jī)構(gòu),可以通俗地理解為:

  1. 生成一份非對(duì)稱加密私鑰
  2. 生成一份明文的證書文件,證書中記錄該機(jī)構(gòu)的地址、名稱、email、機(jī)構(gòu)公鑰、有效期等信息
  3. 為自己的證書簽名:即通過(guò)散列函數(shù)計(jì)算出證書文件的散列值,并通過(guò)私鑰對(duì)散列值加密。將簽名附加到證書中。

這樣,我們就得到了一份稱為“根證書”的證書文件,瀏覽器如果信任我們的CA機(jī)構(gòu),就可以把我們的根證書內(nèi)置到瀏覽器中。

對(duì)應(yīng)的openssl命令為:

  1. openssl genrsa -out caPrivate.key 2048 創(chuàng)建一個(gè)2048位的非對(duì)稱加密私鑰
  2. openssl req -new -key caPrivate.key -out ca.csr 通過(guò)私鑰創(chuàng)建一個(gè)正式簽名請(qǐng)求文件,期間會(huì)要求輸入機(jī)構(gòu)名稱、地址、email等信息。
  3. openssl x509 -req -in ca.csr -signkey caPrivate.key -out ca.crt使用x509證書協(xié)議為剛剛創(chuàng)建的證書簽名請(qǐng)求簽名,得到ca.crt文件,即“根證書”。

至此,我們成功創(chuàng)辦了一家擁有自己根證書的CA機(jī)構(gòu),文件列表:
ca.crt
ca.csr
caPrivate.key

證書的細(xì)節(jié)遠(yuǎn)不止這么簡(jiǎn)單,具體的可以參見(jiàn)CA證書標(biāo)準(zhǔn)X.509,https://www./rfc/rfc5280.txt

2.2 簽發(fā)CA證書

為了安全,我們升級(jí)一下前邊Demo中的Server,創(chuàng)建自己的證書,并請(qǐng)求CA機(jī)構(gòu)簽名頒發(fā)CA證書,來(lái)進(jìn)行TLS安全通信。

  1. 新建目錄 TlsServer
  2. 創(chuàng)建私鑰 openssl genrsa -out private.key 2048
  3. 創(chuàng)建證書簽名請(qǐng)求 openssl req -new -key private.key -out request.csr
  4. openssl x509 -req -CA ../CA/ca.crt -CAkey ../CA/caPrivate.key -CAcreateserial -in request.csr -out server.crt CA機(jī)構(gòu)為L(zhǎng)tsServer的證書簽名,并頒發(fā)CA證書文件server.crt

這里要注意的是,本地測(cè)試的時(shí)候,Common Name屬性要填寫localhost,若填寫線上應(yīng)用地址,則使用時(shí)客戶端會(huì)報(bào)錯(cuò):

Error: Hostname/IP doesn't match certificate's altnames: 'Host: localhost. is not cert's CN: '

2.3 開(kāi)始安全的TLS通信

使用上面一步頒發(fā)的CA證書來(lái)進(jìn)行TLS通信,需要三個(gè)步驟:

  • 使用CA機(jī)構(gòu)為Tls Server頒發(fā)的CA證書創(chuàng)建TLS Server
  • 將CA機(jī)構(gòu)的根證書內(nèi)置到TLS Client中
  • 使用CA根證書創(chuàng)建TLS Client

① TLS Server:

const tls = require('tls'); const fs=require('fs'); const serverHost='127.0.0.1'; const serverPort=8888; const options = { key: fs.readFileSync('private.key'), cert: fs.readFileSync('server.crt'), }; var tlsServer = tls.createServer(options,(clientSocket) => { clientSocket.setEncoding('utf8'); clientSocket.on('data',(data)=>{ console.log(`client say:${data}`); }); clientSocket.on('error',(e)=>{console.log(e)}); }); tlsServer.listen({host:serverHost,port:serverPort},()=>{ console.log(`lts server is listening on port ${8888}`) });

② 將CA機(jī)構(gòu)根證書內(nèi)置到Client中:

③ 創(chuàng)建 TLS Client

const tls = require('tls'); const fs = require('fs'); const serverHost='127.0.0.1'; const serverPort=8888; const options = { ca: [ fs.readFileSync('ca.crt') ] }; let index=0; var tlsSocket = tls.connect(serverPort, options, () => { console.log(`tls client has connected to host ${serverHost} , port ${serverPort}`); setInterval(()=>{ tlsSocket.write(`i love u ${index }`); },3000); }); tlsSocket.on('error',(e)=>{console.log(e)});

再將服務(wù)端部署到另外一臺(tái)機(jī)器上,抓包:

現(xiàn)在看到的內(nèi)容就是亂碼了,沒(méi)有內(nèi)容泄露的風(fēng)險(xiǎn)。同理,在數(shù)據(jù)傳輸?shù)倪^(guò)程中,第三方也無(wú)法篡改我們的數(shù)據(jù)了。

將自己的測(cè)試TLS服務(wù)部署到另外一臺(tái)機(jī)器上時(shí),有個(gè)要注意的地方,TlsClient的option中需要修改如下:

const options = { ca: [ fs.readFileSync('ca.crt') ], checkServerIdentity: function (host, cert) { return undefined; } };

這是因?yàn)門LS通信時(shí),對(duì)于服務(wù)端身份的檢查,使用域名和使用IP的情況下,驗(yàn)證的策略不同,當(dāng)我們?cè)诒镜販y(cè)試,使用IP時(shí),需要將IP加入證書的SAN擴(kuò)展(Subject Alternative Name)中,關(guān)于此擴(kuò)展的內(nèi)容,可以到https://www./rfc/rfc5280.txt查詢,我沒(méi)有深入研究。

3 基于TLS的HTTPS協(xié)議

前邊1.1小節(jié)中說(shuō)道,http協(xié)議是基于tcp傳輸協(xié)議的不安全協(xié)議,那么https協(xié)議為什么被認(rèn)為是安全的協(xié)議呢? 答案就是,它是基于tls傳輸協(xié)議的應(yīng)用層協(xié)議。

3.1 創(chuàng)建https服務(wù)

有了前邊對(duì)LTS通信原理的了解,再來(lái)看https就非常簡(jiǎn)單了,我們可以直接復(fù)用剛剛為TLS Server頒發(fā)的CA證書,來(lái)創(chuàng)建一個(gè)https服務(wù)器。

var https = require('https'); var fs = require('fs'); var options = { key: fs.readFileSync('./private.key'), cert: fs.readFileSync('./server.crt') }; https.createServer(options, function(req, res) { res.writeHead(200); res.end('hello https'); }).listen(8866);


chrome會(huì)這樣提示你,我們的瀏覽器里邊找不到為這個(gè)服務(wù)器CA證書簽名的CA證書,這很可能是一個(gè)騙子網(wǎng)站,這是因?yàn)槲覀兊腃A機(jī)構(gòu)根證書沒(méi)有被內(nèi)置到chrome里邊。點(diǎn)繼續(xù)訪問(wèn):

查看證書:

3.2 讓自己的CA機(jī)構(gòu)被chrome信任

可以將我們的CA機(jī)構(gòu)根證書導(dǎo)入chrome,在chrome設(shè)置中:

重啟chrome,再次訪問(wèn)我們的https服務(wù)

看,變成小綠鎖了~

最后,本文所有Demo代碼存放于:https://github.com/zouchengzhuo/nodejsLearn/tree/master/caAndTLS

原文來(lái)自我的個(gè)人站點(diǎn):http:///blog/2017/01/05/understand-crypto-3/



如果您覺(jué)得這篇文章對(duì)您有幫助,歡迎點(diǎn)擊右下角推薦支持一下我,謝謝!

這篇文章為原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    国产一区二区熟女精品免费| 韩国激情野战视频在线播放| 午夜福利直播在线视频| 国产日产欧美精品大秀| 国产精品第一香蕉视频| 人妻少妇久久中文字幕久久| 久久天堂夜夜一本婷婷| 四季精品人妻av一区二区三区 | 欧美黑人在线一区二区| 最新69国产精品视频| 亚洲最大福利在线观看| 欧美中文日韩一区久久| 青青操精品视频在线观看| 国产精品欧美一区两区| 1024你懂的在线视频| 中文字幕一区二区免费| 欧美日韩少妇精品专区性色| 亚洲内射人妻一区二区| 国产原创激情一区二区三区| 日本在线 一区 二区| 97人妻精品一区二区三区男同| 热情的邻居在线中文字幕| 亚洲最新av在线观看| 精产国品一二三区麻豆| 少妇人妻一级片一区二区三区| 青青操视频在线观看国产| 亚洲视频一级二级三级| 国产级别精品一区二区视频| 中文字日产幕码三区国产| 超薄丝袜足一区二区三区| 欧美激情床戏一区二区三| 天堂网中文字幕在线观看| 视频在线免费观看你懂的| 午夜小视频成人免费看| 国产亚洲精品一二三区| 欧美人妻少妇精品久久性色| 国产av大片一区二区三区| 欧美自拍偷自拍亚洲精品| 两性色午夜天堂免费视频| 国产成人精品一区二三区在线观看 | 高清亚洲精品中文字幕乱码|