Nginx 会话保持、防盗链、地址重定向

一、会话保持

在我们做Nginx负载均衡的时候经常会遇到会话保持的问题,为了保证同一用户session会被分配到同一台服务器上,这时就需要会话保持,Nginx会话保持一般有基于ip_hash基于cookie两种方式

1、基于ip_hash

原理

ip_hash使用源地址哈希算法,将同一客户端的请求总是发往同一个后端服务器,除非该服务器不可用。

ip_hash语法:

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com down;
}

ip_hash简单易用,但有如下问题:

  • 当后端服务器宕机后,session会话丢失;
  • 同一客户端会被转发到同一个后端服务器,可能导致负载失衡;

2、基于cookie

原理

将用户的session存入cookie里,当用户分配到不同的服务器时,先判断服务器是否存在该用户的session,如果没有就先把cookie里面的sessoin存入该服务器,实现session会话保持。缺点是存入cookie有安全隐患。

使用sticky_cookie_insert启用会话亲缘关系,这会导致来自同一客户端的请求被传递到一组服务器的同一台服务器。与ip_hash不同之处在于,它不是基于IP来判断客户端的,而是基于cookie来判断。因此可以避免上述ip_hash中来自同一客户端导致负载失衡的情况。(需要引入第三方模块才能实现,sticky模块)

语法:

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
    sticky_cookie_insert srv_id expires=1h domain=3evip.cn path=/;
}

server {
    listen 80;
    server_name 3evip.cn;
    location / {
		proxy_pass http://backend;
    }
}

说明:

  • expires:设置浏览器中保持cookie的时间
  • domain:定义cookie的域
  • path:为cookie定义路径

二、防盗链

两个网站 A 和 B, B网站引用了A网站上的图片,这种行为就叫做盗链。 防盗链,就是要防止B引用A的图片。

1、对应模块

ngx_http_referer_module

如何区分哪些是不正常的用户?

HTTP Referer是Header的一部分,当浏览器向Web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器借此可以获得一些信息用于处理,例如防止未经允许的网站盗链图片、文件等。因此HTTP Referer头信息是可以通过程序来伪装生成的,所以通过Referer信息防盗链并非100%可靠,但是,它能够限制大部分的盗链情况。

2.、防盗链配置

配置要点:

[root@nginx-server ~]# vim /etc/nginx/nginx.conf
# 日志格式添加"$http_referer"
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                         '$status $body_bytes_sent "$http_referer" '
                         '"$http_user_agent" "$http_x_forwarded_for"';
# valid_referers 使用方式                         
Syntax: 	valid_referers none | blocked | server_names | string ...;
Default: 	—
Context: server, location
  • valid_referers:允许哪些域名访问。

  • none : 允许没有http_referer的请求访问资源;

  • blocked : 允许不是http://开头的,不带协议的请求访问资源—被防火墙过滤掉的;

  • server_names : 只允许指定ip/域名来的请求访问资源(白名单);

3、防盗链实例一

准备两台机器,一台图片网站服务器,一台盗链机器

(1)图片网站服务器

图片网站服务器:上传图片192.168.1.9
[root@nginx-server ~]# cp test.jpg /usr/share/nginx/html/
[root@nginx-server ~]# cd /etc/nginx/conf.d/
[root@nginx-server conf.d]# cp default.conf default.conf.bak
[root@nginx-server conf.d]# mv default.conf nginx.conf
[root@nginx-server conf.d]# vim nginx.conf
server {
    listen       80;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
[root@nginx-server conf.d]# nginx -t
[root@nginx-server conf.d]# systemctl restart nginx

访问:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XujjgX5S-1628764455047)(assets/1583393017711.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xb5mlprq-1628764455049)(assets/1583393034732.png)]

注:Referer:这个匹配的连接为空 “-”

(2)盗链机器

