nginx配置之安全篇
[TOC]
使用最新的版本
- 最新的nginx版本,提供了更高的安全性
- 安装之前去官网找一下最新的版本,官方地址:https://nginx.org/en/download.html
find / -name nginx # 找到nginx安装目录
/usr/local/nginx/sbin/nginx -V # 查看ngxin版本
禁止目录浏览/隐藏版本信息
- 由于某些 Nginx 漏洞只存在于特定的版本,隐藏版本号可以提高安全性
- 一些 WEB 语言或框架默认输出的 X-Powered-By 也会泄露网站信息,如果部署上用到了 Nginx 的反向代理,则建议隐藏Nginx后端服务响应头中的版本信息,比如
X-Powered-By: PHP/5.4.43
http {
autoindex off; # 禁止目录浏览
server_tokens off; # 隐藏nginx版本信息,提高安全性,但并不会加快nginx的执行速度
proxy_hide_header X-Powered-By; # 隐藏proxy反向代理的后端主机头信息
proxy_hide_header Server;
}
- 验证效果
[root@localhost]# curl -s -I http://127.0.0.1 | grep Server #整改前
Server: nginx/1.25.0
[root@localhost]# curl -s -I http://127.0.0.1 | grep Server #整改后
Server: nginx
限制功能
限制HTTP请求方法
- 对于一般的网站和应用程序,只用允许 GET、POST、HEAD 这3种请求即可,其他请求方法直接返回 444 空响应
http {
#.其他省略...
server {
#.其他省略...
location / {
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444; # HTTP 444 响应指空响应
}
}
}
}
限制IP访问
- 若是内部业务或无需对外开放的站点,建议限制某些IP地址的客户端访问
- 规则按照顺序依次检测,直到匹配到第一条规则。 如下示例只允许
192.168.1.0/24
和10.1.0.0/16
访问,但192.168.1.1
除外。
http {
#.其他省略...
server {
#.其他省略...
location / {
deny 192.168.1.1; # 拒绝ip
allow 192.168.1.0/24; # 允许ip
allow 10.1.0.0/16; # 允许ip
deny all; # 拒绝其他所有ip
}
}
}
限制并发和速度
nginx限制IP的连接和并发分别有两个模块:
- limit_req_zone 用来限制单位时间内的请求数,即速率限制,采用的漏桶算法 "leaky bucket"
- limit_req_conn 用来限制同一时间连接数,即并发限制
其中 limit_req_conn 模块可以根据源IP限制单用户并发访问的连接数或连接到该服务的总并发连接数。
注:
limit_req
如果请求不需要被延迟,添加nodelay
参数,服务器会立刻返回503状态码。加上 nodelay之后超过 burst大小的请求就会直接返回503,如果没有该字段会造成大量的tcp连接请求等待。
http {
#.配置limit_zone(缓存空间)为one
limit_conn_log_level error;
limit_conn_status 503;
limit_conn_zone $binary_remote_addr zone=one:10m; # Zone=one:10m 表示设置了名为one的存储区,大小为10m
limit_conn_zone $server_name zone=perserver:10m;
limit_req_zone $binary_remote_addr zone=allips:100m rate=10r/s; # rate=10r/s 表示允许每秒不超过10个请求
server {
#.其他省略...
location / {
limit_conn one 100; # 表示限制每个客户端IP的最大并发连接数100
limit_conn perserver 1000; # 表示该服务提供的总连接数不得超过1000,超过请求的会被拒绝
limit_req zone=allips burst=5 nodelay; # 表示最大延迟请求数量不大于5,若请求过多而不需要限制延迟则配置nodelay参数
}
}
}
设置超时时间
- 合理设置timeout可防御DOS攻击
http {
keepalive_timeout 60; # TCP长连接存活时间,默认75秒
client_header_timeout 10; # 设置请求头header的超时时间
client_body_timeout 10; # 设置请求体body的超时时间
send_timeout 600; # 指定客户端的响应超时时间
}
自定义缓冲区大小
- 设置自定义缓存以限制缓冲区溢出攻击
http {
client_header_buffer_size 4k; # 设置客户端请求的header头缓冲区大小
client_body_buffer_size 256k; # 客户端post的数据先写入client_body_buffer中,若buffer写满会写入临时文件
client_max_body_size 20m; # 设置客户端能够上传的文件大小
large_client_header_buffers 4 32k; # 对于超过client_header_buffer_size的header将会使用该部分buffer,第一个是个数,第二个是每个buffer的大小
server_names_hash_bucket_size 128; # 服务器名字的hash表大小,可选32/64/128
}
注:上述的参数不是最优参数,仅供参考。
账号及权限
配置nginx进程启动账号
- 创建nginx服务账户(比如
www
),并修改站点目录(比如/data/website
)的权限
cat /etc/passwd | grep www || useradd www -s /sbin/nologin
chown -R www.www /data/website
- 更改nginx默认用户,为nginx服务降权(使用非root跑nginx woker进程)
user www;
配置Nginx账号锁定
- 执行
passwd -l www
将nginx启动账号进行锁定 - 执行
passwd -S www
确认账号已锁定
[root@localhost]# passwd -l www
Locking password for user www.
passwd: Success
[root@localhost]# passwd -S www
www LK 2023-06-05 0 99999 7 -1 (Password locked.)
配置nginx配置文件权限
- 确保NGINX配置文件权限为644,以抵御外来攻击
- 默认文件为
/usr/local/nginx/conf/nginx.conf
find / -name nginx.conf
chmod 644 /usr/local/nginx/conf/nginx.conf
日志相关
日志设置
- 通过 log_format 指令自定义请求日志的格式,注:
nsfocus
是设置配置文件格式的 alias - 在server作用域中配置的access_log,其的优先级比http下的高,如果没有指定log_format则会使用系统默认的combined
http {
log_format nsfocus '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#access_log off # 关闭当前作用域下的访问日志,可加快磁盘io操作
access_log logs/nginx_access.log nsfocus; # 设置访问日志的位置和格式
error_log logs/nginx_error.log crit; # 设置错误日志的位置和级别
server {
#.其他省略...
# access_log /var/log/nginx_access.log; #
# error_log /var/log/nginx_error.log; # server作用域的优先级比http下的高
}
}
使用logrotate切割日志
- 通过 yum 安装
logrotate
日志服务
yum install -y logrotate
- 创建一个切割
nginx
的配置文件
cat > /etc/logrotate.d/nginx <<EOF
/usr/local/nginx/logs/*nginx*.log {
daily
rotate 7
minsize 50M
missingok
dateext
compress
notifempty
sharedscripts
postrotate
[ -e /usr/local/nginx/logs/nginx.pid ] && kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
endscript
}
EOF
- 通常,logrotate 切割时间默认是在每天的3:22
[root@localhost local]# cat /etc/anacrontab | grep START_HOURS_RANGE
START_HOURS_RANGE=3-22
自定义错误信息
- 在网站访问过程中,经常会遇见各种各样的错误,如找不到访问的页面则会提示
404 Not Found
错误,没有访问权限会提示403 Forbidden
等,对于普通人而言,这样的提示界面并不友好。
error_page 403 /403.html; # 指定网站根目录下的页面 403.html, 处理 403 错误
error_page 404 =200 /404.jpg; # 更改晌应状态码,产生4O4的时候返回码是200,内容是404.jpg
error_page 500 502 503 504 /50x.html; # 为某一类的错误设置处理方式
location = /50x.html { # 配置location保证可以找到自定义的50x页面
root /usr/share/nginx/html;
}
合理配置响应头
- 如果网站是由 Nginx 通过 proxy_pass 把请求反向代理给后端的 IP 和端口,则建议添加如下头部响应:
http {
#.其他省略...
server {
#.其他省略...
location / {
add_header Strict-Transport-Security "max-age=31536000"; # 在指定的max-age内,始终通过HTTPS访问本站,即使用户输入HTTP地址也会在本地替换为HTTPS再发送请求
add_header X-Frame-Options deny; # 指定此网页是否允许被iframe嵌套,deny就是不允许任何嵌套发生
add_header X-Content-Type-Options nosniff;
}
}
}
配置防盗链
- 盗链是指本网站的图片等资源链接被使用到了其他非授权的网站页面上。对于被盗链的网站来说,被消耗了大量带宽和服务器资源却没有产生任何价值
- 防盗链简单来说就是应用服务中的一些资源,只有规定的合法的请求才能访问,其他请求不能访问资源(如css,js,img等)
valid_referers
指令server_names
参数:若 referer 中的站点域名和 server_names 中的某个域名匹配,则允许访问
http {
#.其他省略...
server {
#.其他省略...
location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip)$ {
expires 30d;
valid_referers none blocked server_names *.sqlfans.cn http://localhost; # 有效的来源
if ($invalid_referer) { # 如果无效的来源
rewrite ^/ http://www.xxx.com/403.html;
# return 403;
}
}
}
}
- 验证效果
curl --referer http://wiki.sqlfans.cn -I http://127.0.0.1/logo.png
SSL协议加固
- 启用 HTTPS 并正确配置了证书,意味着数据传输过程中无法被第三者解密或修改
- 通过参数 ssl_protocols(没有请添加)禁用TLS 1.0、TLS 1.1(去掉即可),并将其替换为TLS 1.2或更高版本
http {
server {
listen 443 ssl;
#.其他省略...
ssl_protocols TLSv1.2 TLSv1.3; # 启用TLSv1.3则要求 OpenSSL版本 >= 1.1.1
ssl_ciphers HIGH:!aNULL:!MD5; # 用!号禁用不需要的加密套件
ssl_prefer_server_ciphers on;
}
}