什么是HTTPS
大家都知道http,为什么现在又多了一个https呢?HTTP是明文传输的,也就意味着,介于发送端、接收端中间的任意节点都可以知道传输的内容是什么。这些节点可能是路由器、代理等。
举个最常见的例子,用户登陆。用户输入账号,密码,采用HTTP的话,只要在代理服务器上做点手脚就可以拿到你的密码了。
用户登陆 --> 代理服务器(做手脚)–> 实际授权服务器
如果在发送端对密码进行加密?没用的,虽然别人不知道你原始密码是多少,但能够拿到加密后的账号密码,照样能登陆。
HTTPS工作流程
HTTPS其实就是 secure http 的意思啦,也就是HTTP的安全升级版。稍微了解网络基础的都知道,HTTP是应用层协议,位于HTTP协议之下是传输协议TCP。TCP负责传输,HTTP则定义了数据如何进行包装。
HTTP --> TCP (明文传输)
HTTPS相对于HTTP有哪些不同呢?其实就是在HTTP跟TCP中间加多了一层加密层TLS/SSL 。
原先是应用层将数据直接给到TCP进行传输,现在改成应用层将数据给到TLS/SSL,将数据加密后,再给到TCP进行传输。自然就安全了,就算你的数据被人截胡了,他也看不懂是什么意思。
HTTPS如何加密数据
对安全或密码学基础有了解的同学,应该知道常见的加密手段。一般来说,加密分为对称加密、非对称加密(也叫公开密钥加密)。
对称加密
对称加密的意思就是,加密数据用的密钥,跟解密数据用的密钥是一样的。 对称加密的优点在于加密、解密效率通常比较高。缺点在于,数据发送方、数据接收方需要协商、共享同一把密钥,并确保密钥不泄露给其他人。此外,对于多个有数据交换需求的个体,两两之间需要分配并维护一把密钥,这个带来的成本基本是不可接受的。比如Base64,DES,PBE。
话虽如此,但是一些简单的小项目(那种一个后端配一个前端APP的项目),甚至有些官方的APP,跟后端交互还真就是用的DES对称加密。
非对称加密
非对称加密需要两把密钥:公钥和私钥,他们是一对,如果用公钥对数据加密,那么只能用对应的私钥解密。如果用私钥对数据加密,只能用对应的公钥进行解密。因为加密和解密用的是不同的密钥,所以称为非对称加密。
(1) A 要向 B 发送信息,A 和 B 都要产生一对用于加密和解密的公钥和私钥。
(2) A 的私钥保密,A 的公钥告诉 B;B 的私钥保密,B 的公钥告诉 A。
(3) A 要给 B 发送信息时,A 用 B 的公钥加密信息,因为 A 知道 B 的公钥。
(4) A 将这个消息发给 B (已经用 B 的公钥加密消息)。
(5) B 收到这个消息后,B 用自己的私钥解密 A 的消息。其他所有收到这个报文的人都无法解密,因为只有 B 才有 B 的私钥。
这就很像邮局的邮筒,邮筒的钥匙就是私钥,管理员自己持有,邮筒的投递口就是公钥,所有人都看得到。你要去寄信的话,需要你把信投入口子(公钥加密),除了管理员外,其他人因为没有钥匙(私钥),所以无法解密,只有管理员可以打开邮筒,看到信件。
HTTPS通讯安全
上面说了对称加密和非对称加密,那么https用的哪一种呢,很多人第一反应是第二种,因为搞过https的都知道,需要去申请一个SSL/TLS证书,这玩意不就是公钥吗?
也对也不对。
https确实用到了非对称加密,但是那只是为了传递客户端自己的私钥,后面传输都是对称加密,如下图。
再用文字描述下。
-
你要访问百度网站,输入https://www.baidu.com。
-
百度返回自己的CA证书给浏览器,也就是公钥。
-
你的浏览器生成一个加密字符串,作为浏览器自己的私钥(浏览器自己没有,也不需要公钥)。
-
你的浏览器使用百度的公钥,对自己的私钥对称加密,并回传给百度。
-
百度拿到加密后的密钥,因为就是用自己的公钥加密的,所以完全可以再根据自己的私钥解密,得到你的浏览器生成的私钥。(这个过程别人就算拿到这个密钥也没用,因为他们没有百度的私钥)
-
之后百度跟你浏览器通信,都会发送用浏览器私钥加密后的数据,浏览器回传也会用自己的私钥加密。
关于证书
证书就是公钥。
网站可以自己签发证书,比如我们本地可以用jdk直接签发一个SSL证书,需要包含
-
颁发证书的机构的名字 也就是 CA
-
证书内容本身的数字签名(用CA私钥加密)
-
证书持有者的公钥
-
证书签名用到的hash算法
以SpringBoot项目为例,我们随便打开一个cmd窗口,输入以下内容:
keytool -genkeypair -alias springboot -keyalg EC -keysize 256 -validity 365 -keypass 123456 -keystore EC_keystore.jks -storepass 123456 -storetype jks
- alias springboot // 指定生成的 keystore 中 entry 也就是证书的别名,我们证书的名字就叫做springboot
- keyalg EC // 指定加密算法,RSA 是大家最常用的,这里使用其它算法演示
- keysize 256 // 指定加密算法的长度,不同算法,对应着不同的长度限制,比如 DSA,长度不能超过2048
- validity 365 // 指定证书的有效期
- keypass 123456 // 指定证书的密码
- keystore EC_keystore.jks // 指定 keystore 文件名,默认路径就是执行命令行的当前路径
- storepass 123456 // 指定 keystore 的密码
- storetype jks // 指定 keystore 的类型
得到证书:
这样生成的就是我们这台电脑,自己持有的证书,江湖人称“根证书”。浏览器通常会内置大多数主流权威CA(证书颁发机构)的根证书,我们的电脑又不是权威CA机构,所以浏览器是不信任的。
我们把这个证书放到resources目录中。
再去配置文件中指定。
server:
port: 8889
ssl:
key-alias: springboot
key-password: 123456
key-store: classpath:EC_keystore.jks
key-store-password: 123456
key-store-type: jks
启动项目,可以看到日志中已经是https了:
访问 https://localhost:8889
我们的电脑不是权威CA机构,所以浏览器是不信任的,不过我们也可以选择继续访问。
阿里云选购SSL免费证书
如果我们是生产环境要选用SSL证书,可以去阿里云或者其他平台选购免费的,虽然可靠性和安全性比不上那些大型的CA机构,但是个人用用是完全足够了。
登录阿里云官网,搜ssl:
选购SSL证书
选择第二个,免费证书
可以一次性获取20个免费证书
购买,有效期只有3个月
完成购买。
然后在证书管理页面去创建证书
验证方式可以手动DNS验证,也可以文件验证。
文件验证会下载一个文本文件,要求你去改服务器代码,让对应url可以访问到这个校验的文本即可,然后就会成功下发证书。
最终得到的就是这两个文件:
PEM文件包含CA证书,而KEY文件包含私钥。因为你是服务器,这个私钥对客户端来说,就是服务端的公钥,我是这么理解的。而pem文件就相当于CA机构的根证书做了个分身给你,以后客户端见到你,就如同见到CA机构,你的可信任度得到了提升。
怎么在服务端配置HTTPS
上面那两个证书,我直接放到了nginx服务器的conf目录,然后在nginx.conf文件中加上:
server {
listen 443 ssl;
ssl_certificate xxx.pem;
ssl_certificate_key xxx.key;
server_name localhost;
location / {
proxy_pass http://localhost:8888;
proxy_set_header Host $host:8888;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
443和80都是服务器的默认端口,443是SSL专用的,这样当有请求发到443端口,就会被https拦截,解密后发到8888端口(实际后端的地址)。
于是乎,咱们的网站就支持HTTPS啦~