盗链机器配置:192.168.1.10
[root@nginx-client html]# cat /etc/nginx/conf.d/qf.conf
server {
        listen 80;
        server_name     localhost;
        location / {
                root /usr/share/nginx/html;
                index index.html;
        }
}

[root@nginx-client ~]# cd /usr/share/nginx/html/
[root@nginx-client html]# cp index.html index.html.bak
[root@nginx-client html]# vim index.html
<html>
<head>
    <meta charset="utf-8">
    <title>qf.com</title>
</head>
<body style="background-color:red;">
    <img src="http://192.168.1.9/test.jpg"/>
</body>
</html>
[root@nginx-client html]# systemctl restart nginx

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dF3RjSNS-1628764455051)(assets/1583393072658.png)]

查看图片网站服务器日志:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cg43YwsI-1628764455054)(assets/1583393094531.png)]
注:Referer记录了:连接是1.10这台机器。

(3)图片服务器设置防盗链

在图片服务器操作
[root@nginx-server conf.d]# vim nginx.conf
server {
    listen       80;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;

        valid_referers none blocked www.jd.com;  #允许这些访问
                if ($invalid_referer) {
                   return 403;
                }
        }
}
[root@nginx-server conf.d]# systemctl restart nginx

测试访问盗链机器:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yeMRgUf1-1628764455055)(assets/1583393512579.png)]

图片服务器查看日志:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Vt2b108-1628764455057)(assets/1583393526910.png)]
注:上面配置并没有允许192.168.1.10这台机器访问。

4、防盗链实例二

继续在图片服务器上面操作
[root@nginx-server html]# vim /etc/nginx/conf.d/nginx.conf #将原来的删除掉
server {
    listen       80;
    server_name  localhost;
    location ~  .*\.(gif|jpg|png|jpeg)$ {
        root  /usr/share/nginx/html;

        valid_referers none blocked *.qf.com 192.168.1.10;
                if ($invalid_referer) {
                        return 403;
                }
        }
}
因为none允许为空值访问,所以加不加ip都可以访问,如果把none擦除,就不可以了
重载nginx服务
[root@nginx-server ~]# nginx -s reload
在其中一台机器测试:
测试不带http_refer:
[root@nginx-server conf.d]# curl -I "http://192.168.1.9/test.jpg"
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Mon, 02 Sep 2019 14:02:56 GMT
Content-Type: image/jpeg
Content-Length: 27961
Last-Modified: Mon, 02 Sep 2019 13:23:12 GMT
Connection: keep-alive
ETag: "5d6d17c0-6d39"
Accept-Ranges: bytes

测试带非法http_refer:
[root@nginx-server conf.d]# curl -e http://www.baidu.com -I "http://192.168.1.9/test.jpg"
HTTP/1.1 403 Forbidden
Server: nginx/1.16.1
Date: Mon, 02 Sep 2019 14:03:48 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive

测试带合法的http_refer:
[root@nginx-server conf.d]# curl -e http://www.qf.com -I "http://192.168.1.9/test.jpg"
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Mon, 02 Sep 2019 14:04:52 GMT
Content-Type: image/jpeg
Content-Length: 27961
Last-Modified: Mon, 02 Sep 2019 13:23:12 GMT
Connection: keep-alive
ETag: "5d6d17c0-6d39"
Accept-Ranges: bytes

[root@ansible-server conf.d]# curl -e http://192.168.1.10 -I "http://192.168.1.9/test.jpg"
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Mon, 02 Sep 2019 14:05:36 GMT
Content-Type: image/jpeg
Content-Length: 27961
Last-Modified: Mon, 02 Sep 2019 13:23:12 GMT
Connection: keep-alive
ETag: "5d6d17c0-6d39"
Accept-Ranges: bytes

如果用户直接在浏览器输入你的图片地址,那么图片显示正常,因为它符合规则。

在图片服务器查看日志:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hCizkrEC-1628764455058)(assets/1583393546304.png)]

三、地址重定向

1、什么是Rewrite

