先来一个例子
A公司的小明被派到B公司办事情。B公司如何信任小明是A公司派来的呢?普通介绍信
为了让B公司信任小明,A公司特意给小明开了一封介绍信,在信件中详细说明了小明的特征以及小明过来的目的, 并且声明这个小明确实是A公司派来的,除此之外还要有一个A公司的公章。 这样B公司前台小姐姐拿到介绍信后,通过信件内容和A公司公章就能判断出小明确实是A公司派来的员工。 那万一A公司公章是假的呢?毕竟公章伪造太容易了,这样岂不是会存在问题。咱们就暂且认为公章这种东西很难伪造, 否则故事无法继续喽。引入第三方中介公司
好,回到刚才的话题。如果和B公司有业务往来的公司很多,每个公司的公章都不同,那B公司的前台小姐姐就要懂得分辨各种公章, 非常滴麻烦。所以,有某个中介公司C,发现了这个商机。C公司专门开设了一项“代理公章”的业务。 于是今后,A公司的业务员去B公司,需要带2个介绍信: 介绍信1(含有C公司的公章及A公司的公章。并且特地注明:C公司信任A公司。) 介绍信2(仅含有A公司的公章,然后写上:兹有xxx先生/女士前往贵公司办理业务,请给予接洽......。) 这样不是增加麻烦了吗?有啥好处呢? 主要的好处在于,对于接待公司的前台,就不需要记住各个公司的公章分别是啥样子的,她只要记住中介公司C的公章即可。 当她拿到两份介绍信之后,先对介绍信1的C公章验明正身,确认无误之后,再比对“介绍信1”和“介绍信2”的两个A公章是否一致。 如果是一样的,那就可以证明“介绍信2”是可以信任的了。相关专业术语的解释
下面就着上面的例子,把相关的名词,作一些解释。 什么是证书?
证书,洋文也叫“digital certificate”或“public key certificate”。 它是用来证明某某东西确实是某某的东西,通俗地说,证书就好比例子里面的公章。通过公章, 可以证明该介绍信确实是对应的公司发出的。 理论上,人人都可以找个证书工具,自己做一个证书。那如何防止坏人自己制作证书出来骗人呢?什么是CA?
CA 是“Certificate Authority”的缩写,也叫“证书授权中心”。它是负责管理和签发证书的第三方机构, 就好比例子里面的中介C公司。 一般来说,CA必须是所有行业和所有公众都信任的、认可的。因此它必须具有足够的权威性。 就好比A、B两公司都必须信任C公司,才会找C公司作为公章的中介。什么是CA证书?
CA证书,顾名思义,就是CA颁发的证书。 前面已经说了,人人都可以找工具制作证书。但是你一个小破孩制作出来的证书是没啥用处的。 因为你不是权威的CA机关,你自己搞的证书不具有权威性。 这就好比上述的例子里,某个坏人自己刻了一个公章,盖到介绍信上。但是别人一看, 不是受信任的中介公司的公章,就不予理睬。什么是证书之间的信任关系?
在开篇的例子里谈到,引入中介后,业务员要同时带两个介绍信。第一个介绍信包含了两个公章,并注明,公章C信任公章A。 证书间的信任关系,就和这个类似。就是用一个证书来证明另一个证书是真实可信滴。什么是证书信任链?
实际上,证书之间的信任关系,是可以嵌套的。 比如,C信任A1,A1信任A2,A2信任A3......这个叫做证书的信任链。 只要你信任链上的头一个证书,那后续的证书,都是可以信任滴。什么是根证书?
根证书的洋文叫“root certificate”,为了说清楚根证书是咋回事,再来看个稍微复杂点的例子。 假设C证书信任A和B;然后A信任A1和A2;B信任B1和B2。则它们之间,构成如下的一个树形关系(一个倒立的树)。 处于最顶上的树根位置的那个证书,就是“根证书”。除了根证书,其它证书都要依靠上一级的证书,来证明自己。 那谁来证明“根证书”可靠呢? 实际上,根证书自己证明自己是可靠滴(或者换句话说,根证书是不需要被证明滴)。 聪明的同学此刻应该意识到了:根证书是整个证书体系安全的根本。 所以,如果某个证书体系中,根证书出了问题(不再可信了),那么所有被根证书所信任的其它证书,也就不再可信了。证书有啥用?
CA证书的作用有很多,只列出常用的几个。验证网站是否可信(针对HTTPS)
通常,我们如果访问某些敏感的网页(比如用户登录的页面),其协议都会使用HTTPS而不是HTTP,因为HTTP协议是明文的, 一旦有坏人在偷窥你的网络通讯,他/她就可以看到网络通讯的内容(比如你的密码、银行帐号、等)。 而 HTTPS 是加密的协议,可以保证你的传输过程中,坏蛋无法偷窥。 但是,千万不要以为,HTTPS协议有了加密,就可高枕无忧了。 假设有一个坏人,搞了一个假的网银的站点,然后诱骗你上这个站点。 假设你又比较单纯,一不留神,就把你的帐号,口令都输入进去了。那这个坏蛋的阴谋就得逞了。 为了防止坏人这么干,HTTPS 协议除了有加密的机制,还有一套证书的机制。通过证书来确保,某个站点确实就是某个站点。 有了证书之后,当你的浏览器在访问某个HTTPS网站时,会验证该站点上的CA证书(类似于验证介绍信的公章)。 如果浏览器发现该证书没有问题(证书被某个根证书信任、证书上绑定的域名和该网站的域名一致、证书没有过期), 那么页面就直接打开,否则的话,浏览器会给出一个警告,告诉你该网站的证书存在某某问题,是否继续访问该站点。验证文件是否可信
本文参考于 https://program-think.blogspot.com/2010/02/introduce-digital-certificate-and-ca.html
单向认证,仅仅是客户端需要检验服务端证书是否是正确的,而服务端不会检验客户端证书是否是正确的。 双向认证,指客户端验证服务器端证书,而服务器也需要通过CA的公钥证书来验证客户端证书。
双向验证的过程:
1.客户端say hello 服务端 2.服务端将证书、公钥等发给客户端 3.客户端CA验证证书,成功继续、不成功弹出选择页面 4.客户端将自己的证书和公钥发送给服务端 5.服务端验证客户端证书,如不通过直接断开连接 6.客户端告知服务端所支持的加密算法 7.服务端选择最高级别加密算法使用客户端公钥加密后发送给客户端 8.客户端收到后使用私钥解密并生成随机对称密钥key,使用服务端公钥加密发送给服务端 9.服务端使用私钥解密,获取对称密钥key 10.后续客户端与服务端使用该密钥key进行加密通信配置说明
1. 443端口为ssl监听端口。 2. ssl on表示打开ssl支持。 3. ssl_certificate指定crt文件所在路径,如果写相对路径,必须把该文件和nginx.conf文件放到一个目录下。 4. ssl_certificate_key指定key文件所在路径。 5. ssl_protocols指定SSL协议。 6. ssl_ciphers配置ssl加密算法,多个算法用:分隔,ALL表示全部算法,!表示不启用该算法,+表示将该算法排到最后面去。 7. ssl_prefer_server_ciphers 如果不指定默认为off,当为on时,在使用SSLv3和TLS协议时,服务器加密算法将优于客户端加密算法。配置示例:
{ listen 443 ssl; server_name www.testlinux.com; index index.html index.php; root /data/wwwroot/testlinux.com; ssl on; ssl_certificate server.crt; ssl_certificate_key server.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ALL:!DH:!EXPORT:!RC4:+HIGH:+MEDIUM:!eNULL; ssl_prefer_server_ciphers on; ssl_client_certificate ca.crt; //这里的ca.crt是根证书公钥文件 ssl_verify_client on; ... }ginx错误日志平时不用太关注,但是一旦出了问题,就需要借助错误日志来判断问题所在。
配置参数格式:error_log /path/to/log level;Nginx错误日志级别
常见的错误日志级别有debug | info | notice | warn | error | crit | alert | emerg 级别越高记录的信息越少,如果不定义,默认级别为error. 它可以配置在main、http、server、location段里。 如果在配置文件中定义了两个error_log,在同一个配置段里的话会产生冲突,所以同一个段里只允许配置一个error_log。 但是,在不同的配置段中出现是没问题的。Nginx错误日志示例
error_log /var/log/nginx/error.log crit;如果要想彻底关闭error_log,需要这样配置
error_log /dev/null;Nginx访问日志格式 Nginx访问日志可以设置自定义的格式,来满足特定的需求。 访问日志格式示例 示例1
log_format combined_realip '$remote_addr $http_x_forwarded_for [$time_local]' '$host "$request_uri" $status' '"$http_referer" "$http_user_agent"';示例2
log_format main '$remote_addr [$time_local] ' '$host "$request_uri" $status "$request"' '"$http_referer" "$http_user_agent" "$request_time"'; 若不配置log_format或者不在access_log配置中指定log_format,则默认格式为: '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent";常见变量
变量说明$time_local通用日志格式下的本地时间;(服务器时间)$remote_addr客户端(用户)IP地址$status请求状态码,如200,404,301,302等$body_bytes_sent发送给客户端的字节数,不包括响应头的大小$bytes_sent发送给客户端的总字节数$request_length请求的长度(包括请求行,请求头和请求正文)$request_time请求处理时间,单位为秒,小数的形式$upstream_addr集群轮询地址$upstream_response_time指从Nginx向后端(php-cgi)建立连接开始到接受完数据然后关闭连接为止的时间$remote_user用来记录客户端用户名称$request请求方式(GET或者POST等)+URL(包含 r e q u e s t m e t h o d , request_method, requestmethod,host,$request_uri)$http_user_agent用户浏览器标识$http_host请求的url地址(目标url地址)的host$host等同于$http_host$http_referer来源页面,即从哪个页面转到本页,如果直接在浏览器输入网址来访问,则referer为空$uri请求中的当前URI(不带请求参数,参数位于 a r g s ) , 不 同 于 浏 览 器 传 递 的 args),不同于浏览器传递的 args),不同于浏览器传递的request_uri的值,它可以通过内部重定向,或者使用index指令进行修改。$document_uri等同于$uri$request_uri比 u r i 多 了 参 数 , 即 uri多了参数,即 uri多了参数,即uri+$args$http_x_forwarded_for如果使用了代理,这个参数会记录代理服务器的ip和客户端的ip调整Linux内核参数
作为高性能WEB服务器,只调整Nginx本身的参数是不行的,因为Nginx服务依赖于高性能的操作系统。 以下为常见的几个Linux内核参数优化方法。1 net.ipv4.tcp_max_tw_buckets
对于tcp连接,服务端和客户端通信完后状态变为timewait,假如某台服务器非常忙,连接数特别多的话,那么这个timewait数量就会越来越大。 毕竟它也是会占用一定的资源,所以应该有一个最大值,当超过这个值,系统就会删除最早的连接,这样始终保持在一个数量级。 这个数值就是由net.ipv4.tcp_max_tw_buckets这个参数来决定的。 CentOS7系统,你可以使用sysctl -a |grep tw_buckets来查看它的值,默认为32768, 你可以适当把它调低,比如调整到8000,毕竟这个状态的连接太多也是会消耗资源的。 但你不要把它调到几十、几百这样,因为这种状态的tcp连接也是有用的, 如果同样的客户端再次和服务端通信,就不用再次建立新的连接了,用这个旧的通道,省时省力。2 net.ipv4.tcp_tw_recycle = 1
该参数的作用是快速回收timewait状态的连接。上面虽然提到系统会自动删除掉timewait状态的连接,但如果把这样的连接重新利用起来岂不是更好。 所以该参数设置为1就可以让timewait状态的连接快速回收,它需要和下面的参数配合一起使用。3 net.ipv4.tcp_tw_reuse = 1
该参数设置为1,将timewait状态的连接重新用于新的TCP连接,要结合上面的参数一起使用。4 net.ipv4.tcp_syncookies = 1
tcp三次握手中,客户端向服务端发起syn请求,服务端收到后,也会向客户端发起syn请求同时连带ack确认, 假如客户端发送请求后直接断开和服务端的连接,不接收服务端发起的这个请求,服务端会重试多次, 这个重试的过程会持续一段时间(通常高于30s),当这种状态的连接数量非常大时,服务器会消耗很大的资源,从而造成瘫痪, 正常的连接进不来,这种恶意的半连接行为其实叫做syn flood攻击。 设置为1,是开启SYN Cookies,开启后可以避免发生上述的syn flood攻击。 开启该参数后,服务端接收客户端的ack后,再向客户端发送ack+syn之前会要求client在短时间内回应一个序号, 如果客户端不能提供序号或者提供的序号不对则认为该客户端不合法,于是不会发ack+syn给客户端,更涉及不到重试。5 net.ipv4.tcp_max_syn_backlog
该参数定义系统能接受的最大半连接状态的tcp连接数。客户端向服务端发送了syn包,服务端收到后,会记录一下, 该参数决定最多能记录几个这样的连接。在CentOS7,默认是256,当有syn flood攻击时,这个数值太小则很容易导致服务器瘫痪, 实际上此时服务器并没有消耗太多资源(cpu、内存等),所以可以适当调大它,比如调整到30000。6 net.ipv4.tcp_syn_retries
该参数适用于客户端,它定义发起syn的最大重试次数,默认为6,建议改为2。7 net.ipv4.tcp_synack_retries
该参数适用于服务端,它定义发起syn+ack的最大重试次数,默认为5,建议改为2,可以适当预防syn flood攻击。8 net.ipv4.ip_local_port_range
该参数定义端口范围,系统默认保留端口为1024及以下,以上部分为自定义端口。这个参数适用于客户端, 当客户端和服务端建立连接时,比如说访问服务端的80端口,客户端随机开启了一个端口和服务端发起连接, 这个参数定义随机端口的范围。默认为32768 61000,建议调整为1025 61000。9 net.ipv4.tcp_fin_timeout
tcp连接的状态中,客户端上有一个是FIN-WAIT-2状态,它是状态变迁为timewait前一个状态。 该参数定义不属于任何进程的该连接状态的超时时间,默认值为60,建议调整为6。10 net.ipv4.tcp_keepalive_time
tcp连接状态里,有一个是established状态,只有在这个状态下,客户端和服务端才能通信。正常情况下,当通信完毕, 客户端或服务端会告诉对方要关闭连接,此时状态就会变为timewait,如果客户端没有告诉服务端, 并且服务端也没有告诉客户端关闭的话(例如,客户端那边断网了),此时需要该参数来判定。 比如客户端已经断网了,但服务端上本次连接的状态依然是established,服务端为了确认客户端是否断网, 就需要每隔一段时间去发一个探测包去确认一下看看对方是否在线。这个时间就由该参数决定。它的默认值为7200秒,建议设置为30秒。11 net.ipv4.tcp_keepalive_intvl
该参数和上面的参数是一起的,服务端在规定时间内发起了探测,查看客户端是否在线,如果客户端并没有确认, 此时服务端还不能认定为对方不在线,而是要尝试多次。该参数定义重新发送探测的时间,即第一次发现对方有问题后,过多久再次发起探测。 默认值为75秒,可以改为3秒。12 net.ipv4.tcp_keepalive_probes
第10和第11个参数规定了何时发起探测和探测失败后再过多久再发起探测,但并没有定义一共探测几次才算结束。 该参数定义发起探测的包的数量。默认为9,建议设置2。 设置和范例 在Linux下调整内核参数,可以直接编辑配置文件/etc/sysctl.conf,然后执行sysctl -p命令生效 结合以上分析的各内核参数,范例如下 net.ipv4.tcp_fin_timeout = 6 net.ipv4.tcp_keepalive_time = 30 net.ipv4.tcp_max_tw_buckets = 8000 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_syn_backlog = 30000 net.ipv4.tcp_syn_retries = 2 net.ipv4.tcp_synack_retries = 2 net.ipv4.ip_local_port_range = 1025 61000 net.ipv4.tcp_keepalive_intvl = 3 net.ipv4.tcp_keepalive_probes = 2 [root@centos-03 vhost]# sysctl -a |grep tw_buckets net.ipv4.tcp_max_tw_buckets = 40961.查看time-wait数量
ss -an