对HTTPS研究有一段时间了,在这里写下一些收集的资料和自己的理解。有不对的地方希望斧正。
1.为什么要使用HTTPS代替HTTP
1.1HTTPS和HTTP的区别
1)https协议需要到CA申请证书,一般免费证书很少,需要交费。
2)http是超文本传输协议,信息是明文传输,https则是具有安全性的SSL加密传输协议。
3)http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4)http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
1.2http为什么不安全
http协议没有任何的加密以及身份验证的机制,非常容易遭遇窃听、劫持、篡改,因此会造成个人隐私泄露,恶意的流量劫持等严重的安全问题。
就像寄信一样,我给你寄信,中间可能会经过很多的邮递员,他们可以拆开信读取里面的内容,因为是明文的。如果你的信里涉及到了你们银行账号等敏感信息,可能就会被窃取。除此之外,邮递员们还可以给你伪造信的内容,导致你遭到欺骗。
1.3https如何保证安全
HTTPS是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。它是一个URI scheme(抽象标识符体系),句法类同http:体系。用于安全的HTTP数据传输。https:URL表明它使用了HTTPS,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。这个系统的最初研发由网景公司进行,提供了身份验证与加密通讯方法,现在它被广泛用于万维网上安全敏感的通讯,例如交易支付方面。
2.HTTPS的加密原理
2.1首先先介绍一些加密过程中用到的原理:
2.1.1对称加密
对称加密是指加密和解密使用相同密钥的加密算法。它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信至关重要。
对称加密算法的优、缺点:
优点:算法公开、计算量小、加密速度快、加密效率高。
缺点:1)交易双方都使用同样钥匙,安全性得不到保证;
2)每对用户每次使用对称加密算法时,都需要使用其他人不知道的惟一钥匙,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的负担。
3)能提供机密性,但是不能提供验证和不可否认性。
2.1.2非对称加密算法
这种加密或许理解起来比较困难,这种加密指的是可以生成公钥和私钥。凡是公钥加密的数据,公钥自身不能解密,而需要私钥才能解密;凡是私钥加密的数据,私钥不能解密,需要公钥才能解密。这种算法事实上有很多,常用的是RSA,其基于的数学原理是两个大素数的乘积很容易算,而拿到这个乘积去算出是哪两个素数相乘就很复杂了,具体原理有兴趣可以自行研究。
非对称加密相比对称加密更加安全,但也存在两个明显缺点:
1)CPU计算资源消耗非常大。一次完全TLS握手,密钥交换时的非对称解密计算量占整个握手过程的90%以上。而对称加密的计算量只相当于非对称加密的0.1%,如果应用层数据也使用非对称加解密,性能开销太大,无法承受。
2)非对称加密算法对加密内容的长度有限制,不能超过公钥长度。比如现在常用的公钥长度是2048位,意味着待加密内容不能超过256个字节。
所以公钥加密目前只能用来作密钥交换或者内容签名,不适合用来做应用层传输内容的加解密。
2.1.3身份认证(CA数字证书)
https协议中身份认证的部分是由数字证书来完成的,证书由公钥、证书主体、数字签名等内容组成,在客户端发起SSL请求后,服务端会将数字证书发给客户端,客户端会对证书进行验证,并获取用于秘钥交换的非对称密钥。
数字证书有两个作用:
1,身份授权。确保浏览器访问的网站是经过CA验证的可信任的网站。
2,分发公钥。每个数字证书都包含了注册者生成的公钥。在SSL握手时会通过certificate消息传输给客户端。
申请一个受信任的数字证书通常有如下流程:
1,终端实体(可以是一个终端硬件或者网站)生成公私钥和证书请求。
2,RA(证书注册及审核机构)检查实体的合法性。如果个人或者小网站,这一步不是必须的。
3,CA(证书签发机构)签发证书,发送给申请者。
4,证书更新到repository(负责数字证书及CRL内容存储和分发),终端后续从repository更新证书,查询证书状态等。
数字证书验证:
申请者拿到CA的证书并部署在网站服务器端,那浏览器发起握手接收到证书后,如何确认这个证书就是CA签发的呢?怎样避免第三方伪造这个证书?答案就是数字签名(digital signature)。数字签名是证书的防伪标签,目前使用最广泛的SHA-RSA(SHA用于哈希算法,RSA用于非对称加密算法)数字签名的制作和验证过程如下:
1)数字签名的签发。首先是使用哈希函数对待签名内容进行安全哈希,生成消息摘要,然后使用CA自己的私钥对消息摘要进行加密。
2)数字签名的校验。使用CA的公钥解密签名,然后使用相同的签名函数对待签名证书内容进行签名并和服务端数字签名里的签名内容进行比较,如果相同就认为校验成功。
需要注意的是:
1)数字签名签发和校验使用的密钥对是CA自己的公私密钥,跟证书申请者提交的公钥没有关系。
2)数字签名的签发过程跟公钥加密的过程刚好相反,即是用私钥加密,公钥解密。
3)现在大的CA都会有证书链,证书链的好处一是安全,保持根CA的私钥离线使用。第二个好处是方便部署和撤销,即如果证书出现问题,只需要撤销相应级别的证书,根证书依然安全。
4)根CA证书都是自签名,即用自己的公钥和私钥完成了签名的制作和验证。而证书链上的证书签名都是使用上一级证书的密钥对完成签名和验证的。
5)怎样获取根CA和多级CA的密钥对?它们是否可信?当然可信,因为这些厂商跟浏览器和操作系统都有合作,它们的公钥都默认装到了浏览器或者操作系统环境里。
2.2加密的详细过程
首先服务器端用非对称加密(RSA)产生公钥和私钥。然后把公钥发给客 户端,路径或许有人会截取,但是没有用,因为用公钥加密的文件只有私钥可以解密,而私钥永远都不会离开服务器的。当公钥到达客户端之后,客户端会用对称加密产生一个秘钥并且用公钥来加密发送给服务器端,这个秘钥就是以后用来通信的钥匙。这样服务器端收到公钥加密的秘钥时就可以用私钥来解公钥从而获得秘钥。这样的话客户端和服务器端都获得了秘钥,信息交流相对是安全的。流程图如下:
听起来确实是挺安全的,但实际上,还有一种更恶劣的攻击是这种方法无 法防范的,这就是传说中的“中间人攻击”。在身份认证的过程中,出现了一个“中间人”拦截我们的信息,他有意想要知道你们的消息。我们将这个中间人称为M。当服务器第一次给客户端发送公钥的时候,途径M。M知道你要进行密钥交换了,它把公钥扣了下来,假装自己是客户端,伪造了一个伪秘钥(对称加密产生的),然后用服务器发来的公钥加密了伪秘钥发还给服务器,这样服务器以为和客户端完成了密钥交换,实际上服务器是和M完成了密钥交换(获得了伪秘钥)。同时M假扮成服务器自行用非对称加密产生伪公钥和伪私钥,与客户端进行秘钥交换,拿到客户端发送过来的秘钥。现在客户端拿着秘钥,M拿着秘钥和为伪秘钥,服务器拿着伪秘钥,整个交流的过程就是:
简单点说就是:
1)客户端用秘钥加密信息发送给M;
2)M收到后用秘钥解密拿到信息,然后用伪秘钥加密信息发送给服务器;
3)服务器收到后用伪秘钥解密拿到信息。
这样中间人M就拿到了客户端和服务器所有的交流信息。
对于这种攻击,我们可以加上身份认证:这个时候就要引入CA证书,CA证书的原理可回到2.1.3。数字证书中包括的主要内容有:证书拥有者的个人信息、证书拥有者的公钥、公钥的有效期、颁发数字证书的CA、CA的数字签名等。所以网上双方经过相互验证数字证书后,不用再担心对方身份的真伪,可以放心地与对方进行交流或授予相应的资源访问权限。
通俗一点理解就是,服务器端把公钥交个CA证书,CA证书再包装一层。(具体原理请回看2.3)然后再发给客户端,这个包装一层的意思是:保证这个证书是我(服务器)给你(客户端的),其他人拿到了也没有用。
最后,你可能会想既然非对称加密可以那么安全,为什么我们不直接用它来加密信息,而是用来加密对称加密的密钥呢?
这是因为非对称加密的密码对生成和加密的消耗时间比较长,为了节省双方的计算时间,通常只用它来交换密钥,而非直接用来传输数据(具体的可看上文非对称加密的缺点)。
3.使用AFNetworking进行双向认证
3.1客户端认证服务器端证书
如上图所示客户端想要认证服务器,首先需要和服务端的数字证书匹配(server.cer),具体方法如下。
1)在项目中导入证书sever.cer和AFNetworking框架:
2)然后到AFSecurityPolicy.m中重写+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode方法:
AFNetworking2是允许内嵌证书的,通过内嵌证书,AFNetworking2通过比对服务器端证书、内嵌的证书、站点域名是否一致来验证连接的服务器是否正确。在完成以上两条的情况下,会自动扫描bundle中.cer的文件,并引入,这样就可以通过自签证书来验证服务器唯一性了。
3.2服务器端认证客户端
1)服务端验证客户端证书,首先把服务端的证书client.p12导入到服务端的密钥库里,同时导入工程;
2)在AFURLConnectionOperation.m中加入以下方法:
3)重写AFURLConnectionOperation.m中的- (void)connection:(NSURLConnection*)connection
如果是需要认证的时候不会先调用didReceiveResponse,而是先调用3)和2)的函数,NSURLAuthenticationChallenge是一个认证挑战类,也就是要求客户端进行挑战,要接收挑战也就是客户端提供挑战的凭证(用户和密码,或者客户端证书,或者信任服务器证书,或者代理),IOS提供了一个NSURLCredential的类来表示挑战凭证。可以通过如下函数来建立挑战凭证。所以访问https的时候服务器认证客户端就调用这个方法。
这两段代码是通过p12文件来验证服务器的,需要自己修改的地方只有一个,那就是2)中的CFStringRefpassword =CFSTR("123456");这是p12证书的密码,用自己的p12证书密码替换"123456"。
4.3控制器里如何请求
通过4.1和4.2我们的客户端和服务器双向认证已经设置好了,在控制器里只需要需要调用manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];的方法来进行双向认证:
然后就可以访问HTTPS的服务器了。