Rewrite又称URL Rewrite,即URL重写,就是把传入Web的请求重定向到其他URL的过程。

2、应用场景

  • 伪静态化,是将动态页面显示为静态页面方式的一种技术。理论上,搜索引擎更喜欢静态页面形式的网页,搜索引擎对静态页面的评分一般要高于动态页面。所以,URL Rewrite可以让我们网站的网页更容易被搜索引擎所收录。
  • 提高安全性,如果在URL中暴露太多的参数,无疑会造成一定量的信息泄漏,可能会被一些黑客利用,对你的系统造成一定的破坏,所以静态化的URL地址可以给我们带来更高的安全性。
  • 美化URL,去除一些后缀名或参数串,让网页的地址看起来尽可能简洁明快,有利于反映访问模块内容。
  • 实现地址跳转、协议跳转、端口跳转。

3、Rewrite 相关指令

Nginx Rewrite 相关指令有 if、rewrite、set、return

(1)if 语句
  • 应用环境
  server,location

语法:

if (condition) {}
if 可以支持如下条件判断匹配符号
~ 					正则匹配 (区分大小写)    
~* 				    正则匹配 (不区分大小写)
!~                  正则不匹配 (区分大小写)
!~*		            正则不匹配  (不区分大小写)
-f 和!-f 		    用来判断是否存在文件
-d 和!-d 		    用来判断是否存在目录
-e 和!-e 		    用来判断是否存在文件或目录
-x 和!-x 		    用来判断文件是否可执行

在匹配过程中可以引用一些Nginx的全局变量
$args				请求中的参数;
$document_root	    针对当前请求的根路径设置值;
$host				请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名;
$limit_rate			对连接速率的限制;
$request_method		请求的方法,比如"GET""POST";
$remote_addr		客户端地址;
$remote_port		客户端端口号;
$remote_user		客户端用户名,认证用;
$request_filename   当前请求的文件路径名(带网站的主目录/usr/local/nginx/html/images /a.jpg)
$request_uri		当前请求的文件路径名(不带网站的主目录/images/a.jpg)
$query_string$args相同;
$scheme				用的协议,比如http或者是https
$server_protocol	请求的协议版本,"HTTP/1.0""HTTP/1.1";
$server_addr 		服务器地址,如果没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费);
$server_name		请求到达的服务器名;
$document_uri$uri一样,URI地址;
$server_port 		请求到达的服务器端口号;
(2)Rewrite flag

rewrite 指令根据表达式来重定向URI,或者修改字符串。可以应用于server,location, if环境下每行rewrite指令最后跟一个flag标记,支持的flag标记有:

标记作用
last标记在本条 rewrite 规则执行完后,会对其所在的 server { … } 标签重新发起请求,默认为last
break本条规则匹配完成后,终止匹配,不再匹配后面的规则
redirect返回302临时重定向,浏览器地址会显示跳转后的URL地址
permanent返回301永久重定向,浏览器地址会显示跳转后URL地址

其实permanentredirect区别就是301和302的区别,301重定向是永久性的,浏览器会把这个跳转规则进行缓存,所以关闭nginx后仍然会进行跳转,302重定向是临时更改,不会被缓存或保存

(3)Rewrite匹配参考示例
本地解析hosts文件(windows)
192.168.62.153 www.testpm.com

例1:
[root@nginx html]# pwd
/html
[root@nginx html]# ls
a  b
[root@nginx html]# cat a/1.html 
1.html
[root@nginx html]# cat b/2.html 
22

# http://www.testpm.com/a/1.html ==> http://www.testpm.com/b/2.html
server {
    listen       80;
    server_name  www.testpm.com;

        location /a {
        root /html;
        index   1.html index.htm;
        rewrite .* /b/2.html permanent;
        }

        location /b {
        root    /html;
        index   2.html index.htm;
        }
}


例2:
[root@mycat html]# pwd
/var/www/html 
[root@mycat html]# ls
2018  2019
[root@mycat html]# cat 2018/a/1.html 
2018
[root@mycat html]# cat 2019/a/1.html 
2019

