写在前面

前面学习的都是如何使用Nginx,接下来学习更深层次的Nginx优化知识。我们可以通过修改或者隐藏Nginx版本号,或者更改Nginx服务的默认用户等方式来提升Nginx的安全性。

隐藏Nginx版本号

在浏览器中访问一个不存在的链接,可以看到页面出现如下所示的信息:

可以看到它直接暴露了Nginx的版本号,这肯定是不安全的,除了这个版本号之外,还有其他的信息也是较为敏感的,开发者可以进入到Nginx安装所在机器,执行如下命令来查看输出信息:

1
2
3
4
5
6
7
8
9
10
[root@envythink vhost]# curl -I 127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.17.0
Date: Wed, 18 May 2020 07:02:59 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 03 Nov 2020 01:18:28 GMT
Connection: keep-alive
ETag: "5fa0afe4-264"
Accept-Ranges: bytes

只不过上述敏感信息不会显示到界面上,接下来介绍如何将敏感信息隐藏起来。其实步骤很简单,开发者只需打开Nginx的主配置文件nginx.conf,在http区块内新增server_tokens off;参数即可,注意添加的位置:

解释一下server_tokens参数,其语法格式为server_tokens on|off,其中on为开启,off为关闭,默认是on也就是开启状态。server_tokens可以放置在http、server、location等区块中。

之后进行语法检查和平滑重启Nginx,接着再次使用curl -I 127.0.0.1来查看输出信息:

1
2
3
4
5
6
7
8
9
10
[root@envythink conf]# curl -I 127.0.0.1
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 18 Nov 2020 07:14:41 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 03 Nov 2020 01:18:28 GMT
Connection: keep-alive
ETag: "5fa0afe4-264"
Accept-Ranges: byte

可以看到Server中已经不再显示Nginx版本信息了。之后在浏览器中访问一个不存在的链接,可以看到页面出现如下所示的信息:

同样通过访问一个不存在的链接,也能证实Nginx版本信息确实不再显示了。

修改Nginx版本信息

上面只是对Nginx的敏感信息进行了隐藏,为了更好的提升Nginx的安全性,最好的做法就是直接修改Nginx的版本信息,注意Nginx版本信息需要从源码中才能修改,这里所说的源码就是没有被编译过的Nginx文件,也就是从官网下载后直接解压的文件。显然我们此时使用的已经不是未编译的Nginx,但是下载解压的安装包还在,可以将其进行修改,最后重新编译覆盖现有的Nginx即可。

笔者Nginx的下载解压路径为/home/envythink目录,这里涉及到三个文件,具体是nginx.hngx_http_header_filter_module.cngx_http_special_response.c
(A)其中nginx.h文件路径为/home/envythink/nginx-1.17.0/src/core/nginx.h
(B)ngx_http_header_filter_module.c文件路径为/home/envythink/nginx-1.17.0/src/http/ngx_http_header_filter_module.c
(C)ngx_http_special_response.c文件路径为/home/envythink/nginx-1.17.0/src/core/ngx_http_special_response.c

接下来将依次对这三个文件进行修改,同时考虑到今后的恢复,这里都将三者进行了备份,以及将修改前和修改后的所涉及到的代码进行了对比:
(1)nginx.h文件修改前的内容:

1
2
3
4
5
6
7
8
#define NGINX_VERSION      "1.17.0" # 版本号
#define NGINX_VER "nginx/" NGINX_VERSION # 软件名称
#ifdef NGX_BUILD
#define NGINX_VER_BUILD NGINX_VER " (" NGX_BUILD ")"
#else
#define NGINX_VER_BUILD NGINX_VER
#endif
#define NGINX_VAR "NGINX" # 软件名称

nginx.h文件修改后的内容:

1
2
3
4
5
6
7
8
#define NGINX_VERSION      "1.1.1"  
#define NGINX_VER "Envythink/" NGINX_VERSION
#ifdef NGX_BUILD
#define NGINX_VER_BUILD NGINX_VER " (" NGX_BUILD ")"
#else
#define NGINX_VER_BUILD NGINX_VER
#endif
#define NGINX_VAR "Envythink"

(2)修改ngx_http_header_filter_module.c文件。首先使用如下命令来查询我们需要修改的数据:

1
2
[root@envythink core]# grep -n 'Server: nginx' /home/envythink/nginx-1.17.0/src/http/ngx_http_header_filter_module.c 
49:static u_char ngx_http_server_string[] = "Server: nginx" CRLF;

接着使用如下命令来将其中的nginx修改为Envythink,如下所示:

1
[root@envythink core]# sed -i 's#Server: nginx#Server: Envythink#g' /home/envythink/nginx-1.17.0/src/http/ngx_http_header_filter_module.c 

然后使用如下命令来检查修改是否成功,可以发现确实成功:

1
2
[root@envythink core]# grep -n 'Server: Envythink' /home/envythink/nginx-1.17.0/src/http/ngx_http_header_filter_module.c 
49:static u_char ngx_http_server_string[] = "Server: Envythink" CRLF;

(3)ngx_http_special_response.c文件修改前的内容:

