https的实现
httpd启用压缩–常用配置
- 使用mod_deflate模块压缩页面优化传输速度
- 适用场景:
- (1) 节约带宽,额外消耗CPU;同时,可能有些较老浏览器不支持
- (2) 压缩适于压缩的资源,例如文本文件
- LoadModule deflate_module modules/mod_deflate.so SetOutputFilter DEFLATE
- SetOutputFilter DEFLATE 启用压缩
- #Restrict compression to these MIME types
- AddOutputFilterByType DEFLATE text/plain
- AddOutputFilterByType DEFLATE text/html
- AddOutputFilterByType DEFLATE application/xhtml+xml
- AddOutputFilterByType DEFLATE text/xml
- AddOutputFilterByType DEFLATE application/xml
- AddOutputFilterByType DEFLATE application/x-javascript
- AddOutputFilterByType DEFLATE text/javascript
- AddOutputFilterByType DEFLATE text/css
- Level of compression (Highest 9 - Lowest 1)
- DeflateCompressionLevel 9 指定压缩比
- 排除特定旧版本的浏览器,不支持压缩
- Netscape 4.x 只压缩text/html
- BrowserMatch ^Mozilla/4 gzip-only-text/html
- Netscape 4.06-08三个版本 不压缩
- BrowserMatch ^Mozilla/4\.0[678] no-gzip
- Internet Explorer标识本身为“Mozilla / 4”,但实际上是能够处理请求的压缩。如果用户代理首部匹配字符串“MSIE”(“B”为单词边界”),就关闭之前定义的限制
- BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
1、压缩的MIME的资源类型主要是针对文本文件进行压缩;对于视频,音频等资源不用进行压缩。
示例:对*.txt文件进行压缩传输:
~]# vim /etc/httpd/conf.d/test.conf
AddOutputFilterByType DEFLATE text/plain
DeflateCompressionLevel 9
压缩只是在网络中传输时以压缩形式传输的,到达浏览器时自动解压缩.
测试:~]# curl -I --compressed http://192.168.38.88/k.txt
....
Content-Encoding: gzip
...
压缩不压缩是双方协商的结果即要以压缩形式在网络中传输,浏览器版本得支持压缩。
使用curl命令时需要使用--compressed明确指出curl支持压缩。
https
-
https 监听端口 443/tcp
-
http默认是明文传输,在生产中对于安全性比较高的场合,一般需要使用https=http+ssl
-
https:http over ssl
-
SSL会话的简化过程
- (1) 客户端发送可供选择的加密方式,并向服务器请求证书
- (2) 服务器端发送证书以及选定的加密方式给客户端
- (3) 客户端取得证书并进行证书验证
如果信任给其发证书的CA
(a) 验证证书来源的合法性;用CA的公钥解密证书上数字签名
(b) 验证证书的内容的合法性:完整性验证
© 检查证书的有效期限
(d) 检查证书是否被吊销
(e) 证书中拥有者的名字,与访问的目标主机要一致 - (4) 客户端生成临时会话密钥(对称密钥),并使用服务器端的公钥加密此数据发送给服务器,完成密钥交换
- (5) 服务用此密钥加密用户请求的资源,响应给客户端
-
注意:SSL是基于IP地址实现,单IP的主机仅可以使用一个https虚拟主机
2、https实现
- (1) 为服务器申请数字证书
- 测试:通过私建CA发证书
(a) 创建私有CA
(b) 在服务器创建证书签署请求
© CA签证
- 测试:通过私建CA发证书
- (2) 配置httpd支持使用ssl,及使用的证书
- yum -y install mod_ssl
- 配置文件:/etc/httpd/conf.d/ssl.conf
DocumentRoot
ServerName
SSLCertificateFile
SSLCertificateKeyFile
- (3) 测试基于https访问相应的主机
- openssl s_client [-connect host:port] [-cert filename] [-CApath directory] [-CAfile filename]
如果就是一个网站实现https,生成自签名证书的实现可以使用mod_ssl模块。
# dnf install mod_ssl 安装模块
# systemctl restart httpd 重启服务
# tree /etc/pki/tls/ 查看目录生成的文件
# ls /etc/pki/tls/certs/localhost.crt 自签名证书
# ls /etc/pki/tls/private/localhost.key 证书私钥
# openssl x509 -in /etc/pki/tls/certs/localhost.crt -noout -text 查看自签名证书内容
目前443已处于监听状态,说明目前已经支持了https
- 安装自签名的证书,至受信任的根证书颁发机构,可以使得浏览器信任改证书颁发机构。
此方式实现https是安装的mod_ssl模块,重启服务,自动生成的自签名证书。仅适用于实验环境。企业使用一般不会使用这这样的方式,企业一般是应该是从一些著名的CA颁发机构向人家申请证书,然后填写相关信息,最后CA颁发会返回三个文件,CA证书,网站的证书,和网站的私钥文件。
然后在自己的web server端加以配置,/etc/httpd/conf.d/ssl.conf 此文件指明的三个相关证书文件所在的路径
此处模拟实验是以192.168.38.17作为CA给192.168.38.88(web server)签署证书申请,然后返回是CA证书,网站的证书,和网站的私钥文件三个文件,服务器端再进行自己的相应配置。
【实验:私建CA,签署httpd的证书】
- CA ip :192.168.38.17 centos7
- httpd ip: 192.168.38.88 centos8
在192.168.38.17主机上创建CA和httpd证书和httpd网站私钥
私建CA:
cd /etc/pki/CA/
(umask 066;openssl genrsa -out private/cakey.pem 2048)
openssl req -x509 -key private/cakey.pem -out cacert.pem -days 3650
touch index.txt
echo 01 > serial
生成httpd的私钥和证书签署请求:
mkdir /data/ssl
cd /data/ssl
(umask 066;openssl genrsa -out httpd.key 2048)(注:1024位数不够)
openssl req -new -key httpd.key -out httpd.csr
签署httpd的证书:
cd /etc/pki/CA/
openssl ca -in /data/ssl/httpd.csr -out certs/httpd.crt
cp certs/httpd.crt /data/ssl/
cp cacert.pem /data/ssl/
将生成的CA证书,网站的证书,和网站的私钥文件三个文件拷贝至httpd主机:
scp -r /data/ssl/ 192.168.38.88:/etc/httpd/conf.d/
在httpd主机上配置:
确认当前主机的CA、证书和秘钥文件
# cd /etc/httpd/conf.d/ssl
# ll
-rw-r--r-- 1 root root 1294 Oct 9 09:07 cacert.pem
-rw-r--r-- 1 root root 3670 Oct 9 09:07 httpd.crt
-rw------- 1 root root 891 Oct 9 09:07 httpd.key
与ssl相关的配置:首先安装mod_ssl模块
然后修改其配置文件:
vim /etc/httpd/conf.d/ssl.conf
将对应的CA、证书、秘钥的路径在配置文件中修改即可
重启httpd服务
windows解析文件:C:\Windows\System32\drivers\etc\hosts
http重定向https
实现让http自动跳转至https,让用户不用主动输入https
- 将http请求转发至https的URL
- 重定向
Redirect [status] URL-path URL - status状态:
- permanent: 返回永久重定向状态码 301
- temp:返回临时重定向状态码302. 此为默认值
- 示例:
Redirect temp / https://www.xxx.com/
以访问jd.com为例:
# curl -I http://www.jd.com
HTTP/1.1 302 Moved Temporarily
.......
Location: https://www.jd.com/ 临时跳转至https
.....
# curl -I http://www.360buy.com (京东早期域名)
HTTP/1.1 301 Moved Permanently
Location: http://www.jd.com/ 永久重定向
永久重定向和临时重定向区别:
永久重定向:永久重定向的如果有缓存,不会缓存下来,不能使用。
临时重定向:临时重定向的缓存信息是可以使用的。
- 注:redirect temp / https://www.xxx.net 这样直接重定向会产生问题,循环不断的重定向导致出现问题
http 至 https的重定向实现:
# redirect temp / https://www.xxx.net 循环不断的重定向导致出现问题。注释了~~~
RewriteEngine on
RewriteRule ^(/.*)$ https://%{HTTP_HOST}$1 [redirect=302]
- 访问步骤:
上述实现的重定向存在的问题:
上述重定向的实现需要用户发请求http,然后再次发生https访问请求,即第一次请求走的还是http,这样存在第一次的安全风险。
【解决办法】 ==>HSTS
- HSTS:HTTP Strict Transport Security
服务器端配置支持HSTS后,会在给浏览器返回的HTTP首部中携带HSTS字段。浏览器获取到该信息后,会将所有HTTP访问请求在内部做307跳转到HTTPS。而无需任何网络过程 - HSTS将在浏览器内部自动直接将http跳转至https。
Header always set Strict-Transport-Security “max-age=31536000”:此选项表示在一年时间内只要访问当前web server,浏览器内部将自动跳转为https、 - HSTS但是最早的第一次还是只能走上述的http,然后再访问一次https
实现HSTS示例:
vim /etc/httpd/conf/httpd.conf
Header always set Strict-Transport-Security "max-age=31536000"
RewriteEngine on
RewriteRule ^(/.*)$ https://%{HTTP_HOST}$1 [redirect=302]
-
HSTS preload list
是Chrome浏览器中的HSTS预载入列表,在该列表中的网站,使用Chrome浏览器访问时,会自动转换成HTTPS。Firefox、Safari、Edge浏览器也会采用这个列表。- 这样可以使得第一次访问web server时直接走https。
-
注意: Apache不支持同一ip,同一端口号使用主机头的方式实现虚拟主机的https。即https不能实现针对一个ip,一个端口号只是主机头不同实现虚拟主机。
正向代理和反向代理
-
正向代理
正向代理是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。 -
反向代理
反向代理对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端,就像这些内容 原本就是它自己的一样。
-
Apache可以作为反向代理,但是一般不会使用Apache作为反向代理。
-
反向代理功能实现
启用反向代理
ProxyPass "/" "http://www.example.com/" 真正的web server的ip地址
ProxyPassReverse "/" "http://www.example.com/" web server的ip
特定URL反向代理
ProxyPass "/images" "http://www.example.com/"
ProxyPassReverse "/images" http://www.example.com/
web server认为的是反向代理在访问
Sendfile机制
-
没有启用sendfile时的工作过程:
如上图所示:用户请求web server的首页资源,请求首先到达web server网卡除,然后复制一份至内核空间的网卡缓冲区,经过分析后交给用户空间的httpd程序的缓冲区,httpd分析后发现请求首页资源,于是发起系统调用,请求内核加载index.html资源。内核将资源加载至内核空间的内存缓存区中,然后发送给httpd应用程序,由应用程序httpd构建响应报文后,再发送至网卡的内核空间缓存区,最后经由网卡发送响应报文至用户。
其中的过程比较繁琐,而且index.html的路程走得比较多,如果inde.html可以直接在内核空间从内存缓冲区至网络缓冲区的话。这样将减少文件复制的次数和内核上下文切换的次数,实现方式:sendfile机制,sendfile启用以后,文件将直接从内核空间从内存缓冲区至网络缓冲区。
减少复制次数的专业称呼:零复制。
-
不用 sendfile 的传统网络传输过程:
- read(file, tmp_buf, len)
- write(socket, tmp_buf, len)
-
硬盘 >> kernel buffer >> user buffer >> kernel socket buffer >> 协议栈
- 一般网络应用通过读硬盘数据,写数据到socket来完成网络传输,底层执行过程:
- 1 系统调用read()产生一个上下文切换:从user mode切换到kernel mode,然后DMA执行拷贝,把文件数据从硬盘读到一个kernel buffer里。
- 2 数据从kernel buffer拷贝到user buffer,然后系统调用read()返回,这时又产生一个上下文切换:从kernel mode切换到user mode
- 3 系统调用write()产生一个上下文切换:从user mode切换到kernel mode,然后把步骤2读到user buffer的数据拷贝到kernel buffer(数据第2次拷贝到 kernel buffer),不过这次是个不同的 kernel buffer,这个buffer和socket相关联。
- 4 系统调用write()返回,产生一个上下文切换:从kernel mode切换到user mode(第4次切换),然后DMA从kernel buffer拷贝数据到协议栈(第4次拷贝)
- 上面4个步骤有4次上下文切换,有4次拷贝,如能减少切换次数和拷贝次数将会有效提升性能
-
在kernel 2.0+版本中,系统调用sendfile() 就是用来简化上面步骤提升性能的。sendfile()不但能减少切换次数而且还能减少拷贝次数
-
用 sendfile() 来进行网络传输的过程:
-
sendfile(socket, file, len);
-
硬盘 >> kernel buffer (快速拷贝到kernel socket buffer) >> 协议栈
- 1 系统调用sendfile() 通过DMA把硬盘数据拷贝到kernel buffer,然后数据被kernel直接拷贝到另外一个与 socket 相关的 kernel buffer。这里没有user mode和kernel mode之间的切换,在kernel中直接完成了从一个buffer到另一个buffer的拷贝
- 2 DMA把数据从kernel buffer直接拷贝给协议栈,没有切换,也不需要数据从user mode拷贝到kernel mode,因为数据就在kernel里
-
sendfile不是Apache专有的技术,Nginx也具有sendfile机制,可以优化服务器响应。
http协议
http协议主要分析
1、http协议的响应报文格式和请求报文格式。
2、http无状态的解决方法。
- http协议
- http/0.9, http/1.0, http/1.1, http/2.0
- http协议:stateless 无状态
- 服务器无法持续追踪访问者来源
- 解决http协议无状态方法
- cookie 客户端存放
- session 服务端存放
- http事务:一次访问的过程
- 请求:request
- 响应:response
HTTP请求报文
- HTTP请求报文头部分成三个部分:开始行、首部行和实体主体。
- 开始行
方法:GET、HEAD、POST
URL:/index.html、/、…
版本:一般是HTTP/1.1、HTTp/2.0 - 首部行
一些首部字段,首部字段是由键值对组成,不同浏览器,首部字段不相同。
例如:
User-Agent: curl/7.29.0
Host: www.jd.com - 实体主体:
- 上传一般会使用到实体主体
一般放登录用户名和密码等或者上传的博客文章等。。。
- 上传一般会使用到实体主体
示例:请求报头
# curl -Iv http://www.jd.com
HEAD / HTTP/1.1
User-Agent: curl/7.29.0
Host: www.jd.com
Accept: */*
- 2.Method 方法:
GET: 从服务器获取一个资源
HEAD: 只从服务器获取文档的响应首部
POST: 向服务器输入数据,通常会再由网关程序继续处理
PUT: 将请求的主体部分存储在服务器中,如上传文件
DELETE: 请求删除服务器上指定的文档
TRACE: 追踪请求到达服务器中间经过的代理服务器
OPTIONS:请求服务器返回对指定资源支持使用的请求方法
HTTP响应报文
-
响应报文的开始行是状态行:
版本
状态码
短语:原因短语(解释状态码的含义) -
首部行:
-
实体主体:
示例:响应报文头
# curl -I http://www.jd.com
HTTP/1.1 302 Moved Temporarily
Server: JDWS/2.0
Date: Wed, 09 Oct 2019 06:46:11 GMT
Content-Type: text/html
Content-Length: 157
Connection: keep-alive
Location: https://www.jd.com/
Strict-Transport-Security: max-age=7776000
常见的状态码及其含义
-
1.状态码分类
1xx:100-101 信息提示
2xx:200-206 成功
3xx:300-305 重定向
4xx:400-415 错误类信息,客户端错误
5xx:500-505 错误类信息,服务器端错误 -
2.http协议常用的状态码
200: 成功,请求数据通过响应报文的entity-body部分发送;OK
301: 请求的URL指向的资源已经被删除;但在响应报文中通过首部Location指明了资源现在所处的新位置;Moved Permanently
302: 响应报文Location指明资源临时新位置 Moved Temporarily
304: 客户端发出了条件式请求,但服务器上的资源未曾发生改变,则通过响应此响应状态码通知客户端;Not Modified
401: 需要输入账号和密码认证方能访问资源;Unauthorized
403: 请求被禁止;Forbidden
404: 服务器无法找到客户端请求的资源;Not Found
500: 服务器内部错误;Internal Server Error
502: 代理服务器从后端服务器收到了一条伪响应,如无法连接到网关;Bad Gateway
503: 服务不可用,临时服务器维护或过载,服务器无法处理请求
504: 网关超时
解决http协议无状态方法
- 解决http协议无状态方法
cookie 客户端存放
session 服务端存放
cookie
-
cookie:
HTTP是一种无状态协议。协议自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做持久化处理。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成如此简单的。可是随着Web的不断发展,很多业务都需要对通信状态进行保存。于是引入了Cookie技术。使用 Cookie的状态管理Cookie技术通过在请求和响应报文中写入Cookie信息来控制客户端的状态。Cookie会根据从服务器端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入Cookie值后发送出去。服务器端发现客户端发送过来的Cookie 后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息Cookie
cookie:文本文件 cookie里面可以存放与用户相关的所有信息,比如登录信息、和用户相关所有信息均在cookie中,但是为了避免cookie越来越大。目前cookie中只存放用户的唯一标记。服务器端产生了一个session,session-id每个用户唯一,cookie中的存放的信息可以是session-id;其中cookie和session是有生命周期。当浏览器再次请求web server时,请求报文里面将携带cookie。
此处cookie和session的概念有点含糊~~
-
Set-Cookie首部字段
- Set-Cookie是响应报文含有的信息,cookie是请求报文中含有的信息。
- Set-cookie首部字段示例:
Set-Cookie: status=enable; expires=Fri, 24 Nov 2017 20:30:02 GMT; path=/;
NAME=VALUE 赋予 Cookie 的名称和其值,此为必需项
expires=DATE Cookie 的有效期,若不明确指定则默认为浏览器关闭前为止
path=PATH 将服务器上的文件目录作为Cookie的适用对象,若不指定则默认为文档所在的文件目录
domain=域名 作为 Cookie 适用对象的域名,若不指定则默认为创建Cookie的服务器的域名
Secure 仅在 HTTPS 安全通信时才会发送 Cookie
HttpOnly 加以限制使 Cookie 不能被 JavaScript 脚本访问
t-Cookie: status=enable; expires=Fri, 24 Nov 2017 20:30:02 GMT; path=/;
NAME=VALUE 赋予 Cookie 的名称和其值,此为必需项
expires=DATE Cookie 的有效期,若不明确指定则默认为浏览器关闭前为止
path=PATH 将服务器上的文件目录作为Cookie的适用对象,若不指定则默认为文档所在的文件目录
domain=域名 作为 Cookie 适用对象的域名,若不指定则默认为创建Cookie的服务器的域名
Secure 仅在 HTTPS 安全通信时才会发送 Cookie
HttpOnly 加以限制使 Cookie 不能被 JavaScript 脚本访问