# http://www.testpm.com/2019/a/1.html ==> http://www.testpm.com/2018/a/1.html
server {
    listen       80;
    server_name  www.testpm.com;

    location /2019/a {
        root    /var/www/html;
        index   1.html index.hml;
        rewrite ^/2019/(.*)$ /2018/$1 permanent;
    }

    location /2018/a {
        root    /var/www/html;
        index   1.html index.htl;
    }

}


例3:
# http://www.qf.com/a/1.html ==> http://jd.com
location /a {
        root    /html;
        if ($host ~* qf.com ) {
        rewrite .* http://jd.com permanent;
        }
}


例4:
# http://www.youngfit.com/a/1.html ==> http://jd.com/a/1.html
location /a {
        root /html;
        if ( $host ~* youngfit.com ){
        rewrite .* http://jd.com$request_uri permanent;
        }
}


例5: 在访问目录后添加/  (如果目录后已有/,则不加/)
[root@nginx-server c]# pwd
/usr/share/nginx/html/a/b/c

http://www.qf.com/a/b/c--->http://www.qf.com/a/b/c/
# http://www.qf.com/a/b/c
# $1: /a/b/
# $2: c
# http://$host$1$2/
location /a/b/c {
        root    /usr/share/nginx/html;
        index   index.html index.hml;
        if (-d $request_filename) {
        rewrite ^(.*)([^/])$ http://$host$1$2/ permanent;
        }
}

例6:
[root@nginx html]# pwd
/usr/share/nginx/html
[root@nginx html]# ls
50x.html  index.html  index.html.bak1  reg
[root@nginx html]# cat reg/login.html 
login
# http://www.qf.com/login/qf.html ==>  http://www.qf.com/reg/login.html?user=qf
	location /login {
        root   /usr/share/nginx/html;
        rewrite ^/login/(.*)\.html$ http://$host/reg/login.html?user=$1;
        }
    location /reg {
        root /usr/share/nginx/html;
        index login.html;
        }

例7:
[root@nginx-server 33]# pwd
/html/qf/11/22/33
[root@nginx-server 33]# cat 1.html 
hello nginx

#http://www.qf.com/qf/11-22-33/1.html  ==>  http://www.qf.com/qf/11/22/33/1.html
location /qf {
            rewrite ^/qf/([0-9]+)-([0-9]+)-([0-9]+)(.*)$ /qf/$1/$2/$3$4 permanent;
        }

        location /qf/11/22/33 {
                root /html;
                index   1.html;
        }
(4)set 指令

set 指令是用于定义一个变量,并且赋值

应用环境:

server,location,if

应用示例

例8:
#http://alice.testpm.com ==> http://www.testpm.com/alice
#http://jack.testpm.com ==> http://www.testpm.com/jack

[root@nginx-server conf.d]# cd /usr/share/nginx/html/
[root@nginx-server html]# mkdir jack alice
[root@nginx-server html]# echo "jack.." >> jack/index.html
[root@nginx-server html]# echo "alice.." >> alice/index.html

本地解析域名host文件
192.168.62.153 www.testpm.com
192.168.62.153 alice.testpm.com
192.168.62.153 jack.testpm.com
编辑配置文件:
server {
    listen       80;
    server_name  www.testpm.com;

    location / {
         root   /usr/share/nginx/html;
         index  index.html index.htm;
         if ( $host ~* ^www.testpm.com$) {
                break;
                }

         if ( $host ~* "^(.*)\.testpm\.com$" ) {
                set $user $1;
                rewrite .* http://www.testpm.com/$user permanent;
                }
        }
    location /jack {
         root /usr/share/nginx/html;
         index  index.html index.hml;
        }
    location /alice {
         root /usr/share/nginx/html;
         index index.html index.hml;
        }
}
(5)return 指令

return 指令用于返回状态码给客户端

server,location,if

