前言
SSL是让人头大的东西,看起来很复杂,我学过信息安全课,但是对SSL仍然是模糊一片。对于数字证书也是一知半解,从来没有去认真研究过。只知道个大概,“反正就是对称加密和非对称加密”,详细的就不懂了。其实这些跟操作系统,计算机体系结构一样,是基础知识,即使你不是专门研究信息安全的,即使你平时用不到,这些东西也应该是必须了解的~ It’s not rocket science!
我这篇文章首先介绍有关信息安全的一些基本概念。然后分析数字证书的构成,用途以及SSL的工作原理。Enjoy!
计算机世界是基于网络的,根据目前网络的结构和实现,数据包在世界各地的路由器之间游荡,任何人都可以获得你的发送的数据包,从而获得你发送的数据。局域网内就更方便了,只要你开个Sniffer在那里监听,别人QQ聊天的信息一览无余啊~为什呢?我来简单解释一下计算机网络是如何传输数据的。
现实生活中,如果你请快递帮你寄东西,一般情况下,快递会把东西送到目的地,而不是其他地方。路由器就像是快递,在Internet上负责送数据。但和真实的快递不同的是,路由器会把你要发送的信息广播给离目的地更近的路由器,可能是一个路由器,也可能是多个路由器(别问我为啥,我不想深入了,有兴趣自己查资料)。这样你的信息就变成多份的了。复制虚拟的信息不值钱那~现实生活中的快递可不能复制你要寄的东西。一般情况下,只有一份数据会被目的计算机接收到,其他的拷贝在网络上游荡一段时间以后就被抛弃了。但是,这给黑客们有了很多可乘之机。他们在网络上监听很多垃圾信息,过滤掉没用的,留下他们感兴趣的,然后就可以偷窥别人隐私了。
正是因为网络有这样的问题,人们就发明了很多加密通信的手段,来保证自己的通信的内容不会被泄露。SSL和数字证书就是用来干这个的。
在解释SSL和数字证书之前,我觉得有必要解释一下几个有关信息安全的基本概念。
安全的定义
如果说两个人之间的通信是安全的,那么如何定义这个安全呢?
通常,我们平时说的“安全”往往只包括第一点,保密性。其实后面两点也是很重要的,特别是在信息安全领域。如果没有完整性和可获得性,光保密又有什么用呢?回到我们的主题,SSL和数字证书主要关注的是前两点。至于可获得性就需要涉及到硬件,管理等等了。
认证与授权
现在的问题是,我们如何保证上面所定义的“安全”?通常,有以下两个方法:
这里每一点都可能涉及很多不同的技术来保证过程的顺利进行。“授权”跟业务逻辑的牵扯比较大,SSL和数字证书更多的关注第一点。
加密是保护信息安全的常用手段之一。对信息的加密是需要加密算法的,如果加密算法被破解了,那么一切免谈。不过,基本上,要破解一个加密算法是非常非常困难的。至少,目前流行的加密算法还是安全的,所以我们也就不必考虑这个问题了。
散列(Hash)
经常用bt下载的人应该很熟悉这个。这就是MD5啊~虽然Hash不只是MD5,常见的还有SHA1。不过MD5最流行所以一般大家说的hash就是它了。值得一提的是,山东大学的王小云在2005年的时候发了一篇“ How to Break MD5 and Other Hash Functions”引起了信息安全界的轰动。虽然我没仔细研读过这篇paper,不过我相信按照paper里面的说法要破解MD5还是很费劲的,要不早就出乱子了。所以我们就不考虑这个问题了。那么究竟什么是MD5呢?我来简单解释一下。
Hash就是一个工具,能把任意大小的文档变成一个 固定大小(MD5是32个字符)的字符串。并且,这个过程是 不可逆的,也就是说,没有任何办法从那个字符串得到原来那个文档。还有很重要的一点是, 任意两个文档(哪怕极其相似)得到相同字符串的概率几乎等于0。现在你有一个10000字的文章,发给你的朋友,那你的朋友怎么判断他收到的文章一个标点符号都没有少呢?你在发送文章的同时把这个文章的Hash字符串也发过去,这样你的朋友收到文章以后,根据收到的文章重新计算一遍这个字符串,如果这个字符串和你发过去的一样,那就证明你朋友收到的文章是和你发送的一模一样。
对称加密(Symmetric Cryptography)
所谓加密就是把一段能看懂的东西通过某种变换变成看不懂的东西。当然这种变换是可逆的,否则加密有什么用啊!这里所说的“变换”就是加密算法。目前我们所说的加密算法基本上都是基于密钥的。加密算法不能单独工作,必须有密钥配合。就像现实生活中的锁,同一型号的锁的原理都一样,但是没把锁都有各自的钥匙,用来开锁和关锁。 加密的算法是公开的,但密钥是保密的。自己“发明”加密算法是很愚蠢的,除非你是密码学专家。历史上有很多使用自己发明的加密算法的笑话,往往你发明的算法都是自以为是,其实很容易破解的拉。而目前流行的加密算法都是经过时间和众人检验的,一般情况下,只要密钥不泄露,那就是安全的。有一点要说明的是,虽然我们平时一般说“加密算法”,但往往这个加密算法都包含解密算法的。 “对称加密”是指加密和解密的密钥是同一个。目前流行的对称加密算法有DES,AES,Blowfish等等。举个例子,你有一篇文章想要发给你朋友,但是你不想让别人看见这篇文章所以你选择AES加密。用的密钥是你和你朋友事先约定的,只有你们两个人知道。在发送之前,你用AES算法和约定好的密钥给文章加密,然后把加密过的文章发送给你的朋友。你朋友收到以后可以用AES算法和那个密钥解密而获得原始的那篇文章。 对称加密算法的优点是速度快,缺点是密钥管理不方便,要求共享密钥。
非对称加密(Asymmetric Cryptography)
如果你理解了上面讲的对称加密,那么这里的非对称加密就很简单了。从字面上理解就可以猜到, 加密和解密不是用的同一个密钥,其中一个称为公钥(public key),另一个称为私钥(private key)。公钥就是公开的,大家都知道,而私钥只有你自己知道。这两个密钥在数学上是有联系的,用公钥加密的内容只能由相应的私钥来解密,反过来,用私钥加密的内容只能由相应的公钥来解密。另外很重要的一点是, 不能从公钥推导出私钥,或者说很困难。常用的非对称加密算法有RSA,ECC等等。举个例子,你想要把一篇文章发送给你的朋友,但是不想让别人看到这篇文章。除了用上面讲的方法以外,你还可以用非对称加密来实现。在发送之前,你把文章用你朋友的公钥加密(公钥是公开的,每个人都知道),然后把加密过后的文章发送给你的朋友,你的朋友可以用他的私钥来解密。其他人获得了你传送的内容都是没有用的,因为只有你朋友有私钥可以解密。非对称加密算法的优点是密钥管理很方便,缺点是速度慢。
数字签名(Digital Signature)
我们先来看看现实生活中的签名是如何实现的。比如为信用卡账单签名,商家会打印一张消费单子给你,你看过以后觉得没有问题,于是在这张纸上签上自己的大名,表示你承认了这笔消费,并同意商家从你的信用卡账户扣钱。而商家可以对比你的签名和信用卡背后的签名是否一致来验证你是否冒用别人的信用卡(事实上很多商家不看的哦)。这个流程是基于一个假设的: 只有你自己能重现你的签名。虽然我们不能每次都签的一摸一样,但是通过笔迹鉴定,我们可以确定这个签名是否出自你手。分析一下,签名具有哪些特点呢?
相似的,在虚拟世界里,我们有数字签名来帮助证明某个文档是你创建的,或者是你认可的。 数字签名所用的技术是散列和非对称加密。数字签名的假设是: 只有你自己有你的私钥。根据前面对散列的介绍,我们先为你要签名的信息生成一个Hash字串,Hash1,然后用你的私钥加密得到Encrypted(Hash1),这就是你对这个文档的数字签名。当别人需要验证某个文档是否是你签名的时候,只需要用你的公钥解密你的签名得到Hash1,并和该文档计算出来的Hash2对比,查看是否一致。如果一致则说明你确实对该文档签过名,否则就是没有。下面来分析一下,数字签名是如何保证上面所讲的签名的特点的。
仔细想想数字签名和现实生活中的签名真的蛮像的,逻辑上是一样的。或许你在想,为什么要对Hash加密呢?我直接对文档用我的私钥加密不就完了嘛?对啊,效果是一样的,但是效率不一样哦~别忘了非对称算法是很慢的,加密一个100M的文件要算半天呢!
这里要顺便提一下消息认证码( Message Authentication Code)。 它和数字签名很相似,只不过它是用对称加密的而数字签名用的是非对称加密。
在现实生活中,各种加密手段往往是配合使用以达到最好的效果和效率。比如我将要介绍的SSL和数字证书,就是混合了各种的加密手段。
上面讲了这么多都是前戏,现在该到主题了。前面提到的认证(Authentication)的时候说,现实生活中可以用身份证和护照来证明身份, 那么在虚拟世界里,数字证书就是身份证。和现实生活不同的是,并不是每个上网的用户都有数字证书的,往往只有当一个人需要证明自己的身份的时候才需要用到数字证书。那么什么时候需要证明自己的身份呢?普通用户一般是不需要的,网站并不关心是谁访问了网站,现在的网站只关心流量啊~反过来,网站就需要证明自己的身份了。比如你想要提交信用卡信息给预定航班的网站,那么你如何确定你正在访问的网站就是你所想要访问的那个呢?现在 钓鱼网站很多的。比如你想访问的是“www.ctrip.com”,但其实你访问的是“www.otrip.com”,所以在提交自己的信息之前你需要验证一下网站的身份,要求网站出示数字证书。一般正常的网站都会主动出示自己的数字证书。由于证书在网页浏览中最为常见,所以我下面举的例子都是基于浏览器的。
数字证书的构成
我们的身份证是由公安机关颁发的,并加有很多防伪技术,不能伪造(或者说很难)。同样的,数字证书也有专门的发证机关(Certificate Authority,简称CA,其实是一些商业公司啦)。比较常见的发证机关是VeriSign。数字证书的发证机关会对自己发放的证书加上自己的数字签名,以保证证书不能被伪造。那数字证书到底包含了些什么呢?
基本信息就这些了(这些信息会在后面的章节有所解释),为了更清晰的说明问题,来几张截图:
这几张截图都是我从Firefox里面拷贝出来的,这张证书已经过期了,不过不影响理解。从图2我们可以看到,Certificate(证书)和Signature(签名)是分开的,但其实这个Signature也是证书的一部分。可以这么理解,数字证书包含证书主体和数字签名。证书中的签名是对证书主体的签名。
如何验证数字证书?
好了,现在我们有了虚拟世界的身份证了,那如何使用呢?和现实生活中检查身份证一样,包含三个步骤:
1. 检查身份证防伪标记
数字证书的防伪标记就是发证机关的私钥加密的那段内容。如何验证?首先我们是默认拥有发证机关的公钥的。如果是浏览器的话,常见的发证机关的公钥是内置的。如下图所示:
虽然Firefox内置的是数字证书,但是有数字证书就有公钥,所以是一样的。当浏览器拿到一个数字证书,先看发证机关,然后找到相应的发证机关的证书,获得发证机关的公钥,用此公钥解密被加密的MD5,这样就获得了此证书的MD5值,我们称它为Hash1。然后浏览器用MD5算法对此证书重新计算一遍MD5,获得Hash2。然后比较Hash1和Hash2是否相等。如果相等就证明这张证书是由发证机关颁发的,并且没有被篡改过。回过头去看看上面讲Hash和MD5的部分,你应该能想明白为什么的。
2. 核对相貌
在现实生活中,你的身份证只有一张,你应该好好保管不被别人拿到。但难免钱包丢了,身份证跟着遭殃。所以我们在验证完身份证的真假之后我们要验证持证的人,和身份证上所声明的那个人是不是同一个,我们往往通过比较相貌来辨别。那在虚拟世界又是怎样的呢?你应该已经发现,任何人都可以拥有你的证书就像我们装的Firefox就有很多发证机关的证书。所以核对持有证书人的身份就很重要了。这就要依赖证书里面包含的公钥了。此公钥是这张证书所有者的公钥(注意,我这里指的是所有者,而不是持有者!),我们用此公钥加密一段信息发送给证书的持有者,如果持有者能发送回(可以是被私钥加密,也可以是明文,没有关系)被加密的这段信息的话就证明该持有者拥有该证书对应的私钥,也就是说,该持有者就是该证书的所有者。
3. 核对姓名
最后一步,也是最重要的一步。看清楚了,站在你面前的人的名字和登记在册的名字一样。举个例子,我拿着护照去机场登机,护照和人都没有问题,问题是我根本没有买机票。如果机场工作人员只核对了前面两步的话,我就可以登机了,岂不是很荒谬?同样的,在虚拟世界,比如那个“ctrip”的例子,你拿到了一个证书,并且验证没有问题,但是证书上的Common Name明明写的是“otrip”,你还继续吗?
如果这三个步骤都没有问题,你就可以确信正在和你通信的对方是可以信任的,是你想要联系的那个人。
数字证书的级联(Certificate Chain)
根据上述讨论,我们可以知道,所有数字证书都是基于另外一张默认为可信任(浏览器内置)的数字证书的。也就是说,我们必须用一张已知合法的数字证书去验证另外一张未知的数字证书。第二节提到的发证机关的数字证书就是默认为可信任的。事实上,发证机关的证书是自己签发给自己的,验证没有意义。因为这些证书是人工配置在我们电脑上的,所以默认为安全的。这些证书称为“根证书”。
由于申请证书的人数众多,发证机关忙不过来,需要一些代理来帮忙签发证书,有可能代理也需要代理来帮忙。这样就产生了证书的层级关系,如下图所示:
这里的“www.paypal.com”是由二级代理“VeriSign Class 3 Extended Validation SSL SGC CA”签发的,而二级代理的证书又是由一级代理“VeriSign Class 3 Public Primary Certification Authority – G5”签发的,而一级代理的证书是由根证书机关“Buildin Object Token: Verisign Class 3 Public Primary Certification Authority”签发的。不必太关注这里的名字,名字而已,重要的是他们各自的位置。在验证这张证书的时候需要从下往上递归验证。先验证用户证书(最下面的证书,这里就是“www.paypal.com”),如果这样证书在浏览器的可信任列表里面那么验证到此结束,如果不是的话就要检查证书的防伪标记,这需要用到二级代理的证书,同样的,如果二级代理的证书在可信任列表里面,那么直接使用,否则就要检查二级代理证书的防伪标记,这需要用到一级代理的证书……直到根证书为止,如果根证书不在可信任列表里面,那么这张证书就没法验证了。这个过程的简单流程图是这样的:
需要注意的是,这是一个递归过程,所以这里的返回只是返回到上层递归。对于我们这个例子中的级联证书的验证可能是这样的:
这个过程看起来没有什么问题。但是仔细一想,发现有一个大问题。任何一个拥有合法证书的人都可以给别人签发证书了,不就是在这个继承关系上面多加一层吗?黄粱大梦!事情没那么简单啦~能够签发证书的叫CA,不管是否是代理,它都是CA,只有CA的证书才能拥有下级,那如何判断一张证书是否是CA呢?还记得我们在第一节讲过的证书中包含的扩展信息吗?这里可以放很多东西,包括这张证书的合法用途,如下图所示:
这里我们很清楚的可以看到用户证书是不能作为CA来用的,白纸黑字写着“Is not a Certificate Authority”。而CA的证书也有不同的权限。“Maximum number of intermediate CAs”说明了这个CA的权限大小。如果这个数字是0(比如这里的二级代理的证书),说明这个CA只能签发用户证书,而不能再授权其他机构为CA。如果这个数字是1,说明这个CA可以再授权一层代理,以此类推。图中没有显示根证书的Extension,因为根证书没有Extension,没有表示没有限制。在验证级联证书的时候,浏览器会检查证书的Extension,如果某个证书超范围使用了,浏览器会发出警告的。级联证书为证书的签发带来了很大的方便和灵活性。事实上我们可以看到,任何一张用户证书都应该是级联的,至少拥有一个上级证书(根证书)。所以在我们前面的例子中的“ebiz.isir.cmu.edu”这张证书是很奇怪的,不是标准的证书。这张证书是无法验证的,只在学校内部网上使用,默认接收就行了(浏览器会把它当成根证书来处理)。
关于数字证书,我还有几点想要提一下:
现在回到我们最原始的问题,由于Internet的架构问题,信息在网络上传输是很容易被别人获取的,那如何建立一个安全的传输网络呢?前面我们讨论了很多保证信息安全的技术,而SSL就是建立在这些技术的基础上的一套协议,用来保证通信的安全。SSL全称是 Secure Sockets Layer,它是一种间于传输层(比如TCP/ip)和应用层(比如HTTP)的协议。具体的SSL协议很复杂,我这里只讲一个大概。
最简单的方法来保证通信安全是用非对称加密。我们前面讲过数字证书的认证,如果双方都认证了对方的数字证书,那么每次传输信息的时候都用对方的公钥加密,这样就只有对方能解密,从而保证了信息的安全。但是对于日常应用(比如网页浏览)有两个问题:
SSL通过“握手协议”和“传输协议”来解决上述问题。握手协议是基于非对称加密的,而传输协议是基于对称加密的。根据不同的应用,SSL对证书的要求也是不一样的,可以是单方认证(比如HTTP, ftp),也可以是双方认证(比如网上银行)。通常情况下,服务器端的证书是一定要具备的,客户端的证书不是必须的。下面两张图片显示了SSL握手的过程。
握手协议可以看成是客户端和服务器协商的一个过程,结果就是一个对称密钥,然后就进入了传输协议的部分。也许,你在想,“现在还不简单吗?用这个对称密钥加密传输数据呗!”。否,没那么简单。先来看一下结果,等会儿再解释原因。在通信双方协商出一个对称密钥以后,他们用这个密钥来加密传输的数据。同时为每个消息生成时间戳,用此密钥为消息和相应的时间戳生成消息认证码(MAC)。也就是说,每次发送的内容包括 Encrypt(message) + MAC(message + timestamp)
这么做有几个好处:
1. 防止消息的篡改
所谓消息篡改就是有第三者插在通信双方之间,篡改往来的消息。由于消息是加密的,第三者不能获得消息的内容,但是他可以闭着眼睛瞎改。如果没有MAC的话,接受者就无法判断此消息是否被篡改过。
2. 防止消息重放
消息的重放是只第三者记录下通信双方的每一次发送的消息,虽然他不能获得消息的内容。但是它可以通过重新发送客户端或者服务端的信息来把自己装成是客户端或者服务端。如果在MAC里面加上了时间戳,消息接收方验证时间戳就可以阻止消息的重放攻击。
SSL的基本思想是用非对称加密来建立链接(握手阶段),用对称加密来传输数据(传输阶段)。这样既保证了密钥分发的安全,也保证了通信的效率。
通过上面对SSL的分析,我们可以看到,SSL并不能阻止别人获得你传输的数据,但是由于你传输的数据都是加密过的,别人拿到了毫无用处,一样可以保护信息的安全。还有一点需要强调一下,SSL并不依赖于TCP,它可以建立在任何可靠的传输层协议(比如TCP)之上。也就是说SSL是不能建立在UDP之上的。这是显然的,如果传输都不可靠,偶尔丢两个包或者包的顺序换一换的话,怎么保证安全呢?
来源:http://www.linuxde.net/2012/03/8301.html
-----------------------
最后,Startssl SSL证书就算申请好了
--------------------
介绍
网络安全已成为大家最关心的问题. 如果你利用服务器存储客户资料, 那你应该考虑使用 SSL 加密客户跟服务器之间的通讯. 随着这几年手机应用迅速崛起. 黑客也开始向手机应用转移, 原因有下列3点:
手机系统各式各样, 缺乏统一的标准.
许多程序员缺乏手机应用开发经验.
更严重的是, 通过手机应用, 黑客可以得到手机用户的隐私数据, 如:日程安排, 联系人信息, 网页浏览历史记录, 个人资料, 社交数据, 短信或者手机用户所在的地理位置.
最为一个网络安全爱好者的我, 最近花了几个月的时间对50到60安卓应用进行安全分析, 结果发现这些应用存在许多安全漏洞.
下面我主要讲一讲, 怎样才能写出比较安全的安卓代码.
从最基本的开始讲.
阅读本文前, 最好先看下 Ranjan.D article 写的一篇跟安卓连接有关的文章:(http://www.codeproject.com/Articles/818734/Article-Android-Connectivity).
下列代码用来打开一个 http 连接.
URL urlConnection = new URL("http://www.codeproject.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
不要在 http连接中打开:登陆页面, 或是传递用户名, 密码, 银行卡之类的重要个人资料. 这些重要个人数据应该通过 HTTPS 传输. (具体参看HTTPS).
HTTPS是什么?
HTTPS 其实就是个安全版的 http. HTTPS 能保证电子商务的交易安全. 如:网上银行.
像 IE 或者火狐浏览器, 如果出现下面的挂锁图标.
同时, 在浏览器的地址栏中以 https:// 开头, 这表示, 你的浏览器跟这个网站的数据往来都是安全的.
https 跟 http 的最大区别在于 https 多加了一个保障通讯安全的层.
像下列代码这样打开一个 https 连接, 可以保障这个连接的数据通讯安全.
URL urlConnection = new URL("https://www.codeproject.com/");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
HTTPS 通过 SSL/TLS 传递数据.
SSL/TLS:
SSL (Secure Sockets Layer) 是一种在客户端跟服务器端建立一个加密连接的安全标准. 一般用来加密网络服务器跟浏览器, 或者是邮件服务器跟邮件客户端(如: Outlook)之间传输的数据.
SSL 能保障敏感信息(如:银行卡号, 社保卡号, 登陆凭证等)的传输安全. 一般情况下, 数据在浏览器跟服务器之间的传输使用的是明文格式, 这种方式存在资料被窃取的风险. 如果黑客能拦截浏览器跟服务器之间的通讯数据, 就能看到通讯的内容.
SSL/HTTPS and X.509 证书概述
你要是对 SSL 或 X.509 证书一无所知, 那我大概解释下. 对于那些打算用自签名证书(self-signed certificate)的人来说, 需要了解自签名证书跟花钱购买机构颁发的证书有什么区别.
首先我们需要了解下 SSL 证书究竟是个什么东东? 其实它就包含俩部分: 1) 一个身份标识, 一个用来识别身份的东西, 有点类似警察叔叔通过护照或驾照查你的身份; 2) 一个公共密钥, 这个用来给数据加密, 而且只有证书的持有者才能解密. 简而言之, SSL 证书就俩个功能, 身份验证跟保障通讯过程中的数据安全.
另外还有一点很重要. 那就是一个证书可以给另外一个证书“签字”. 用 layman 的话说就是 Bob 用他自己的证书在别的证书上盖上 “同意” 两个红红的大字. 如果你信任 Bob (当然还有他的证书), 那么你也可以信任由他签发的证书. 在这个例子中, Bob 摇身一变, 成了证书颁发机构(Certificate Authority). 现在主流的浏览器都自带一大堆受信任证书颁发机构(trusted Certificate Authorities)(比如:Thawte, Verisign等).
最后我们讲一讲浏览器是怎么使用证书的. 笼统的讲, 当你打开下列连接的时候 “https://www.yoursite.com” :
服务器会给浏览器发一个证书.
浏览器会对比证书中的“common name”(有时也叫 “subject”) 跟服务器的域名是否一样. 例如, 一个从“www.yoursite.com” 网站发过来的证书就应该有一个内容是 “www.yoursite.com” 的 common name, 否则浏览器就会提示该证书有问题.
浏览器验证证书真伪, 有点像门卫通过证件上的全息图辨别你的证件是不是真的. 既然在现实生活中有人伪造别人的身份. 那么在网络世界也就有人造假, 比如用你的域名“www.yoursite.com” 来伪造一个安全证书. 浏览器在验证的时候, 会检查这个证书是否是它信任机构颁发的, 如果不是, 那么浏览器就会提示这个证书可能有问题. 当然, 用户可以选择无视警告, 继续使用.
一旦证书通过验证 (或是用户无视警告, 继续使用有问题的证书), 浏览器就开始利用证书中的公开密钥加密数据并传给服务器.
TLS (SSL)中的加密
一旦服务器发过来的证书通过验证, 浏览器就会利用证书中包含的公共密钥加密某个指定的共享密钥, 然后发给服务器. 这个加密过的共享密钥只能用服务器的私有密钥才能解密(非对称加密), 别人无法解密出其中的内容. 服务器把解密出来的共享密钥保存起来, 供本次连接会话专用. 从现在开始, 服务器跟浏览器之间的所有通讯信息都用这个共享密钥加密解密(对称加密).
理论部分就这么多, 下面我们来看几个例子.
在浏览器中打开网站 mail.live.com , 地址栏中会出现一个绿色图标, http 也会变成 https.
单击这个绿色图标, 然后点证书信息连接, 就能看到下列内容.
这是个 SSL 证书, 该证书是 Verisign 给 mail.live.cm 颁发的.
Verisign 是一个证书颁发机构, 它提示你的浏览器正在连接的网站是: mail.live.com, 需要跟这个网站的服务器建立一条安全连接进行通讯, 避免他人拦截或篡改浏览器跟服务器之间传递的数据.
MITM 攻击
MITM 攻击(MITMA)是指: 黑客拦截篡改网络中的通讯数据
被动 MITMA 是指黑客只能窃取通讯数据, 而在主动 MITMA 中, 黑客除了窃取数据, 还能篡改通讯数据. 黑客利用 MITMA 方式攻击手机要比攻击台式电脑容易的多. 这主要是因为使用手机的环境在不固定, 有些地方用手机连接上网并不安全, 尤其是那些对公众免费开放的无线网络热点.
证书颁发机构(CA)
·Symantec (which bought VeriSign's SSL interests and owns Thawte and Geotrust) 38.1% 市场份额
·Comodo SSL 29.1%
·Go Daddy 13.4%
·GlobalSign 10%
Jelly bean 版本的安卓系统中, 你可以在下列路径中找到证书颁发机构:
设置 -> 安全 -> 受信任的凭证.
Https 连接
URL url = new URL("https://www.example.com/");
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
InputStream in = urlConnection.getInputStream();
如果你连接的服务器(www.example.com)传过来的证书是由机构颁发的, 这段代码就能正常运行.
但是如果你连的服务器用的是自己颁发的证书(self-singed certificate), 那就会出现错误.
什么是自签名证书( self-signed certicates)
自签名证书就是没有通过受信任的证书颁发机构, 自己给自己颁发的证书.
SSL 证书大致分三类:
由安卓认可的证书颁发机构(如: VeriSign), 或这些机构的下属机构颁发的证书.
没有得到安卓认可的证书颁发机构颁发的证书.
自己颁发的证书, 分临时性的(在开发阶段使用)或在发布的产品中永久性使用的两种.
只有第一种, 也就是那些被安卓系统认可的机构颁发的证书, 在使用过程中不会出现安全提示.
为什么有人喜欢用自签名证书
免费. 购买受信任机构颁发的证书每年要交 100 到 500 美元不等的费用. 自签名证书不花一分钱.
自签名证书在手机应用中的普及率较高 (跟用电脑浏览网页不同, 手机的应用一般就固定连一台服务器.).
在开发阶段写的代码, 测试跟发布的时候也可以用.
最近一项调查表明, 810万个证书中, 只有 320万个是由受信任机构颁发的. 剩余490万证书中, 自签名的占48%, 未知机构颁发的占33%, 而不被信任的机构颁发的证书占19%.
无独有偶, 我的分析结果也表明, 起码有 60% 安卓应用使用自签证书.
个人以为, 在手机应用中使用自签名证书没什么不好, 既不需要花钱, 也不需要修改代码.(注:如果你用的是机构颁发的证书, 在产品发布阶段, 需要修改代码).
下面一般性的https请求代码
URL url = new URL("https://www.example.com/");
HttpsURLConnection urlConnection = (HttpsURLConnection)
url.openConnection();
InputStream in = urlConnection.getInputStream();
如果你使用上述的代代码去验证你的自己签署的证书,由于在android操作系统中自己签署的不能通过验证的,所以安卓应用软件将会抛出错误。因此你需要书写你自己的代码来检查你的自己签署的证书。
但是在这个领域中,安卓开发者犯了一个很大的错误,自己签署的证书在web开发中不是常见的,同时大多数安卓开发者来自于web开发者,所以开发者缺失在密码学的概念的知识。
在我分析中,我发现开发者仅仅是简单的复制、粘贴Stack Overflow和其他博客中允许你的应用默认信任所以证书的答案。即使大多说的答案表述仅仅在测试模式下可以使用,但是开发者简单地复制代码,将会导致应用软件在遭到中间件攻击和session黑客攻击是,表现的非常的脆弱!
例子:
http://stackoverflow.com/questions/2703161/how-to-ignore-ssl-certificate-errors-in-apache-httpclient-4-0
http://stackoverflow.com/questions/2012497/accepting-a-certificate-for-https-on-android?lq=1
http://www.caphal.com/android/using-self-signed-certificates-in-android/#toc_3
http://stackoverflow.com/questions/2642777/trusting-all-certificates-using-httpclient-over-https
在使用自己签署的证书时一般性的错误
信任所以的证书
TrustManager的主要责任是去决定提出的认证证书应该是可信任的。如果证书是不可信任的,那么连接将会被终止。去认证远程的安全套接字识别,你需要用一个或者多个TrustManager(s)初始化SSLContext对象。
import org.apache.http.conn.ssl.SSLSocketFactory;
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
我发现,80到100个应用软件中,在20到25个应用中实现了上述的代码。
在上述的TrustManager接口中,可以实现信任所以的证书,不论是谁签署的或者即使他们发布的任何主题。这个接口将会允许接受ANY证书。接受任何的证书将会危害数据的完整性、安全性等等。
在上述的例子中,检查客户端可信任性,获得接受事件,检查服务器端可信任性是三点重要的功能。每一位开发者都应该留意这三点功能的实现上。但是却很少有开发者从不同的网站中搜索、负责上述的功能。
允许所有的主机名。
忘记检查证书是否在这个地址发布是有可能的。当证书接受了example.com的服务器,那么另外的一个域名也将被接受。
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
DefaultHttpClient client = new DefaultHttpClient();
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
// Set verifier
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
// Example send http request
final String url = "https://www.paypal.com”
HttpPost httpPost = new HttpPost(url);
HttpResponse response = httpClient.execute(httpPost);
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
上述的代码中,即使是错误的实现,也将会接受对任何域名的任何CA证书声明。
Mixed-Mode/No SSL.
应用软件开发者在相同的应用中使用最大安全、不安全的连接,或者不使用SSL将是免费的。这不是直接的SSL声明,但是和提到的没有向外的签署个有关,同时对于一般软件的使用者,检查是否使用一个安全的连接是不可能的。这将会为例如SSL剥离,或者像FireSheep这样的攻击开后门。
SSL剥离是另外的一种可以使MITMA登陆并抵制SSL连接方式。利用使用最大HTTP和HTTPS应用。SSL剥离依赖大量建立在点击链接、或者来自于没有SSL重定向保护的网站SSL连接。在SSL剥离中,Mallory用HTTPS://取代了没有保护的网站中http:// 链接中。因此,除非使用者注意到了链接被篡改了,Mallory可以完全地规避SSL保护。这样的攻击主要与浏览器应用、或者原生使用安卓WebView应用有关。
更多关于SSL剥离的信息:
http://security.stackexchange.com/questions/41988/how-does-sslstrip-work
http://www.thoughtcrime.org/software/sslstrip/
!
证书锁定
直接在代码中固定写死使用某个服务器的证书. 然后在应用中使用自己定义的信任存储(trust store)代替手机系统自带的那个, 去连接指定的服务器.
这样做的好处是, 我们既能使用自签名证书, 又不需要额外安装其他证书.
优势
安全性提升 - 采用这种方式, 应用不再依赖系统自带的信任存储(trust store). 使得破解这种应用变得复杂: 首先你要反编译, 修改完后, 还要重新编译. 关键是你不可能使用应用作者原先用的那个 keystore 文件重新颁发证书.
成本降低 - 证书锁定方式让我们可以在自己的服务器上使用免费的自签名证书, 调用自己写的 API. 虽说复杂了点, 可是像这种既不花钱, 还能提高应用安全的好事上哪找去?
缺点
适应性较差 - 一旦 SSL 证书出现变动, 应用也要跟着升级. 再发布到 Google Play. 然后祈祷用户能都升级到最新版本.
安卓的 SSLContext 自带的 TrustManager 无法让本文示例中提到的自签名证书通过验证. 解决的办法是自己定义一个 TrustManager 类. 然后用这个类去验证自签名证书.
先把证书加载到 KeyStore, 然后用 KeyStore 生成一个 TrustManager 数组, 最后再用这个 TrustManager 数组创建 SSLContext.
本文的应用把服务器的证书直接存进应用的资源.(毕竟这个文件是所有用户都共用的, 而且也不会经常改动), 当然你可以把它存到别的地方.
实现的步骤
第1步: 创建自签名证书和.bks 文件
1)
创建 BKS 或者 keystore, 需要用到下面这个文件,bcprov-jdk15on-146.jar, 版本很多, 我用的是这个:http://www.bouncycastle.org/download/bcprov-jdk15on-146.jar, 下载后, 把文件存到 C:\codeproject.
然后用 Keytool 生成 keystore 文件.(keytool 是 Java SDK 自带的文件, 跟javac 放在同一个目录下)在命令提示符窗口中输入 keytool 就能看到这个工具的各种选项说明. 或者输入下列路径运行.
"C:\Program Files (x86)\Java\jre7\bin>keytool".
2)
下面是用 keytool 生成 keysotre 文件的命令. 要是这个文件已经存在, 这一步可以忽略.
keytool -genkey -alias codeproject -keystore C:\codeproject\codeprojectssl.keystore -validity 365
这行命令创建一个别名为 code project 的密钥(key), 生成的文件名是 codeprojectssl.keystore. 执行文件生成过程中会要求输入密钥(key)跟keystore的密码诸如此类的东东. 这里需要注意下, 当要求你录入 Common name 的时候, 要填你的主机名. 本文例子用的是: codeproject.com
3)
keytool -export -alias codeproject -keystore C:\codeproject\codeprojectssl.keystore -file C:\codeproject\codeprojectsslcert.cer
这行命令将密钥(key)从 .keystore 文件导入 .cer 文件.
4)
keytool -import -alias codeproject -file C:\codeproject\codeprojectsslcert.cer -keystore C:\codeproject\codeprojectssl.bks -storetype BKS -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath C:\codeproject\bcprov-jdk15on-146.jar
搞定! 现在, 全部 .bks 文件都生成了. 稍后将这些文件复制到安卓应用中. 连接那些使用自签名证书的服务器的时候会用到.
第2步
把 .keystore 文件复制到 /androidappdir/res/raw/
第3步
创建一个新类: MyHttpClient, 继承 DefaultHttpClient 类. 这个新类在验证SSL 证书的时候, 会自动加载我们自己创建的 keystore 文件, 而不是安卓自带的那个. 只要证书跟服务器匹配上了就没问题. 代码如下:
import java.io.InputStream;
import java.security.KeyStore;
import android.content.Context;
public class MyHttpClient extends DefaultHttpClient {
private static Context context;
public static void setContext(Context context) {
MyHttpClient.context = context;
}
public MyHttpClient(HttpParams params) {
super(params);
}
public MyHttpClient(ClientConnectionManager httpConnectionManager, HttpParams params) {
super(httpConnectionManager, params);
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// 用我们自己定义的 SSLSocketFactory 在 ConnectionManager 中注册一个 443 端口
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// 从资源文件中读取你自己创建的那个包含证书的 keystore 文件
InputStream in = MyHttpClient.context.getResources().openRawResource(R.raw.codeprojectssl); //这个参数改成你的 keystore 文件名
try {
// 用 keystore 的密码跟证书初始化 trusted
trusted.load(in, "这里是你的 keystore 密码".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); // 这个参数可以根据需要调整, 如果对主机名的验证不需要那么严谨, 可以将这个严谨程度调低些.
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
MyHttpClient 类的调用代码如下:
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.google.com");
// 以 GET 方式读取服务器返回的数据
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
-------------
一、什么是 SSL 证书,什么是 HTTPS
SSL 证书是一种数字证书,它使用 Secure Socket Layer 协议在浏览器和 Web 服务器之间建立一条安全通道,从而实现:
1、数据信息在客户端和服务器之间的加密传输,保证双方传递信息的安全性,不可被第三方窃听;
2、用户可以通过服务器证书验证他所访问的网站是否真实可靠。
(via百度百科)
HTTPS 是以安全为目标的 HTTP 通道,即 HTTP 下加入 SSL 加密层。HTTPS 不同于 HTTP 的端口,HTTP默认端口为80,HTTPS默认端口为443.
二、什么网站需要使用SSL证书
1、购物交易类网站
不用多说,网上银行、支付宝、Paypal等肯定会全程加密以保护你的信息安全。
2、注册与登陆
一些大的网站,比如电子邮箱,注册会员或者登陆的时候,会专门通过SSL通道,保证密码安全不被窃取。
总之涉及到用户重要隐私及安全方面的都需要
三、自行颁发不受浏览器信任的SSL证书
为晒晒IQ网颁发证书。ssh登陆到服务器上,终端输入以下命令,使用openssl生成RSA密钥及证书。
# 生成一个RSA密钥
$ openssl genrsa -des3 -out 33iq.key 1024
# 拷贝一个不需要输入密码的密钥文件
$ openssl rsa -in 33iq.key -out 33iq_nopass.key
# 生成一个证书请求
$ openssl req -new -key 33iq.key -out 33iq.csr
# 自己签发证书
$ openssl x509 -req -days 365 -in 33iq.csr -signkey 33iq.key -out 33iq.crt
第3个命令是生成证书请求,会提示输入省份、城市、域名信息等,重要的是,email一定要是你的域名后缀的。这样就有一个 csr 文件了,提交给 ssl 提供商的时候就是这个 csr 文件。当然我这里并没有向证书提供商申请,而是在第4步自己签发了证书。
使用openssl生成密钥和证书
编辑配置文件nginx.conf,给站点加上HTTPS协议
server {
server_name YOUR_DOMAINNAME_HERE;
listen 443;
ssl on;
ssl_certificate /usr/local/nginx/conf/33iq.crt;
ssl_certificate_key /usr/local/nginx/conf/33iq_nopass.key;
# 若ssl_certificate_key使用33iq.key,则每次启动Nginx服务器都要求输入key的密码。
}
重启Nginx后即可通过https访问网站了。
自行颁发的SSL证书能够实现加密传输功能,但浏览器并不信任,会出现以下提示:
不信任的安全证书
四、受浏览器信任的证书
要获取受浏览器信任的证书,则需要到证书提供商处申请。证书授证中心,又叫做CA机构,为每个使用公开密钥的用户发放一个数字证书。浏览器在默认情况下内置了一些CA机构的证书,使得这些机构颁发的证书受到信任。VeriSign即是一个著名的国外CA机构,工行、建行、招行、支付宝、财付通等网站均使用VeriSign的证书,而网易邮箱等非金融网站采用的是中国互联网信息中心CNNIC颁发的SSL证书。一般来说,一个证书的价格不菲,以VeriSign的证书为例,价格在每年8000元人民币左右。
据说也有免费的证书可以申请。和VeriSign一样,StartSSL也是一家CA机构,它的根证书很久之前就被一些具有开源背景的浏览器支持(Firefox浏览器、谷歌Chrome浏览器、苹果Safari浏览器等)。后来StartSSL竟然搞定了微软:在升级补丁中,微软更新了通过Windows根证书认证(Windows Root Certificate Program)的厂商清单,并首次将StartCom公司列入了该认证清单。现在,在Windows 7或安装了升级补丁的Windows Vista或Windows XP操作系统中,系统会完全信任由StartCom这类免费数字认证机构认证的数字证书,从而使StartSSL也得到了IE浏览器的支持。(来源及申请步骤)
五、只针对注册、登陆进行https加密处理
既然HTTPS能保证安全,为什么全世界大部分网站都仍旧在使用HTTP呢?使用HTTPS协议,对服务器来说是很大的负载开销。从性能上考虑,我们无法做到对于每个用户的每个访问请求都进行安全加密(当然,Google这种大神除外)。作为一个普通网站,我们所追求的只是在进行交易、密码登陆等操作时的安全。通过配置Nginx服务器,可以使用rewrite来做到这一点。
在https server下加入如下配置:
if ($uri !~* "/logging.php$")
{
rewrite ^/(.*)$ http://$host/$1 redirect;
}
在http server下加入如下配置:
if ($uri ~* "/logging.php$")
{
rewrite ^/(.*)$ https://$host/$1 redirect;
}
这样一来,用户会且只会在访问logging.php的情况下,才会通过https访问。
更新:有一些开发框架会根据 $_SERVER[‘HTTPS’] 这个 PHP 变量是否为 on 来判断当前的访问请求是否是使用 https。为此我们需要在 Nginx 配置文件中添加一句来设置这个变量。遇到 https 链接重定向后会自动跳到 http 问题的同学可以参考一下。
server {
...
listen 443;
location \.php$ {
...
include fastcgi_params;
fastcgi_param HTTPS on; # 多加这一句
}
}
server {
...
listen 80;
location \.php$ {
...
include fastcgi_params;
}
}
来源:http://www.lovelucy.info/nginx-ssl-certificate-https-website.html
参考链接:
http://zou.lu/nginx-https-ssl-module
http://blog.s135.com/startssl/
http://www.baalchina.net/2008/08/nginx-https-rewrite/
----------------
开发网页的时候,往往需要观察HTTP通信。
我使用的工具主要有两个,在Firefox中是Firebug,在IE中是Fiddler。但是,一直听别人说,付费软件HttpWatch是这方面最好的工具。
前几天,HttpWatch的官方网志刊登了一篇好文章,澄清了一些HTTPS协议容易产生误解的地方。学习之后,我增长了不少网页加密通信的知识。
我觉得这篇文章很实用,值得留作参考,就翻译了出来。
==============================================
HTTPS的七个误解
原文网址:http://blog.httpwatch.com/2011/01/28/top-7-myths-about-https/
译者:阮一峰
误解七:HTTPS无法缓存
许多人以为,出于安全考虑,浏览器不会在本地保存HTTPS缓存。实际上,只要在HTTP头中使用特定命令,HTTPS是可以缓存的。
微软的IE项目经理Eric Lawrence写道:
"说来也许令人震惊,只要HTTP头允许这样做,所有版本的IE都缓存HTTPS内容。比如,如果头命令是Cache-Control: max-age=600,那么这个网页就将被IE缓存10分钟。IE的缓存策略,与是否使用HTTPS协议无关。(其他浏览器在这方面的行为不一致,取决于你使用的版本,所以这里不加以讨论。)"
Firefox默认只在内存中缓存HTTPS。但是,只要头命令中有Cache-Control: Public,缓存就会被写到硬盘上。下面的图片显示,Firefox的硬盘缓存中有HTTPS内容,头命令正是Cache-Control:Public。
误解六:SSL证书很贵
如果你在网上搜一下,就会发现很多便宜的SSL证书,大概10美元一年,这和一个.com域名的年费差不多。而且事实上,还能找到免费的SSL证书。
在效力上,便宜的证书当然会比大机构颁发的证书差一点,但是几乎所有的主流浏览器都接受这些证书。
误解五:HTTPS站点必须有独享的IP地址
由于IPv4将要分配完毕,所以很多人关心这个问题。每个IP地址只能安装一张SSL证书,这是毫无疑问的。但是,如果你使用子域名通配符SSL证书(wildcard SSL certificate,价格大约是每年125美元),就能在一个IP地址上部署多个HTTPS子域名。比如,https://www.httpwatch.com和https://store.httpwatch.com,就共享同一个IP地址。
另外,UCC(统一通信证书,Unified Communications Certificate)支持一张证书同时匹配多个站点,可以是完全不同的域名。SNI(服务器名称指示,Server Name Indication)允许一个IP地址上多个域名安装多张证书。服务器端,Apache和Nginx支持该技术,IIS不支持;客户端,IE 7+、Firefox 2.0+、Chrome 6+、Safari 2.1+和Opera 8.0+支持。
误解四:转移服务器时要购买新证书
部署SSL证书,需要这样几步:
1. 在你的服务器上,生成一个CSR文件(SSL证书请求文件,SSL Certificate Signing Request)。
2. 使用CSR文件,购买SSL证书。
3. 安装SSL证书。
这些步骤都经过精心设计,保证传输的安全,防止有人截取或非法获得证书。结果就是,你在第二步得到的证书不能用在另一台服务器上。如果你需要这样做,就必须以其他格式输出证书。
比如,IIS的做法是生成一个可以转移的.pfx文件,并加以密码保护。
将这个文件传入其他服务器,将可以继续使用原来的SSL证书了。
误解三:HTTPS太慢
使用HTTPS不会使你的网站变得更快(实际上有可能,请看下文),但是有一些技巧可以大大减少额外开销。
首先,只要压缩文本内容,就会降低解码耗用的CPU资源。不过,对于当代CPU来说,这点开销不值一提。
其次,建立HTTPS连接,要求额外的TCP往返,因此会新增一些发送和接收的字节。但是,从下图可以看到,新增的字节是很少的。
第一次打开网页的时候,HTTPS协议会比HTTP协议慢一点,这是因为读取和验证SSL证书的时间。下面是一张HTTP网页打开时间的瀑布图。
同一张网页使用HTTPS协议之后,打开时间变长了。
建立连接的部分,大约慢了10%。但是,一旦有效的HTTPS连接建立起来,再刷新网页,两种协议几乎没有区别。先是HTTP协议的刷新表现:
然后是HTTPS协议:
某些用户可能发现,HTTPS比HTTP更快一点。这会发生在一些大公司的内部局域网,因为通常情况下,公司的网关会截取并分析所有的网络通信。但是,当它遇到HTTPS连接时,它就只能直接放行,因为HTTPS无法被解读。正是因为少了这个解读的过程,所以HTTPS变得比较快。
误解二:有了HTTPS,Cookie和查询字符串就安全了
虽然无法直接从HTTPS数据中读取Cookie和查询字符串,但是你仍然需要使它们的值变得难以预测。
比如,曾经有一家英国银行,直接使用顺序排列的数值表示session id:
黑客可以先注册一个账户,找到这个cookie,看到这个值的表示方法。然后,改动cookie,从而劫持其他人的session id。至于查询字符串,也可以通过类似方式泄漏。
误解一:只有注册登录页,才需要HTTPS
这种想法很普遍。人们觉得,HTTPS可以保护用户的密码,此外就不需要了。Firefox浏览器新插件Firesheep,证明了这种想法是错的。我们可以看到,在Twitter和Facebook上,劫持其他人的session是非常容易的。
咖啡馆的免费WiFi,就是一个很理想的劫持环境,因为两个原因:
1. 这种WiFi通常不会加密,所以很容易监控所有流量。
2. WiFi通常使用NAT进行外网和内网的地址转换,所有内网客户端都共享一个外网地址。这意味着,被劫持的session,看上去很像来自原来的登录者。
以Twitter为例,它的登录页使用了HTTPS,但是登录以后,其他页面就变成了HTTP。这时,它的cookie里的session值就暴露了。
也就是说,这些cookie是在HTTPS环境下建立的,但是却在HTTP环境下传输。如果有人劫持到这些cookie,那他就能以你的身份在Twitter上发言了。