HTTPS全称为Hypertext Transfer Protocol over Secure Socket Layer,中文含义为“超文本传输安全协议”。
HTTP协议是没有加密无状态的明文传输协议,如果APP采用HTTP传输数据,则会泄露传输内容,可能被中间人劫持,修改传输的内容。HTTPS相当于HTTP的安全版本,作用如下:
认证用户和服务器,确保数据发送到正确的客户机和服务器;(身份认证)
加密数据以防止数据中途被窃取;(内容加密)
维护数据的完整性,确保数据在传输过程中不被改变。(数据完整性)
Https通讯原理
HTTPS是HTTP over SSL/TLS,HTTP是应用层协议,TCP是传输层协议,在应用层和传输层之间,增加了一个安全套接层SSL/TLS:
TLS协议主要有五部分:应用数据层协议,握手协议,报警协议,加密消息确认协议,心跳协议。TLS协议本身又是有record协议传输的,record协议的格式如上图最右所示。
SSL/TLS层负责客户端和服务器之间的加解密算法协商、密钥交换、通信连接的建立,安全连接的建立过程如下所示:
简单描述如下:
- 浏览器将自己支持的一套加密算法、HASH算法发送给网站。
- 网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
- 浏览器获得网站证书之后,开始验证证书的合法性,如果证书信任,则生成一串随机数字作为通讯过程中对称加密的秘钥。然后取出证书中的公钥,将这串数字以及HASH的结果进行加密,然后发给网站。
- 网站接收浏览器发来的数据之后,通过私钥进行解密,然后HASH校验,如果一致,则使用浏览器发来的数字串使加密一段握手消息发给浏览器。
- 浏览器解密,并HASH校验,没有问题,则握手结束。接下来的传输过程将由之前浏览器生成的随机密码并利用对称加密算法进行加密。
数字证书、CA
信息安全的基础依赖密码学,密码学涉及算法和密钥,算法一般是公开的,而密钥需要得到妥善的保护,密钥如何产生、分配、使用和回收,这涉及公钥基础设施。
公钥基础设施(PKI)是一组由硬件、软件、参与者、管理政策与流程组成的基础架构,其目的在于创造、管理、分配、使用、存储以及撤销数字证书。公钥存储在数字证书中,标准的数字证书一般由可信数字证书认证机构(CA,根证书颁发机构)签发,此证书将用户的身份跟公钥链接在一起。CA必须保证其签发的每个证书的用户身份是唯一的。
链接关系(证书链)通过注册和发布过程创建,取决于担保级别,链接关系可能由CA的各种软件或在人为监督下完成。PKI的确定链接关系的这一角色称为注册管理中心(RA,也称中级证书颁发机构或者中间机构)。RA确保公钥和个人身份链接,可以防抵赖。如果没有RA,CA的Root 证书遭到破坏或者泄露,由此CA颁发的其他证书就全部失去了安全性,所以现在主流的商业数字证书机构CA一般都是提供三级证书,Root 证书签发中级RA证书,由RA证书签发用户使用的证书。
X509证书链,左边的是CA根证书,中间的是RA中间机构,右边的是用户:
.pfx格式和.cer格式的区别
购买的证书,格式为.pfx,带有公钥和私钥,附带一个密码。还有一种格式为.cer的证书,这种证书是没有私钥的。
带有私钥的证书
由Public Key Cryptography Standards #12,PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形式,以pfx作为证书文件后缀名(导出私钥,是需要输入密码的)。二进制编码的证书
证书中没有私钥,DER 编码二进制格式的证书文件,以cer作为证书文件后缀名。Base64编码的证书
证书中没有私钥,BASE64 编码格式的证书文件,也是以cer作为证书文件后缀名。
https加密
加密算法一般分为对称加密与非对称加密。HTTPS一般使用的加密与HASH算法如下:
非对称加密算法:RSA,DSA/DSS
对称加密算法:AES,RC4,3DES
HASH算法:MD5,SHA1,SHA256
对称加密
客户端与服务器使用相同的密钥对消息进行加密
优点:1.加密强度高,很难被破解 2.计算量小,仅为非对称加密计算量的 0.1%
缺点:1.无法安全的生成和管理密钥 2.服务器管理大量客户端密钥复杂
非对称加密
非对称指加密与解密的密钥为两种密钥。服务器提供公钥,客户端通过公钥对消息进行加密,并由服务器端的私钥对密文进行解密。
优点:安全
缺点: 1. 性能低下,CPU 计算资源消耗巨大,一次完全的 TLS 握手,密钥交换时的非对称加密解密占了整个握手过程的 90% 以上。而对称加密的计算量只相当于非对称加密的 0.1%,因此如果对应用层使用非对称加密,性能开销过大,无法承受。2. 非对称加密对加密内容长度有限制,不能超过公钥的长度。比如现在常用的公钥长度是 2048 位,意味着被加密消息内容不能超过 256 字节。
其中非对称加密算法用于在握手过程中加密生成的密码,对称加密算法用于对真正传输的数据进行加密,而HASH算法用于验证数据的完整性。
非对称密钥加密最大的一个问题,就是无法证明公钥本身就是货真价实的公钥。比如,正准备和某台服务器建立非对称密钥加密方式下的通信时,如何证明收到的公开密钥就是原本预想的那台服务器发行的公开密钥。或许在公开密钥传输途中,真正的公开密钥已经被攻击者替换掉了。
为了解决上述问题,可以使用由数字证书认证机构(CA,Certificate Authority)和其相关机关颁发的公开密钥证书。
Hash算法(摘要算法)
Hash算法特别的地方在于它是一种单向算法,用户可以通过hash算法对目标信息生成一段特定长度的唯一hash值,却不能通过这个hash值重新获得目标信息。因此Hash算法常用在不可还原的密码存储、信息完整性校验等。
常见的Hash算法有MD2、MD4、MD5、HAVAL、SHA
HTTPS采用混合加密机制
HTTPS采用对称密钥加密和非对称密钥加密两者并用的混合加密机制,在交换密钥环节使用非对称密钥加密方式(安全地交换在稍后的对称密钥加密中要使用的密钥),之后的建立通信交换报文阶段则使用对称密钥加密方式。
所以,AES+RSA结合才更好,AES加密数据,且密钥随机生成,RSA用对方(服务器)的公钥加密随机生成的AES密钥。传输时要把密文,加密的AES密钥和自己的公钥传给对方(服务器)。对方(服务器)接到数据后,用自己的私钥解密AES密钥,再拿AES密钥解密数据得到明文。这样就综合了两种加密体系的优点。下面代码展示OkHttp添加拦截器实现(要对response.code()做处理,只有在和后台约定好的返回码下才走解密的逻辑,具体看自己的需求):
public class DataEncryptInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
//请求
Request request = chain.request();
RequestBody oldRequestBody = request.body();
Buffer requestBuffer = new Buffer();
oldRequestBody.writeTo(requestBuffer);
String oldBodyStr = requestBuffer.readUtf8();
requestBuffer.close();
MediaType mediaType = MediaType.parse("text/plain; charset=utf-8");
//生成随机AES密钥并用serverPublicKey进行RSA加密
SecretKeySpec appAESKeySpec = EncryptUtils.generateAESKey(256);
String appAESKeyStr = EncryptUtils.covertAESKey2String(appAESKeySpec);
String appEncryptedKey = RSAUtils.encryptDataString(appAESKeyStr, serverPublicKey);
//计算body 哈希 并使用app私钥RSA签名
String appSignature = RSAUtils.signature(oldBodyStr, appPrivateKey);
//随机AES密钥加密oldBodyStr
String newBodyStr = EncryptUtils.encryptAES(appAESKeySpec, oldBodyStr);
RequestBody newBody = RequestBody.create(mediaType, newBodyStr);
//构造新的request
request = request.newBuilder()
.header("Content-Type", newBody.contentType().toString())
.header("Content-Length", String.valueOf(newBody.contentLength()))
.method(request.method(), newBody)
.header("appEncryptedKey", appEncryptedKey)
.header("appSignature", appSignature)
.header("appPublicKey", appPublicKeyStr)
.build();
//响应
Response response = chain.proceed(request);
if (response.code() == 200) {//只有约定的返回码才经过加密,才需要走解密的逻辑
//获取响应头
String serverEncryptedKey = response.header("serverEncryptedKey");
//用app的RSA私钥解密AES加密密钥
String serverDecryptedKey = RSAUtils.decryptDataString(serverEncryptedKey, appPrivateKey);
SecretKeySpec serverAESKeySpec = EncryptUtils.covertString2AESKey(serverDecryptedKey);
//用AES密钥解密oldResponseBodyStr
ResponseBody oldResponseBody = response.body();
String oldResponseBodyStr = oldResponseBody.string();
String newResponseBodyStr = EncryptUtils.decryptAES(serverAESKeySpec, oldResponseBodyStr);
oldResponseBody.close();
//构造新的response
ResponseBody newResponseBody = ResponseBody.create(mediaType, newResponseBodyStr);
response = response.newBuilder().body(newResponseBody).build();
}
response.close();
//返回
return response;
}
}
参考资料
https://www.cnblogs.com/alisecurity/p/5939336.html
Https原理和实现
Android Okhttp网络请求加解密实现方案
java CA证书制作和代码中使用