应用示例:

例9:如果访问的.sh结尾的文件则返回403操作拒绝错误
http://www.testpm.com/1.sh     返回403
server {
    listen       80;
    server_name  www.testpm.com;
    #access_log  /var/log/nginx/http_access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        }

    location ~* \.sh$ {
        return 403;
        }
}

例10:80 ======> 443:80转443端口
server {
    listen       80;
    server_name  www.testpm.cn;
    access_log  /var/log/nginx/http_access.log  main;
    return 301 https://www.testpm.cn$request_uri;
}

server {
    listen 443 ssl;
    server_name www.testpm.cn;
    access_log  /var/log/nginx/https_access.log  main;

    #ssl on;
    ssl_certificate   /etc/nginx/cert/2447549_www.testpm.cn.pem;
    ssl_certificate_key  /etc/nginx/cert/2447549_www.testpm.cn.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers on;

    location / {
        root  /usr/share/nginx/html;
        index index.html index.htm;
    }
}

[root@nginx-server ~]# curl -I http://www.testpm.cn
HTTP/1.1 301 Moved Permanently
Server: nginx/1.16.0
Date: Wed, 03 Jul 2019 13:52:30 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://www.testpm.cn/

4、location

语法

在server块中使用,如

server {
    location 表达式 {
    }
}

location表达式类型

符号描述
~表示执行一个正则匹配,区分大小写
~*表示执行一个正则匹配,不区分大小写
^~表示普通字符匹配。使用前缀匹配。如果匹配成功,则不再匹配其他location。
=进行普通字符精确匹配。也就是完全匹配。

优先级

  • 等号类型(=)的优先级最高。一旦匹配成功,则不再查找其他匹配项。
  • ^~类型表达式。一旦匹配成功,则不再查找其他匹配项。
  • 正则表达式类型(~ ~*)的优先级次之。如果有多个location的正则能匹配的话,则使用正则表达式最长的那个。
  • 常规字符串匹配类型。按前缀匹配。
例子- 假地址掩饰真地址
server {
    # 用 xxoo_admin 来掩饰 admin
    location / {
        # 使用break拿一旦匹配成功则忽略后续location
        rewrite /xxoo_admin /admin break;
    }
    # 访问真实地址直接报没权限
    location /admin {
        return 403;
    }
}

四、知识扩展

1、HTTP Server和Application Server的区别和联系

Apache/Nginx是静态服务器(HTTP Server);

  • Nginx优点:负载均衡、反向代理、处理静态文件优势。nginx处理静态请求的速度高于apache;

  • Apache优点:相对于Tomcat服务器来说处理静态文件是它的优势,速度快。Apache是静态解析,适合静态HTML、图片等。

  • HTTP Server 关心的是 HTTP 协议层面的传输和访问控制,所以在 Apache/Nginx 上你可以看到代理、负载均衡等功能

  • HTTP Server(Nginx/Apache)常用做静态内容服务和代理服务器,将外来请求转发给后面的应用服务(tomcat,jboss,jetty等)。

应用服务器(tomcat/jboss/jetty)是动态服务器(Application Server):

  • 应用服务器Application Server,则是一个应用执行的容器。它首先需要支持开发语言的 Runtime(对于 Tomcat 来说,就是 Java,若是Ruby/Python 等其他语言开发的应用也无法直接运行在 Tomcat 上)。

  • 但是事无绝对,为了方便,应用服务器(如tomcat)往往也会集成 HTTP Server 的功能,nginx也可以通过模块开发来提供应用功能,只是不如专业的 HTTP Server 那么强大,所以应用服务器往往是运行在 HTTP Server 的背后,执行应用,将动态的内容转化为静态的内容之后,通过 HTTP Server 返回到客户端。

2、集群软硬件

  • 常用开源集群软件有:lvs,keepalived,haproxy,nginx,apache,heartbeat

  • 常用商业集群硬件有:F5, Netscaler,Radware,A10等

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值