HTTPS/SSL原理及Ruby实现

来源:互联网 发布:风险评估矩阵表 编辑:程序博客网 时间:2024/05/16 00:38
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/