HTTPS/SSL原理及Ruby實現

What

SSL (Secure Socket Layer)爲Netscape所研發,用以保障在Internet上數據傳輸之安全,利用數據加密(Encryption)技術,可確保數據在網絡 上之傳輸過程中不會被截取及竊聽。目前一般通用之規格爲40 bit之安全標準,美國則已推出128 bit之更高安全 標準,但限制出境。只要3.0版本以上之I.E.或Netscape瀏覽器即可支持SSL。 當前版本爲3.0。它已被廣泛地用於Web瀏覽器與服務器之間的身份認證和加密數據傳輸。

說到SSL就不得不說HTTPS,全稱:Hypertext Transfer Protocol over Secure Socket Layer,是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容請 看SSL。

SSL協議位於TCP/IP協議與各種應用層協議之間,爲數據通訊提供安全支持。SSL協議可分爲兩層: SSL記錄協議(SSL Record Protocol):它建立在可靠的傳輸協議(如TCP)之上,爲高層協議提供數據封裝、壓縮、加密等基本功能的支持。 SSL握手協議(SSL Handshake Protocol):它建立在SSL記錄協議之上,用於在實際的數據傳輸開始前,通訊雙方進行身份認證、協商加密算法、交換加密密鑰等。HTTPS使用端 口443,而不是象HTTP那樣使用端口80來和TCP/IP進行通信。

SSL協議提供的服務主要有:

1)認證用戶和服務器,確保數據發送到正確的客戶機和服務器;

2)加密數據以防止數據中途被竊取;

3)維護數據的完整性,確保數據在傳輸過程中不被改變。

Why

此前我一直對https/ssl如何保護數據不被竊聽有點疑問,因爲服務器的證書是公開的,只能實行上行方向的數據加密,下行數據的加密我一直認爲 是瀏覽器會自動生成一個客戶端的密鑰對並將公鑰發給服務器。仔細研究了https/ssl後發現其實並不像我想的那樣,這裏面既有非對稱加密,又因爲性能 原因使用了對稱加密。

基本的加解密算法類型也就這兩種:

對稱加密 :密鑰只有一個,加密解密爲同一個密碼,且加解密速度快,典型的對稱加密算法有DES、AES等;

非對稱加密 :密鑰成對出現(且根據公鑰無法推知私鑰,根據私鑰也無法推知公鑰),加密解密使用不同密鑰(公鑰加密需要私鑰解密,私鑰加密需要公鑰解密),相對對稱加密速度較慢,典型的非對稱加密算法有RSA、DSA等。

明白了這兩種加密類型,具體的認證過程就容易理解了:

  1. 客戶端瀏覽器連接到https/ssl服務器,併發送ssl版本號等信息到服務器,協商此次連接使用的版本和參數。

  2. 服務器根據客戶端發來的協商數據和自身支持的特性返回客戶端協商參數,並且將服務器的證書發送給客戶端,服務器的證書裏包括用於非對稱加密的服務器的公鑰。

  3. 客戶端收到服務器的證書,可以用於鑑別服務器身份,防止假冒的服務器。但最重要的用處是將一段由客戶端瀏覽器隨機生成的數據pre- master secret用服務器證書裏的公鑰進行加密,發給服務器。注意,因爲這段加密的數據只由用服務器的私鑰才能解密,所以pre-master secret不會被人監聽到。

  4. 服務器收到加密後的pre-master secret數據後,用自己的私鑰解密得到原始的pre-master secret,並使用一定算法得到對稱加密的密鑰master secret。

  5. 客戶端也根據同樣的算法得到master secret。

  6. 至此,客戶端和服務器之間的上/下行數據傳送使用對稱加/解密,初始密鑰爲master secret。常用的對稱加密算法有RC4,AES等。

經過這些步驟就可以保證https/ssl上下行數據不被監聽並且加/解密速度也可以接受。

文字看起來特別枯燥吧?別急,有圖:

https/ssl

以上是單向認證的過程,也就是服務端身份驗證,https/ssl還支持客戶端身份驗證,也就是雙向驗證,需要將客戶端證書上傳到服務器,但這個證書並不用來加密下行數據。比如銀行那些高價賣給你的'x盾'之類,就是屬於客戶端的證書。

