写在前面

在前面我们使用Nginx基于来源IP或者用户账号密码等信息来做用户访问控制,其实使用类似的原理还可以使用Nginx来实现根据扩展名来限制程序和文件的访问、禁止访问指定目录下的所有文件和目录(屏蔽某些目录)等配置功能。之后还会学习如何对Nginx程序结构进行优化,最后介绍如何适配PC或者移动设备。

根据扩展名来限制程序和文件的访问

一般来说,现在很多网站都是以用户为中心的,不仅支持用户发布文本内容到服务器,甚至还支持用户发送图片、视频、文件等内容到服务器上,但是给用户开启上传功能是很危险的,极有可能带来重大问题。

接下来举一个简单的例子,使用Nginx禁止访问上传资源目录下的PHP、SHELL、PYTHON、JAVA、GO等程序文件,这样即使用户上传了木马文件也无法执行,可以提高系统的安全性。如下所示:

1
2
3
4
5
6
7
8
9
10
11
location ~ ^/images/.*\.(php|php5|sh|py|java|go)$ {
deny all;
}

location ~ ^/static/.*\.(php|php5|sh|py|java|go)$ {
deny all;
}

location ~* ^/data/(attachment|avatar)/.*\.(php|php5|sh|py|java|go)$ {
deny all;
}

禁止访问指定目录下的所有文件和目录

接下来就尝试使用Nginx来实现禁止访问指定目录下的所有文件和目录。

最简单的配置就是禁止访问指定的单个或者多个目录,如下所示:

1
2
3
4
5
6
7
location ~ ^/(static)/ {
deny all;
}

location ~ ^/static {
deny all;
}

当然上述这种配置是比较生硬的,正常的做法都是当某个用户被禁止访问某些目录的时候,应当返回404代码,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
listen 80;
server_name www.envythink.com;

location / {
root /home/envythink/html;
index index.html index.htm;
}

access_log logs/envy.log main gzip huffer=128k flush=5s;

location /admin/ {
return 404;
}

location /templates/ {
return 403;
}
}

通过IP来源限制网站访问

前面介绍过,开发者可以使用ngx_http_access_module模块来根据网站来源IP来限制访问网站。

情况(1),只允许某个IP访问该目录,其余IP均禁止访问。此时对应的配置如下所示:

1
2
3
4
location ~ ^/envythink/ {
allow 192.168.73.100;
deny all;
}

情况(2),限制及指定IP或IP段访问。此时对应的配置如下所示:

1
2
3
4
5
6
location / {
deny 192.168.73.1;
allow 192.168.73.0/24;
allow 192.168.72.0/16;
deny all;
}

配置Nginx禁止使用网站IP访问网站

在实际工作中,为了提高网站的安全性,都会禁止用户直接使用网站IP来进行访问,那么接下来就学习Nginx如何禁止使用网站IP访问网站。

最简单的方式就是直接报错,此时的配置如下:

1
2
3
4
5
server {
listen 80 default_server;
server_name _;
return 501;
}

上面配置非常简单,但是对用户不太友好,正确的做法是直接通过301永久重定向到主页,也就是使用域名访问,此时的配置如下:

1
2
3
4
5
server {
listen 80 default_server;
server_name _;
rewrite ^(.*) http://www.envygo.com/$1 permanent;
}

屏蔽.git文件

在实际工作中,开发者都开始使用Git来管理网站源码,但是.git数据目录在网站的源码根目录也会有一份,nginx通常配置的时候不会对隐藏目录进行特别处理,这样会使源文件直接暴露在大庭广众之下,因此为了安全,一般都需要在Nginx配置中对此进行特别处理,这里就是直接不允许任何人访问这个.git文件。

此时可以在配置文件中新增如下location配置信息:

1
2
3
location ~ (.git|.gitignore|.svn|.gitattributes) {
deny all;
}

Nginx程序结构优化

在实际开发过程中,通常会注重解耦,所谓的解耦,简单来讲就是将一堆程序代码按照业务用途分开,然后各自提供服务。

举个例子,注册、登录、修改密码、忘记密码、上传、下载、浏览列表、商品内容页面、订单支付等都是独立的服务,只是在客户端看来是一个整体,如果没有这么细致的解耦,那么最起码是有如下几个独立的程序模块:
(1)网页页面服务。(2)图片下载服务。(3)图片上传服务。
上面这三者的功能应当尽可能的分离,最佳的方式就是分别使用独立的服务器,此时需要修改代码,且可能需要解决各种问题,如session共享,数据一致性等。

当然如果不想修改代码,可以在前端负载均衡haproxy或者nginx上,根据URI(如目录或者文件扩展名)来进行请求过滤,然后将其转发给后面的应用服务器。

举个例子,如果根据扩展名来进行分发,用户请求http://www.envygo.com/a/a.jpg链接时,这个链接就应该转发到图片服务器。通常我们会将图片、样式表、脚本等静态文件放到独立的服务上。

如果根据URL来进行分发,那么用户请求http://www.envygo.com/upload/index.html链接时,这个链接就应该转发图片上传服务器,其他不符合要求的可以转给Web服务器。

当然上面这些结构优化更适合并发较高、服务器较多的情况。

适配PC或者移动设备

在之前我们都是使用纯前端的自适应布局,但是它的复杂性较高和易用性较差,不太适合大型的企业网站。我们常用的淘宝,京东等网站就没有采用自适应,而是分开制作的方式,根据用户访问设备的不同来返回不同样式的站点。从实现上来说就是根据用户请求的user-agent来返回PC、移动端还是H5站点。

接下来通过一个实际的例子,来模拟用户根据不同的设备返回不同的站点。

第一步,新建不同的index.html页面。在/usr/share/nginx/html/envy文件夹下面新建两个文件夹pc和mobile,然后在各自文件夹中新建index.html页面,其中的代码如下所示:

1
2
3
4
5
<!-- /usr/share/nginx/html/envy/pc/index.html -->
<h1 style="color:red">The site is built by pc!</h1>

<!-- /usr/share/nginx/html/envy/mobile/index.html -->
<h1 style="color:blue">The site is built by mobile!</h1>

第二步,配置Nginx虚拟主机配置文件。在/usr/local/nginx/conf/vhost目录下新建一个名为book.com.conf的配置文件,其中的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
server_name book.com www.book.com;

location / {
root /usr/share/nginx/html/envy/pc;

if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
root /usr/share/nginx/html/envy/mobile;
}
index index.html index.htm;
}
}

可以看到这里只是使用if语句对访问用户的设备进行判断,具体就是判断用户请求的user-agent,进而指向不同的root路径,返回对应的站点。

然后在本地hosts文件配置DNS解析信息,之后对Nginx配置文件进行语法检测和重启。

然后直接去访问http://www.book.com可以发现出现如下信息:

当使用F12打开控制台,点击左上角的设备切换框,然后刷新一下页面,可以看到访问同样的网站,使用不同的设备,显示的结果就是不同: