Nginx系列之过滤模块以及变量使用

Nginx过滤模块

Nginx的过滤模块是发生在content模块之后,log模块之前,如image_fiter模块,gzip模块就是过滤模块的一部分。过滤模块用于修改返回的响应头和响应的body。如下左图所示,在content阶段生成响应的内容后,执行过滤模块,过滤模块可以对返回的响应header以及body进行修改处理。过滤模块有很多,比较重要的过滤模块有4个,copy_filter模块,postpone_filter模块,header_filter模块,write_filter模块。执行顺序上是先执行copy_filter,最后执行write_filter模块。

除了上面提到的模块外,还有其他过滤模块,如sub模块additional模块,sub模块用于替换返回的响应中的字符串信息,additional模块用于在返回的内容前后添加自定义的内容。如下图所示是sub模块的配置,sub_filter orignal_string replaced_string 配置替换的字符串内容,sub_filter_last_modified打开时,返回的请求中会添加上Last_modified字段。实验结果如下左图所示:

下面是addition模块的使用,add_before_body 和add_after_body指令用于在返回的reponse body前后添加自定义内容。这里/before_action和/after_action,理论上应该通过pass_proxy连接到反向代理服务上,下面的配置为了简便,直接return了内容来模拟。实验结果如下所示,在返回的mirror.txt文件内容的前后都添加了自定义的内容。

需要注意一点:上面使用的sub和addition模块默认不会编译进nginx,需要通过--with编译进去才能使用。--with-http_sub_module --with-http_addition_module。

Nginx的内置变量

Nginx中有很多变量,可以通过读取这些变量获取期望的信息,Nginx官网也列举了内置的很多变量含义,下图按模块分类列举了常用变量。具体如下所示

上面是列举的变量,下面是通过实验方式获取不同的变量值。结果如下所示:

有些变量信息需要在日志中查看,例如body_bytes_sent,bytes_sent等,日志结果如下所示

使用变量进行防盗链实践

某个网站通过url引用了你的页面,当用户在浏览器中点击url时,http请求的头部会通过referer头部,将该网站当前页面的url带上,告诉服务器本次请求是由这个页面发起的。通过referer模块,用invalid_referer变量根据配置判断referer头部是否合法,这样可以拒绝非正常网站访问站点资源。valid_referers指令的参数值可以设置多个,表示多个referer头部都生效。其中,none表示允许缺失referer头部的请求访问,blocked表示允许referer头部没有对应的值的请求访问,server_names表示如果referer中站点域名与server_name中域名匹配,则允许访问,另外在配置valid_referer时支持在前缀和后缀中含有*通配符,也支持正则表达式配置。下面是一段valid_referer的配置。

在nginx.conf中引入上面的配置,通过curl命令验证配置的valid_referers,验证的结果如下所示:

curl -H 'referer:http://www.taohui.org.cn/ttt' taoli.test.pub:8010/
curl -H 'referer:http://www.taohui.tech' taoli.test.pub:8010/
curl -H 'referer:http://image.baidu.com/search/detail' taoli.test.pub:8010/
#以上的配置会返回403错误

curl -H 'referer: http://www.taohui.org.cn/nginx/' taoli.test.pub:8010/
#匹配命中了字符串

curl -H 'referer: htttp://www.taohui.pub/ttt' taoli.test.pub:8010/
匹配命中了前缀*,因为没有添加/,不是url,只是一个泛域名,故匹配

curl taoli.test.pub:8010
#匹配命中了none

curl 'referer:' taoli.test.pub:8010/
#匹配命中了blocked

curl -H 'referer:http://taoli.test.pub' taoli.test.pub:8010/
#匹配命中了server_name

curl -H 'referer:http://image.google.com/search/detail' taoli.test.pub:8010/
#匹配命中了google的正则表达式配置
#以上的配置会返回valid,即匹配到了valid_referer

前面介绍的referer模块虽然可以防止非法站点的访问,但是,实际情况下,很容易伪造referer字段的值,所以需要更安全的方式,secure_link模块就是防盗链的一种更可靠的解决方案。工作原理是:由某服务器(也可以是nginx)生成加密后的安全链接url,返回给客户端,客户端使用安全url访问nginx,由nginx的secure_link变量判断是否验证通过。因为哈希算法是不可逆的,客户端只能获取到执行过hash算法的URL,仅生成URL的服务器、验证URL是否安全的nginx才存储了执行hash算法前的原始URL字符串,这样就保证了访问的安全性。secure_link值为空字符串则表示验证不通过,值为0则表示URL过期,值为1则表示验证通过,secure_link_expires字段存放过期时间戳。

 