簡單來說,非對稱加因爲速度問題只用來認證(驗證?)。而通信內容的安全及完整性是通過對稱加密完成的。

How

其實我們設計自己的加密通信協議時完全可以照搬https/ssl這種方式,當然,有時我們也可以適當簡化認證步驟,下面兩段代碼就是使用Ruby使用RSA非對成加密認證過程的簡單實現。

過程簡要描述:

1.服務端使用RSA初始化一個key-pair

2.客戶端請求服務端的public-key

3.客戶端使用public-key加密傳輸內容 發送至服務端

4.服務端使用private-key解密內容並執行

傳輸內容的有效性驗證使用SHA1加密串與正文內容一併加密發送 服務端使用同樣算法來驗證內容是否被篡改(當然 這個過程中我們還可以加salt)

客戶端代碼:

require 'socket' 

require 'digest/sha1' 

require "openssl" 

begin 

print "Starting client......" 

client = TCPSocket.new('localhost'8888

puts"connected!\n\n" 

10 

11 temp = "" 

12 #get server public encryption key 

13 5.times do 

14 temp << client.gets 

15 end 

16 

17 puts "Received public 1024 RSA key!\n\n" 

18public_key = OpenSSL::PKey::RSA.new(temp) 

19 

20 p public_key 

21 #Construct message to send 

22 msg = 'open*open*/' 

23 sha1 = Digest::SHA1.hexdigest(msg) 

24 

25command = public_key.public_encrypt("#{sha1}*#{msg}")

26 print "Sending the command...." 

27 

28 #send the message 

29 client.send(command,0

30 

31 puts "sent!" 

32rescue => e 

33 puts "Something terrible happened..." 

34 puts e 

35 retry 

36 end 

37 

38 client.close

服務端代碼:

require 'socket' 

require 'digest/sha1' 

require "openssl" 

priv_key = OpenSSL::PKey::RSA.new(1024

pub_key = priv_key.public_key 

host = ARGV[0||'localhost' 

port = (ARGV[1|| 8888).to_i 

10 

11 #Start a listening TCP server on the ip address of host and port 

12 server = TCPServer.new(host, port) 

13 

14 #If a connection is madge, send the public key and wait for data 

15 while session = server.accept 

16 begin 

17 puts "Connection made...sending public key.\n\n" 

18 puts pub_key 

19 session.print pub_key 

20 puts "Public key sent, waiting on data...\n\n" 

21 

22 temp = session.recv(10000

23 puts "Received data..." 

24 

25 msg =priv_key.private_decrypt(temp) 

26 rescue => e 

27 puts "Something terrible happened while receiving and decrypting." 

28 puts e 

29 end 

30 

31 #Split the message sent by the client 

32 command = msg.split("*"

33 

34 serv_hash = command[0

35 nix_app = command[1

36 win_app = command[2

37 file = command[3

38 

39 #Execute message from client based on the server platform 

40 if Digest::SHA1.hexdigest("#{nix_app}*#{win_app}*#{file}")==serv_hash 

41 puts "Message integrity confirmed..." 

42 ifRUBY_PLATFORM.include?('mswin32'

43 puts "Executing windows command: #{win_app} #{file}" 

44 `#{win_app} #{file}` 

45 exit 

46 else 

47 puts "Executing Linux command:#{nix_app} #{file}" 

48 `#{nix_app} #{file}` 

49 exit

50 end 

51 else

52 puts "The message could not be validated!" 

53 end 

54 exit 

55 end

給出Ruby的實現,主要是因爲ruby容易讀。但無論哪種語言實現,要想凹/凸牆加密就是必須的,有興趣的童鞋建議Erlang或者node.js來實現服務端。

=====================

附上ruby安裝缺少openssl的trouble shooting:

報錯內容no such file to load -- openssl

解決方法:

cd /ruby_source_code_dir/ext/openssl ruby extconf.rb --with-openssl-include=/usr/local/ssl/include/ --with-openssl-lib=/usr/local/ssl/lib make make install

http://foobar.me/2011/05/19/https-ssl-yuan-li-ji-ruby-shi-xian/ 
發佈了6 篇原創文章 · 獲贊 5 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章