随着计算机网络技术的发展,方便快捷的互连网使人们渐渐习惯了从web页上收发e-mail、购物和交易,这时web页面上需要传输重要或敏感的数据,例如用户的银行帐户、密码等,所以网络安全就成为现代计算机网络应用急需解决的问题。
现行网上银行和电子商务等大型的网上交易系统普遍采用http和ssl相结合的方式。服务器端采用支持ssl的web服务器,用户端采用支持ssl的浏览器实现安全通信。
ssl是secure socket layer(安全套接层协议)的缩写,可以在internet上提供秘密性传输。netscape公司在推出第一个web浏览器的同时,提出了ssl协议标准,目前已有3.0版本。ssl采用公开密钥技术。其目标是保证两个应用间通信的保密性和可靠性,可在服务器端和用户端同时实现支持。目前,利用公开密钥技术的ssl协议,已成为internet上保密通讯的工业标准。本文着重在ssl协议和ssl程序设计两方面谈谈作者对ssl的理解。
ssl协议初步介绍
安全套接层协议能使用户/服务器应用之间的通信不被攻击者窃听,并且始终对服务器进行认证,还可选择对用户进行认证。ssl协议要求建立在可靠的传输层协议(tcp)之上。ssl协议的优势在于它是与应用层协议独立无关的,高层的应用层协议(例如:http,ftp,telnet等)能透明地建立于ssl协议之上。ssl协议在应用层协议通信之前就已经完成加密算法、通信密钥的协商及服务器认证工作。在此之后应用层协议所传送的数据都会被加密,从而保证通信的私密性。
通过以上叙述,ssl协议提供的安全信道有以下三个特性:
1.数据的保密性
信息加密就是把明码的输入文件用加密算法转换成加密的文件以实现数据的保密。加密的过程需要用到密匙来加密数据然后再解密。没有了密钥,就无法解开加密的数据。数据加密之后,只有密匙要用一个安全的方法传送。加密过的数据可以公开地传送。
2.数据的一致性
加密也能保证数据的一致性。例如:消息验证码(mac),能够校验用户提供的加密信息,接收者可以用mac来校验加密数据,保证数据在传输过程中没有被篡改过。
3.安全验证
加密的另外一个用途是用来作为个人的标识,用户的密匙可以作为他的安全验证的标识。
ssl是利用公开密钥的加密技术(rsa)来作为用户端与服务器端在传送机密资料时的加密通讯协定。目前,大部分的web 服务器及浏览器都广泛支持ssl 技术。当浏览器试图连接一个具有ssl认证加密的服务器时,就会唤醒一个ssl会话,浏览器检查认证,必须具备下面三个条件:
1)有一个权威机构发放证书,当然可以创建自我签订的证书(x509 结构)。
2)证书不能过期。
3)证书是属于它所连接的服务器的。
只有全部具备了这三个条件,浏览器才能成功完成认证。通过这三个条件,用户能确认其浏览器连接到正确的服务器,而不是连接到一些想盗取用户密码等重要信息的虚假的服务器上。
在当今的电子商务中还有一项被广泛使用的安全协议是set协议。set(secure electronic transaction,安全电子交易)协议是由visa和mastercard两大信用卡公司于1997年5月联合推出的规范。set能在电子交易环节上提供更大的信任度、更完整的交易信息、更高的安全性和更少受欺诈的可能性。set交易分三个阶段进行:用户向商家购物并确定支付;商家与银行核实;银行向商家支付货款。每个阶段都涉及到rsa对数据加密,以及rsa数字签名。使用set协议,在一次交易中,要完成多次加密与解密操作,故有很高的安全性,但set协议比ssl协议复杂,商家和银行都需要改造系统以实现互操作。
在linux 下,比较流行支持ssl认证的是openssl服务器。openssl项目是一个合作的项目,开发一个健壮的、商业等级的、完整的开放源代码的工具包,用强大的加密算法来实现安全的socket层(secure sockets layer,ssl v2/v3)和传输层的安全性(transport layer security,tls v1)。这个项目是由全世界的志愿者管理和开发openssl工具包和相关文档。
如何在linux下配置openssl服务器,首先从openssl的主页(http://www.openssl.org/)上下载openssl-version.tar.gz软件包来编译安装,与apache服务器配合可以建立支持ssl的web服务器,并可以使用自我签订的证书做认证,关于如何编译、安装openssl服务器,可以参考一下openssl howto文档。
ssl 程序设计初步介绍
ssl 通讯模型为标准的c/s 结构,除了在 tcp 层之上进行传输之外,与一般的通讯没有什么明显的区别。在这里,我们主要介绍如何使用openssl进行安全通讯的程序设计。关于openssl 的一些详细的信息请参考openssl的官方主页 http://www.openssl.org。
在使用openssl前,必须先对openssl 进行初始化,以下的三个函数任选其一:
ssl_library_init(void);
openssl_add_ssl_algorithms();
ssleay_add_ssl_algorithms();
事实上 后面的两个函数只是第一个函数的宏。
如果要使用openssl的出错信息,使用ssl_load_error_strings (void)进行错误信息的初始化。以后可以使用void err_print_errors_fp(file *fp) 打印ssl的错误信息。
一次ssl连接会话一般要先申请一个ssl 环境,基本的过程是:
1. ssl_method* meth = tlsv1_client_method(); 创建本次会话连接所使用的协议,如果是客户端可以使用
ssl_method* tlsv1_client_method(void); tlsv1.0 协议
ssl_method* sslv2_client_method(void); sslv2 协议
ssl_method* sslv3_client_method(void); sslv3 协议
ssl_method* sslv23_client_method(void); sslv2/v3 协议
服务器同样需要创建本次会话所使用的协议:
ssl_method *tlsv1_server_method(void);
ssl_method *sslv2_server_method(void);
ssl_method *sslv3_server_method(void);
ssl_method *sslv23_server_method(void);
需要注意的是客户端和服务器需要使用相同的协议。
2.申请ssl会话的环境 ctx,使用不同的协议进行会话,其环境也是不同的。申请ssl会话环境的openssl函数是
sslk_ctx* ssl_ctx_new (ssl_method*); 参数就是前面我们申请的 ssl通讯方式。返回当前的ssl 连接环境的指针。
然后根据自己的需要设置ctx的属性,典型的是设置ssl 握手阶段证书的验证方式和加载自己的证书。
void ssl_ctx_set_verify (ssl_ctx* , int , int* (int, x509_store_ctx*) )
设置证书验证的方式。
第一个参数是当前的ctx 指针,第二个是验证方式,如果是要验证对方的话,就使用 ssl_verify_peer。不需要的话,使用ssl_verify_none.一般情况下,客户端需要验证对方,而服务器不需要。第三个参数是处理验证的回调函数,如果没有特殊的需要,使用空指针就可以了。
void ssl_ctx_load_verify_locations(ssl_ctx*, const char* , const char*);
加载证书;
第一个参数同上,参数二是证书文件的名称,参数三是证书文件的路径;
int ssl_ctx_use_certificate_file(ssl_ctx *ctx, const char *file, int type);
加载本地的证书;type 指明证书文件的结构类型;失败返回-1
int ssl_ctx_use_privatekey_file(ssl_ctx *ctx, const char *file, int type);
加载自己的私钥;type 参数指明私钥文件的结构类型;失败返回-1
加载了证书和文件之后,就可以验证私钥和证书是否相符:
bool ssl_ctx_check_private_key (ssl_ctx*);
3.既然ssl 使用tcp 协议,当然需要把ssl attach 到已经连接的套接字上了:
ssl* ssl_new (ssl_ctx*); 申请一个ssl 套节字;
int ssl_set_rfd (ssl*); 绑定只读套接字
int ssl_set_wfd (ssl*); 绑定只写套接字
int ssl_set_fd ( ssl*); 绑定读写套接字
绑定成功返回 1, 失败返回0;
4. 接下来就是ssl 握手的动作了
int ssl_connect (ssl*); 失败返回 -1
5. 握手成功之后,就可以进行通讯了,使用ssl_read 和ss_write 读写ssl 套接字代替传统的read 、write
int ssl_read (ssl *ssl, char *buf, int num );
int ssl_write (ssl *ssl, char *buf, int num);
如果是服务器,则使用 ssl_accept 代替传统的 accept 调用
int ssl_accept(ssl *ssl);
6. 通讯结束,需要释放前面申请的 ssl资源
int ssl_shutdown(ssl *ssl); 关闭ssl套接字;
void ssl_free (ssl); 释放ssl套接字;
void ssl_ctx_free (ctx); 释放ssl环境;
openssl 虽然已经发展到了0.9.96版本,但是它的文档还很少,甚至连最基本的man 函数手册都没有完成。所以,本文紧紧是讲述了使用openssl 进行程序设计的框架。更加详细的资料可以参考openssl 的文档或者 apache mod_ssl 的文档。
通过以上的介绍,我想读者对ssl协议已经有了一定的了解,作者有机会将会继续给大家介绍ssl协议的其他方面的内容。
(作者:张云帆)