上面定义了secure_link_md5值生成的规范,执行下面的命令即可生成md5值。

echo -n '2147483647/test.txt127.0.0.1 secret' | openssl md5 -binary | openssl base64 | tr +/ -__|tr -d =

通过生成的md5值与expire参数组合,访问nginx服务器上html目录下的test.txt文件,可以看到当输入正确的md5值和expire值时,返回正确的结果,如果修改任意参数,例如expire值,则返回403错误,实验结果如下所示:

除了上面的md5加密方式外,还可以采用仅对URI进行hash的简单做法,原理是将请求URL分为三部分(prefix,hash,原始的link),/prefix/hash/link。Hash生成方式:对“link密钥”做md5哈希求值,用secure_link_secret secret 配置密钥。如上图的配置文件所示"/p/"就是采用这种方式进行配置的。执行下面的命令生成md5值后,访问请求,可以看到上面的实验结果中正确获取到test.txt文件的内容,说明整个配置过程正确。

echo -n 'test.txtmysecret2' | openssl md5 -hex

以上就是利用secure_link进行防盗链的实践,需要注意该模块默认情况下不会编译进nginx,需要通过--with参数编译进去才能使用。 

为复杂业务生成新变量-map模块

在编程语言中可以通过if-else,switch-case等处理复杂业务逻辑,在nginx配置时却不支持编程语言中的语法,所以为了实现复杂逻辑的处理,可以利用map生成新的变量来处理。如下图左边所示,配置文件中$http_host是已有变量,$name是新定义的变量,$mobile也是新定义的变量,利用map可以根据http_host的不同取值,获取到不同的name值,和编程语言里面switch-case非常像。下图右边是实验结果,可以看到,在访问nginx时,设置不同的http_host后,获取到了不同name值

map在定义变量值时匹配规则如下:

  • 如果是字符串,那么进行严格匹配
  • 使用hostnames指令,可以对域名使用前缀*泛域名匹配
  • 使用hostnames指令,可以对域名使用后缀*泛域名匹配
  • ~和~*正则表达式匹配,后者忽略大小写

通过变量指定实现A/B测试

A/B 测试(也被称为对比测试和分桶测试)旨在对比两个版本的内容,识别哪一个版本对于访客/查看者更具吸引力。它将测试对照 (A) 版本与变量 (B) 版本,基于关键指标来衡量哪一个版本更成功。通过split_client模块,可以实现A/B测试。下面是split_client相关配置,这里只是个demo,所以根据请求中http_testcli的值来确定$variant的值,访问nginx后返回$variant的值。

上面只是个演示demo,实际项目中,A/B两个版本是部署在不同的服务器上,那么可以根据请求中的某个字段信息决定发送到A版本的服务,还是B版本的服务。

根据客户端地址创建新变量

geo模块的作用是根据客户端地址创建新变量,语法格式:geo[$address] $variable{...},如果geo指令后不输入$address,那么默认使用$remote_addr变量作为IP地址。{}内的指令匹配规则:

优先最长匹配
1.通过IP地址以及子网掩码的方式定义IP范围,当IP地址在范围内时,新变量使用其后的参数值
2.default指定了当范围内的值都不匹配时,新变量使用默认值
3.通过proxy指令指定可信地址,此时remote_addr的值为X-Forwarded-For头部值中最后一个IP地址的值
4.proxy_recursive,允许循环地址搜索,开启此选项后,会排除掉设置的可信地址(同realip的recursive作用相同)

下面是geo的配置,通过curl命令"curl -H 'X-Forwarded-For: 1.1.1.1,127.0.0.2,2.2.2.2' taoli.test.pub:8001"访问nginx,会返回RU的值。

上面是geo模块简单配置demo,实际项目中存在根据IP地址范围导航用户到不同的网站的场景,例如北美的客户,中国的客户需要导航到不同的网站,那么可以利用geo实现,上图右边是不用地域与IP地址间的映射关系。

以上就是Nginx中过滤模块与变量相关模块的使用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

taoli-qiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值