15. 对称加密、非对称加密
在对称加密场景中,两个想通讯的人张三和李四,他们共同持有同一把密钥,张三可以把原始明文的文档,通过这一把密钥加密生成一个密文文档,而李四拿到文档以后呢,他可以用这把密钥还原转换为原始的明文文档,而中间的任何人如果没有持有这把密钥,即使他知道了对称加密的算法他也没有办法把密文还原成原始文档。
那么对称加密究竟的实现可以以RC4对称加密的序列算法来描述。
使用异或(xor)操作, 他是一个位操作,比如1和0进行异或得到1,0和1也得到了1,那么相同的1和1或者0和0进行异或操作都会得到0。
在一个场景下1010是共同持有的密钥,0110是明文,张三执行加密的时候就会得到密文1100。
1 0 1 0 # 密钥 xor # 异或操作 0 1 1 0 # 明文 | | # 输出 1 1 0 0 # 密文 复制代码
异或有一个对称的特性,就是把密文与密钥同样的做异或操作可以得到明文。
1 0 1 0 # 密钥 xor # 异或操作 1 1 0 0 # 密文 | | # 输出 0 1 1 0 # 明文 复制代码
密文可以用同一把密钥完全还原成了明文,所以对称加密有一个最大的优点就是他的性能非常的好,他只要遍历一次就可以得到最终的密文,解密的过程也是一样,而非对称加密他的性能就会差很多。
非对称加密根据一个数学原理,他会生成一对密钥,这一对密钥中如果称其中一个叫做公开钥匙(公钥),那么另一个就叫做私有钥匙(私钥)。
公钥和私钥作用就是同一份命名文档如果用公钥加密了那么只有用对应的私钥才能把它解密,同样道理,如果文档用私钥加密了用公钥才能解密。
比如说李四他有一对公钥和私钥,那么他就可以把他的公钥发布给大家,比如张三是其中的一个人,他拿到了李四的公钥,加密操作是怎么做的呢?
张三如果想传递一份原始文档给李四,那么张三就可以拿着李四的公钥对原始文档进行加密,把密文再发送给李四,李四用自己的私钥才能进行解密,其他人即使得到了这份文档也没有办法进行解密。
---------- ---------- ---------- | ------ | 李四的公钥 | ------ | 李四的私钥 | ------ | | ------ | -----------> | -- 密 -- | -----------> | ------ | | ------ | 加密 | ------ | 解密 | ------ | ---------- ---------- ---------- 原始文档 加密文档 原始文档 复制代码
公钥和私钥还有第二种用途,就是身份验证,比如现在有一段信息李四用它的私钥进行了加密,然后把密文发给了张三,只要张三如果可以使用李四的公钥解开这份文档,那么就证明这段密文确实是由李四发出的。因为只有李四有自己的加密私钥,如果是王五加密的文档张三用李四的公钥是解不开的,只有用李四私钥加密的使用李四的公钥才能解开。
16. SSL证书的公信力
这里其实还有个问题,李四怎么就知道消息真的是张三发过来的。这里面涉及到一个新的概念叫公信机构。在多方通信的过程中必须有一个公信机构CA,负责颁发证书和把证书过期的。
作为站点的维护者就是证书的订阅人,首先必须申请一个证书,申请证书可能需要登记是谁,属于什么组织,想做什么。
登记机构通过CSR发给CA,CA中心通过后会生成一对公钥和私钥,公钥在CA保存着,公钥私钥证书订阅人拿到之后就会把它部署到自己的web服务器,当浏览器访问站点的时候,服务器会把公钥证书发给浏览器,浏览器需要向CA验证证书是否合法和有效的。如果有效就证明没有被篡改。
由于CA会把过期的证书放在CRL服务器里,服务器会把所有过期的证书形成一条链条所以他的性能非常的差,后来又推出了OCSP程序可以就一个证书去查询是否过期,所以浏览器是可以直接去查询OCSP响应程序的,但OCSP响应程序性能还不是很高。
nginx会有一个OCSP的开关,当打开开关以后会由nginx主动的去OCSP去查询,大量的客户端直接从nginx就可以获取到证书是否有效。
证书一共有3种类型。
第一种叫做域名验证DV证书,也就是说证书只会去验证域名的归属是否正确,申请证书的时候只要域名指向的服务器是正在申请证书的服务器,就可以成功的申请到证书。
第二种证书叫做组织验证OV证书,组织验证就是在申请证书的时候会去验证填写的机构,企业名称是否是正确的,申请OV证书往往需要几天的时间,不像DV证书,基本上实时就可以获取到,OV证书的价格远远高于DV证书,DV证书很多都是免费的。
比OV证书做更严格的是EV证书,大部分浏览器对EV证书显示的非常友好,他会把证书申请时所填写的机构名称在浏览器的地址栏中显示出来。
浏览器在安全角度对DV,OV,,EV证书他的效果是一样的。唯一验证的就是证书链。
如果你点击网站地址栏中的锁头标志,打开证书链的时候,可以发现存在三个级别,目前所有主证书都是由根证书、二级证书、主证书三个证书构成的。
之所以需要三级机构是因为根证书的验证是非常谨慎的,如windows,安卓等操作系统每一年以上才会去更新一次根证书库,所以一个新的根证书CA机构是很难快速的加入到操作系统或者浏览器中的。
大部分浏览器他使用的是操作系统的证书库,只有像firefox这种浏览器会维护自己的根证书库,所以浏览器在验证证书是否有效时,除了验证有没有过期以外,最主要就是在验证根证书是不是有效的,是不是被跟证书库所认可的。
nginx在向浏览器发送证书的时候需要发送两个证书,根证书是被操作系统或者浏览器内置的并不需要发送。首先发送站点的主证书,接着会发送二级证书,浏览器会自动去认证二级证书的签发机构,根证书是不是有效的。
浏览器和服务器之间通信时确认对方是信赖的人其实就是验证给站点颁发根证书的发行者是不是有效的。
17. SSL协议握手时nginx的性能瓶颈
TLS的通信过程主要想完成四个目的。
1. 验证对方身份
浏览器会向服务器发送一个client hello消息。有一浏览器非常多样化,而且版本在不停的变更。所以不同的浏览器所支持的安全套件,加密算法都是不同的。这一步主要是告诉服务器,浏览器支持哪些加密算法。
2. 对安全套件达成共识
nginx有自己能够支持的加密算法列表,以及他倾向于使用的哪一个加密算法套件,nginx会选择一套他最喜欢的加密套件发送给客户端。
如果想复用session,也就是说nginx打开了session cache,希望在一天内断开链接的客户端不用再次协商密钥,可以直接去复用之前的密钥。
server hello信息中主要会发送究竟选择哪一个安全套件。
3. 传递并生成密钥
nginx会把自己的公钥证书发送给浏览器,公钥证书中包含证书链,浏览器可以找到自己的根证书库,去验证证书是否是有效。
4. 对数据进行加密通讯
服务器会发送server hello done,如果之前协商的安全套件是椭圆曲线算法,这时会把椭圆曲线的参数发送给客户端。客户端需要根据椭圆曲线的公共参数,生成自己的私钥后再把公钥发送给服务器。
服务器有了自己的私钥,会把公钥发送给客户端,服务端可以根据自己的私钥和客户端的私钥,共同生成双方加密的密钥。
客户端根据服务器发来的公钥和他自己的私钥也可以生成一个密钥。
服务器和客户端各自生成的密钥是相同的,是由非对称加密算法保证的。接着可以用生成的密钥进行数据加密,进行通信。
TLS通信主要在做两件事,第一个是交换密钥,第二个是加密数据,主要的性能消耗也是这两点。
nginx在这里是有性能优化的,主要是他的算法性能,对于小文件,握手是影响QPS性能的主要指标,对于大文件而言,主要考虑对称加密算法的性能比如AES,对称加密算法虽然性能很好,但是对非常大的一个文件,测吞吐量时还是AES的性能比较好的。
当以小文件为主时主要考验的是nginx的非对称加密的性能,比如说RSA,当主要处理大文件时主要考验的是对称加密算法的性能,比如说AES。
面对的场景是小文件比较多时重点应该优化椭圆曲线算法的一些密码强度,看是不是有所降低,当主要面对大的文件处理的时候需要考虑AES算法是不是可以替换为更有效的算法,或者把密码强度调得更小一些。
18. 用免费SSL证书实现一个HTTPS站点
首先需要有一个域名比如说yindong.zhiqianduan.com他是一个http的网址。
接着开始安装工具,必须的工具。
如果系统是CentOS,可以使用yum安装,优班图系统可以使用wget工具下载。
yum install pthon2-certbot-nginx 复制代码
安装好会提供certbot命令,当后缀加上--nginx的时候就开始为nginx的conf自动执行相应的修改。通常他会默认修改/usr/local/目录下的nginx配置。可以通过--nginx-server-root指定nginx.conf所在的路径。
使用-d指定需要申请证书的域名,比如说yindong.zhiqianduan.com。
certbot --nginx --nginx-server-root=/usr/local/nginx/conf/ -d yindong.zhiqianduan.com 复制代码
首先他会去获取一个证书,接着会等待验证,然后把证书部署到nginx.conf文件中。最后提示两个选择,第一不要做任何的重定向,第二做重定向。重定向就是将http的访问302到https从而禁掉不安全的http访问。
选择之后就可以使用https访问yindong.zhiqianduan.com域名了。https://yindong.zhiqianduan.com
他是在在server指令块中增加了443端口,让后将公钥证书和私钥证书部署好,并把一些通用的参数通过include加入到配置文件中。
因为ssl中最消耗性能是的握手,所以为了降低握手增加了sessin_cache, 设置1m,可以为大约4000个链接建立服务。也就是说每个http链接握手建立第一次以后如果断开了再次链接,那么在session_timeout时间以内是不用进行再次握手的。可以复用之前的密钥,session_timeout设置了1440m,也就是一天。
ssl_protocols表示https支持哪些版本的TLS协议,ssl_prefer_server_ciphers表示nginx开始决定使用哪些协议与浏览器进行通信,他是通过ssl_ciphers中的安全套件,所有的安全套件以分号分隔,是有顺序的,排在前面的会优先被使用。
最后server中的ssl_dhparam是表示加密的时候使用怎样的参数,这些参数会决定网络安全的加密强度。
19. 基于OpenResty用Lua语言实现简单服务
在openresty的站点(openresty.org)下载,在源码发布中找到最新版本,复制他的下载链接进行下载。
wget http://openresty.org/download/openresty-1.13.6.2.tar.gz 复制代码
下载完成以后解压压缩包,然后进入到源代码目录,可以发现openresty目录和nginx的源代码目录相比少了很多东西,少的这些东西都在bundle目录下,build目录是编译以后生成的一些中间目标文件。
在bundle目录中有很多模块,最核心的是nginx的源代码,也就说当前的OpenResty是基于对应的nginx版本进行的二次开发。
所有nginx对应版本中没有的特性都不可能出现在OpenResty的版本中。
其他的目录又分为两类,第一类是nginx的第三方模块,都是一些C模块,通常会以ngx开头。第二类模块是LUA模块,是lua代码写就的,他需要使用刚刚那些C模块提供的各种功能,在编译的时候主要是在编译C模块。
./configure --help | more 复制代码
通过帮助文件可以看到OpenResty和nginx基本没有太大的不同,只不过OpenResty他集成了很多第三方模块,比如http_echo, http_xss等等,这些在nginx的官方版本中是没有的。这些模块很多是OpenResty的作者写的。
最核心的lua_module核心模块通常是不能移除来的,移除来之后整个lua就不能运行了。其他的配置项和官方的nginx基本上是一样的。
./configure make install 复制代码
要将lua代码添加到OpenResty当中首先打开OpenResty的conf文件,在文件中是可以直接添加lua代码的,但是不能直接的把lua的语法放在conf中,因为nginx的解析器配置语法和lua代码是不相同的。
在OpenResty的nginx_lua_module中提供了几条指令,其中有一条叫做content_by_lua, 是在http请求处理的内容生成阶段用lua代码来处理。
增加一个location,当输入/lua的时候,使用lua代码进行处理, 为了使输出的文本能够以浏览器直接显示文本的方式显示,添加一个default_type text/html,在content_by_lua中加一些最简单的命令来演示lua是怎么生效的。
在OpenResty的lua模块中提供了一些API,比如说ngx.say会生成http响应,他是放在http请求的body中的,并不是放在header中的。
可以通过ngx.say语法将内容添加到body中的文本中。这里通过ngx.req.get_headers把用户请求时的http头取出来,然后找出UA,把值返回给浏览器。
server { server_name yindong.com; listen 80; location /lua { default_type text/html; content_by_lua 'ngx.say("User-Agent: ", ngx.req.get_headers()["User-Agent"])'; } location / { alias html/yindong/; } } 复制代码
访问/lua就可以看到效果了。
通过OpenResty的nginx_lua_http模块可以用它提供的API完成很多功能,可以用lua语言本身的一些工具库,把lua语言添加进来参与响应的过程。
可以用lua语言以及相应的提供的工具库直接访问redis,mysql或者tomcat等服务,然后把不同的响应通过程序逻辑组合成相应的内容返回给用户。
总结:
以上
作者:隐冬