将图中圈红的两个信息都进行修改。第一个修改为如下所示的信息:

1
2
3
4
5
static u_char ngx_http_error_full_tail[] =
"<hr><center>" NGINX_VER "(http://www.envythink.com)</center>" CRLF
"</body>" CRLF
"</html>" CRLF
;

第二个修改为如下所示的信息:

1
2
3
static u_char ngx_http_error_tail[] =
"<hr><center>Envythink</center>" CRLF
"</body>" CRLF

在完成上述文件的修改保存之后,接下来开始重新编译Nginx。由于在前面安装了一些第三方插件,因此首先需要查看编译参数,如下所示:

1
2
3
4
[root@envythink http]# nginx -V
nginx version: nginx/1.17.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
configure arguments: --user=nginx --group=nginx --prefix=/usr/local/nginx --add-module=/usr/local/nginx/third_module/echo-nginx-module-0.61 --with-http_stub_status_module

那么接下来回到/home/envythink/nginx-1.17.0目录,这是configure脚本所在目录,执行如下的命令:

1
./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --add-module=/usr/local/nginx/third_module/echo-nginx-module-0.61 --with-http_stub_status_module

之后使用make命令进行安装,切记不可使用make install命令,这样会覆盖前面已经安装的Nginx。

由于此处执行了编译和安装命令,那么接下来就需要将安装目录中的nginx命令进行更新,也就是将/home/envythink/nginx-1.17.0/objs目录下的nginx覆盖掉之前的/usr/local/nginx/sbin/目录下的nginx,使用的命令如下:

1
cp /home/envythink/nginx-1.17.0/objs/nginx /usr/local/nginx/sbin/nginx

如果出现cp: 无法创建普通文件"/usr/local/nginx/sbin/nginx": 文本文件忙的提示语,那么就需要使用systemctl stop nginx命令来终止Nginx的运行,然后重新运行上述命令。

之后进行语法检查和平滑重启Nginx,接着再次使用curl -I 127.0.0.1来查看输出信息:

1
2
3
4
5
6
7
8
9
10
[root@envythink nginx-1.17.0]# curl -I 127.0.0.1
HTTP/1.1 200 OK
Server: Envythink
Date: Wed, 18 May 2020 07:57:37 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 03 May 2020 01:18:28 GMT
Connection: keep-alive
ETag: "5fa0afe4-264"
Accept-Ranges: bytes

之后在浏览器中访问一个不存在的链接,可以看到页面出现如下所示的信息:

更改Nginx服务的默认用户

除了前面的安全优化之外,接下来还可以通过更改Nginx服务的默认用户来提升系统的安全性。

第一步,创建新用户,这里假定Nginx服务的默认用户名和组都是nginx,依次执行如下命令:

1
2
3
[root@envythink ~]# useradd nginx -s /sbin/nologin -M # 创建用户
[root@envythink ~]# id nginx # 检查用户
uid=1003(nginx) gid=1003(nginx) 组=1003(nginx)

第二步,重新编译Nginx。由于在前面安装了一些第三方插件,因此首先需要查看编译参数,如下所示:

1
2
3
4
[root@envythink http]# nginx -V
nginx version: nginx/1.17.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
configure arguments: --user=nginx --group=nginx --prefix=/usr/local/nginx --add-module=/usr/local/nginx/third_module/echo-nginx-module-0.61 --with-http_stub_status_module

可以发现笔者在之前编译的时候就使用了nginx用户和nginx用户组,因此接下来的操作是假设没有使用nginx用户和nginx用户组的情况。

回到/home/envythink/nginx-1.17.0目录,这是configure脚本所在目录,执行如下的命令:

1
./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --add-module=/usr/local/nginx/third_module/echo-nginx-module-0.61 --with-http_stub_status_module

之后使用make命令进行安装,切记不可使用make install命令,这样会覆盖前面已经安装的Nginx。

由于此处执行了编译和安装命令,那么接下来就需要将安装目录中的nginx命令进行更新,也就是将/home/envythink/nginx-1.17.0/objs目录下的nginx覆盖掉之前的/usr/local/nginx/sbin/目录下的nginx,使用的命令如下:

1
cp /home/envythink/nginx-1.17.0/objs/nginx /usr/local/nginx/sbin/nginx

如果出现cp: 无法创建普通文件"/usr/local/nginx/sbin/nginx": 文本文件忙的提示语,那么就需要使用systemctl stop nginx命令来终止Nginx的运行,然后重新运行上述命令。

第三步,修改Nginx主配置文件nginx.conf,在里面添加如下代码:

1
user nginx nginx;

注意代码添加的位置如下所示:

之后进行语法检查和平滑重启Nginx,然后使用如下命令来验证Nginx服务用户名是否已经修改成功:

1
2
3
[root@envythink conf]# ps -aux|grep nginx | grep -v grep
root 18873 0.0 0.2 20212 2044 ? Ss 15:55 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 18906 0.0 0.1 20212 1464 ? S 16:22 0:00 nginx: worker process

注意关于Nginx安全优化的相关学习就到此为止,后续开始学习其他知识。