文章目录
- 访问控制是网络安全防范和保护的主要策略,其任务是保证网络资源不被非法访问 。 Nginx 作为 Web 服务器的后起之秀,也提供了访问控制的功能。它可以根据实际需求,对用户可以访问和禁止的目录进行限制。下面将对 Nginx 提供的权限控制指令以及典型的 应用进行详细讲解 。
1.1 权限控制指令
- Nginx 中提供了两个用于配置访问权限控制的指令,分别为
allow
和deny
。 从其名称就可以看出,allow
用于设置允许访问的权限、deny
用于设置禁止访问的权限 。 在使用时, 权限指令后只需跟上允许或禁止的 IP、IP 段或 all 即可 。 其中,all 表示所有的 。 - 权限控制指令的使用虽然简单,但是在设置的过程中,还需要特别注意以下几个点。
- 单个 IP 指定作用范围最小, all 指定作用范围最大。
- 同一块下,若同时存在多个权限指令(
deny、allow
) ,则先出现的访问权限设置生效, 并且会对后出现的设置进行破盖,未覆盖的范围依然生效,否则以先出现的设置为准。 · - 当多个块(如
http、server、 location
)中都出现了权限设置指令,则内层块中的权限级别要比外层块中设置的权限级别高 。
- 为了读者更好地理解权限控制指令,下面对几种常用使用方式分别演示说明 。
1. 准备工作
- 由于权限的控制测试,需要涉及不同的 IP。 因此,在具体讲解前,准备多台虚拟机, 一 台作为 Nginx 服务器,如
192. 168. 78. 3
。另外几台作为客户端,如192. 168. 78. 128
和192. 168. 78. 200
,通过curl
访问服务器192. 168. 78. 3
),进行测试。
2. 默认访问权限
- 打开 IP 地址为
192. 168. 78. 3
的 Nginx 服务器配置文件,按照如下配置修改 server 块 后,平滑重启 Nginx,使配置生效 。
1 server {2 listen 80;3 server_name 1ocalhost;4 root html;5 index index.html index.htm;6 }
- 为了方便测试,在
html
目录中编写 index. html ,输出一行提示信息,如下所示
<h1>Welcome 192.168. 78.3!h1>
- 接着,利用之前准备的两个客户端(
192. 168. 78. 128
和192. 168. 78. 200
),通过curl
请 求服务器地址 192. 168. 78. 3 ,具体命令如下。
curl http://192 .168.78.3
- 执行完上述命令后,若在两个客户端中都能看到如图所示的结果,表明虚拟主机默认未设置访问权限时,允许所有用户的访问,效果相当于为
server
设置allow all
。
3. 禁止所有用户的访问
- 在步骤 2 中第 5 行下添加以下指令,用于禁止所有的客户端访问,具体如下。
deny all;
1 server { 2 listen 80; 3 server_name 1ocalhost; 4 root html; 5 index index.html index.htm; 6 deny all; 7 }
接着,再次使用两个客户端进行访问测试,访问结果如图所示。从图中可以看出, 页面显示
403 Forbidden
,表明禁止访问成功。需要注意的是,在
server
块下设置deny all
后,服务器(192. 168. 78. 3
)内的客户端软件在访问自己时也会出现403 Forbidden
。 因此,在设置时需要慎重考虑。
4 . 只允许指定用户访问
- 对于服务器
192. 468. 78. 3
来说,若仅允许客户端192. 168. 78. 128
访问,则将第 3 步中 的权限设置修改成以下配置即可 。
1 server { 2 listen 80; 3 server_name 1ocalhost; 4 root html; 5 index index.html index.htm; 6 allow 192.168.78.128; 7 deny all; 8 }
- 上述指令表示只允许
192. 168. 78. 128
客户端访问,其他所有客户端都不能访问 。 利用之前准备的两个客户端可以进行测试。 需要注意的是,若省略此处的deny all
,则会允许所有客户端访问;若将deny all
移动到allow 192. 168. 78. 128
之后,则会阻止所有客户端 访问 。 - 从上述规律看出,同一个块下的两个权限指令,先出现的设置会覆盖后出现的设置,使 得
allow 192. 168. 78. 128
的配置优先生效;同时deny
指令设置的访问范围all
较大,未被allow
覆盖的范围配置依然生效,达到除了 IP 为192. 168. 78. 128
的用户外,禁止其他用户对服务器访问的效果 。
5. 不同块间的权限指令优先级
- 为了测试不同块间的权限指令优先级,重新配置服务器
192. 168. 78. 3
的权限设置,在http
块中设置禁止所有用户对http
块的访问,具体配置如下 。
1 http { 2 ... 3 deny all; 4 server { 5 1isten 80; 6 server_name localhost; 7 root html; 8 index index.html index.htm; 10 } 11 }
- 接着 ,使用之前准备的两个客户端访问测试,可以看到如上图 4-12 所示的访问失败结果 。 然后,在第 8 行指令的配置后添加以下配置。
allow all;
- 修改完成后,使用两个客户端访问,可以看到如图 4-11 所示的访问成功结果。 这是由于 Nginx 配置文件中的各个块在嵌套的情况下,内层块内的指令比外层块内的指令执行优先级高 。 因此,当内外层块中同时出现权限指令时,则内层块中的
allow all
会覆盖外层块 中的deny all
的设置。
1.2 访问控制典型应用
- 在实际应用中,权限控制的需求更加复杂。例如,对于网站下的
img
目录允许所有用户访问,但对于网站下的admin
目录则仅允许管理员身份的用户访问。此时,仅靠deny 和 allow
这两个权限指令不能满足用户的需求,还需要使用location
块来完成相关需求的匹配。 - 在此之前,首先要简单了解一下
location
的相关语法及规定,具体如下。
location [ = I ~ | ~ * | ^ ~ ] URI { ... } #语法类型1 location @name { ... } #语法类型2
- 在上述语法中,
=
、~
、~ *
、^~
和@
都是location
用于实现访问控制的前缀,且在使用时只能选择一种,当然也可以不设置前缀。其中,关于location
前缀的含义如表 4-3 所示。URI
表示URL 地址
中从域名到参数之间的部分 , { … }表示指令块 ,用于满足location
匹配条件后需要执行的指令。
- 根据表 4-3 的描述,可将
location
根据不同前缀的使用方式,大致分为普通 location 和 正则 locationo 其中,~和~*
属于正则 location,其余的前缀和没有前缀的情况都属于普 通 location。 - 接下来,通过
location
块和权限控制指令,逐一演示访问控制的几种典型使用方式。
1. 精准匹配
- 所谓精准匹配指的就是用户访问的
URI
与指定的URI
完全一致的情况,才会执行其后的指令块,示例配置如下 。
1 server { 2 listen 80; 3 server_name localhost; 4 root html; 5 index index.html index.htm; 6 location = /js { 7 allow 192.168.78.128; 8 } 9 location = /admin/auth{ 10 allow 192.168.78.200; 11 } 12 deny all; 13 }
上述第
6~8 行
和第9~11
行配置设置了两个精准匹配,第12
行用于禁止所有用户的访问 。当上述配置中允许访问的两个客户端,请求网站根目录下不存在的文件或目录时,如果符合匹配规则,网页显示404 Not Found
,不符合时显示403 Forbidden
。假设网站根目录下没有任何文件,下面使用 IP 为
192. 168. 78. 128
的 A 用户和 IP 为192. 168. 78. 200
的 B 用户通过不同的URL
进行访问测试,其对应的响应结果如表 4-4 所示。从表 4-4 可以看出,精准匹配是只有用户请求的
URI
与location
中定义的匹配模式完 全一致的情况下,才会执行其后的指令块,否则匹配不成功。
2. 正则匹配
- Nginx 配置文件中,多个正则
location
之间按照正则
location
在配置文件中的书写顺序进行匹配,且只要匹配成功就不会继续匹配后面定义的正则 location
. 下面在 IP 为192. 168. 78. 3
的虚拟机中,设置以下两个正则 location
访问控制,具体如下 。
1 location ~ \.html$ { 2 allow all; 3 } 4 location ~ ^/aaa/.* \.html$ { 5 deny all; 6 }
在上述配置中,第 1 行表示匹配网站根目录下以
.html
结尾的文件,第 4 行表示匹配网站根目录下 aaa 目录中以. html 结尾的文件。下面使用 IP 为
192. 168. 78. 128
的用户通过不同的URL
进行访问测试,其对应的响应 结果如表 4-5 所示 。从表 4-5 可以看出,当
location
中的URI
与用户请求中以.html
为结尾的文件匹配上时,正则location
停止了继续匹配,因此显示结果都为404 Not Found
。接下来,调换第
1~3
行与第4~6
行代码的编写顺序,再次访问http: //192.168.78.3/test. html
结果依然为404 Not Found
,而访问http : //192. 168. 78. 3/ aaa/ test. html
的结果为403 Forbidden
从上述两组测试对比可总结出,
正则 location
的编写顺序不同,则结果不同,且只有前面定义的正则 location 匹配不成功的情况下,才会继续匹配后面的正则 location。因此,在实际应用中要注意正则 location 在配置文件中的书写顺序 。
3. 最大前缀匹配
- 由于
location
可以同时定义多个,当一个配置文件中同时出现多个location
时,普通 location 之间遵循“最大前缀匹配”原则 。 通俗地讲就是,匹配度最高的location
将会执行,示例如下 。
1 location /ng.test { 2 allow all; 3 } 4 location /ng.test/log { 5 deny all; 6 }
为了方便对比学习 ,下面利用不同的
URL
进行访问测试,对应的响应结果如表 4-6 所示。值得一提的是,当最大前缀
location
与正则location
同时存在时,如果正则location
匹配成功,则不会执行最大前缀location
。具体示例如下。
1 location / { 2 deny all; 3 } 4 location ~\.html$ { 5 allow all; 6 }
- 上述配置中,第
1~3
行定义的是最大前缀location
,用于匹配当前网站根目录下的所有文件,第4~6
行用于正则匹配所有以.html
结尾的URI
。 不同URL
及其对应的响应结果如表 4-7 所示。
- 从表 4-7 中可以看出,当用户访问
http : //192. 168. 78. 3
时,完成第 1 行的匹配;而在用户访问http: //192. 168. 78. 3/ notfound. html
和http : //192. 168. 78. 3/ index.php
时,前者符合正则 location
,结果为404 Not Found
,而后者不符合正则 location
,显示了最大前缀匹 配的结果403 Forbidden
。
location / {} 与location =/ {} 的区别
-
location / {}
遵守普通location
的最大前缀匹配,由于任何URI
都必然以“ / ”
根开头, 所以对于一个URI
,若配直文件中有更合适的匹配则会将其替代,否则返回location /{}
匹配到的结果,它相当于站点默认配直 。 - 而
location= / {}
遵 守的是精准匹配,也就是只能匹配该站点根目录,同时会禁止继续搜索正则 location
,效率比location / {}
妥高 。 因此,若在开发中能确定精准匹配的情况,可以采用location =/{}
的方式,提升匹配效率 。
4. 禁用正则匹配
- 利用
=
精准匹配或^~
非正则匹配可以在正则匹配之前优先匹配,从而禁止执行原有的正则匹配 。 下面在server
块中添加以下几条location
匹配规则,具体如下 。
1 location = /aaa/test.html { 2 allow all; 3 } 4 location ^~ { 5 deny all; 6 } 7 location ~\.html$ ( 8 allow all; 9 }
- 在上述配置中,第 1 行仅用于精准匹配网站根目录下的
aaa/ test.html
,第 4 行用于非 正则匹配网站根目录下的文件,第 7 行用于正则匹配网站根目录下以.html
为结尾的文件。 - 接下来通过不同
URL
进行访问测试,具体如表 4-8 所示。从表中的响应结果可以看 出,在使用了“=”
或“^~”
前缀时,普通location
匹配后将不再执行正则location
的匹配 。 - 值得一提的是,前缀
“=”
和“^~”
虽然都能阻止继续搜索正则location
,不同的地方是它们遵循的规则不同,叫“^~”
依然遵循最大前缀匹配规则,而=
则严格按照精准匹配执行。 - 因此,当多种类型的
location
匹配同时出现时,最终执行结果为“ = ”
匹配优先于“^~”
匹配,“^~”
匹配优先于正则匹配,正则匹配优先于普通的最大前缀匹配。 只要优先的location
匹配成功,就不会执行其他的location
。
root 与 alias 的时区别
- 在
location
中指定目录时,除了可以使用root
指令外,还可以使用alias
指令完成 。 两者在使用时有一定的区别,具体示例如下 。
#当收到"/img/a.png"请求时,将请求映射为"/var/www/image/a.png" location /img/ { alias /var/www/image/; } #当收到"/img/b.png"请求时,将请求映射为"/var/www/image/img/b.png" location /img/ { root /var/www/image; }
- 从上述示例可以看 出 ,
alias
在映射路径时不会追加location
匹 配到的 部分,而root
追加了location
匹配到的部分。