1、Nginx 基本安全优化
1.1 隐藏服务版本号
位置:http、server、location
代码:server_tokens: off;
1.2 更改源码,修改软件名及版本号
修改三个文件:
nginx-1.6.3/src/core/nginx.h
nginx-1.6.3/src/http/ngx_http_header_filter_module.c
nginx-1.6.3/src/http/ngx_http_special_response.c
1.3 更改nginx的默认用户
useradd nginx -s /sbin/nologin -M
默认为nobody;主配置文件:
user nginx nginx;
nginx work进程的用户。
2、根据参数优化nginx服务性能
2.1 优化nginx服务的worker进程个数
worker_processes 1;
进程数可以是CPU的核数*2;
# 查看系统有多少核心
grep processor /proc/cpuinfo | wc -l
# 查看有几颗cpu
grep 'physical id' /proc/cpuinfo | sort | uniq |wc -l
2.2 绑定不同的nginx进程到不同的cpu上
work_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
2.3 nginx 事件处理模型优化
events { # events 指令是设定nginx的工作模式和连接数上限
use epoll;
worker_connections 20480; # 单个进程允许的客户端最大连接数;
}
进程的最大连接数受linux 系统进程d的最大打开文件数限制。
2.4 nginx worker进程最大打开文件数
worker_rlimit_nofile 65535;
最大打开文件数,可以设置为系统优化后d的ulimit -HSn 的结果。
放置位置:主标签段
2.5 优化服务器域名的散列表大小
放置位置:仅能放置在http 标签端
server_name_hash_max_size 512; # 默认是512kb
server_name_hash_bucket_size 64;
2.6 高效文件传输模式
sendfile on;
tcp_nopush on;
tcp_nodelay on; # 开启这俩on,可以防止网络和磁盘io阻塞,提高nginx工作效率。
2.7 调整连接超时时间
keepalive_timeout 60; # 长连接超时时间
client_header_timeout 15; # 读取客户端请求头数据的超时时间
client_body_timeout 15; # 读取客户端请求主体的超时时间
send_timeout 25; # 响应客户端的超时时间,如果在这个时间内,客户端没有接受任何数据,连接将被关闭。
2.8 设置最大的客户端请求主体大小
client_max_body_size 8m;
位置:http\server\location
2.9 fastcgi 调优
2.10 gzip压缩性能优化
gzip on;
gzip_min_length 1k; # 允许压缩页面d的最小字节数,建议设置为1k,小于1k可能越压越大。
gzip_buffers 4 32k;# 压缩缓冲区大小
gzip_http_version 1.1; #
gzip_comp_level 9;
gzip_types text/css text/xml applicaton/javascript;
gzip_vary on;
# 这个选项可以让前段的缓存服务器缓存经过gzip 压缩的页面,比如用squid缓存经过nginx压缩的数据。
2.11 expires 缓存实现性能优化
有可能不希望被缓存的内容:
1、广告图片,用户广告服务,都缓存了就不好控制展示了
2、网站流量统计工具(js代码),都缓存了流量统计就不准了
3、更新很频繁的文件
3、nginx 日志相关优化与安全
3.1 编辑脚本实现nginx access日志轮询
3.2 不记录不需要的访问日志
location ~ .*\.(js|jpg|JPG|css|gif|GIF)$ {
access_log off;
}
3.3 访问日志的权限设置
# 加入日志目录为/app/logs,则授权方法如下
chown -R root.root /app/logs
chmod -R 700 /app/logs
4、nginx站点目录及文件url访问控制
4.1 根据扩展名限制访问
location ~* ^/data/(attacgment|avatar)/.*\.(php|php5)$ {
deny all;
}
# 对上述目录d的限制必须在nginx 处理php 服务配置的前边。
location ~ .*\.(php|php5)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
}
4.2 禁止访问指定目录下的所有文件
# 禁止访问多个目录
location ~* ^/data/(js|static) {
deny all;
}
# 禁止访问并返回指定d的状态码
location ~* ^/data/(js|static) {
return 403;
}
4.3 限制来源ip访问
使用ngx_http_access_module限制网站来源ip访问。
if ( $remote_addr = 10.0.0.7 ) {
return 403;
}
location / {
root html/blog;
allow 10.0.0.7;
deny all;
}
对于allow的ip端,从允许访问的端位从小到大排列,例如/24的下边才能是/16,下边是/8.
以deny all;结尾的,表示除了上边允许的,其他都是禁止的。
4.4 禁止ip访问
server {
listen 80 default_server;
server_name _;
return 444;
}
server {
listen 80 default_server;
server_name _;
rewrite ^ http://www.houbinglei.com$request_uri?;
}
# There is nothing special about this name, it is just one of a myriad of invalid domain names which never intersect with any real name. Other invalid names like “--” and “!@#” may equally be used.
if ( $host !~ ^www.houbinglei.com$ ) {
rewrite ^(.*) http://www.houbinglei.com$request_uri?;
}
# Nginx 的 $host 与 $http_host 的区别
$host 是nginx的官方变量,可以从官方查询
$http_host 则是读取请求头header里面的key,所有请求头里面的key在nginx里面都可以通过小写和下划线来让nginx读取。例如header里面的Host就能转成$http_host, user_agent可以转成$http_user_agent。
所以,只要是header的请求头都可以这样被nginx读取,
HEAD /rec/app/detail/youxidaren.html HTTP/1.1
Host: mo.ouwan.com
Content-type: html/txt
Test-key: test-value
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Thu, 22 Mar 2018 12:28:56 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Vary: Cookie
# 这三个头都是我请求的时候加的。
x_host: mo.ouwan.com
x_test_key: test-value
x_content_type: html/txt
当然这个几个头部能在response显示是因为在nginx加了add_header控制的:
location / {
add_header x_host $http_host;
add_header x_test_key $http_test_key;
add_header x_content_type $http_content_type;
}
$http_header的应用:当我们一个项目部署在两个服务器下面,然后在另外一个服务器搭建nginx反响代理,反响代理把请求转发给两个服务器的时候,他们的日志记录的是反向代理的ip, 而不是真正请求的用户IP, 这时就可以通过配置proxy_set_header 把真实IP设置给一个X-forwarded-For 或者 X-Real-IP 转给后端服务器,然后后端服务器读取通过http_x_real_ip来读取真实IP, 记录到access_log下面
location / {
proxy_pass http://tg_web_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
}
日志的格式把第一个IP换成刚才转发过来的头部X-Real-IP就可以记录用户IP了:
log_format tg_log '$http_x_real_ip - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$gzip_ratio" - $request_time';
5、nginx图片及目录防盗链解决方案
防止别人盗用你的链接。
# referer
# 请求从哪里过来的,通过这个字段,阻止一些不可认的请求。
ngx_http_referer_module 模块用于在referer请求头字段阻止无效的值请求访问。
示例:
location ~* \.(gif|jpg|png|mp4)$ {
valid_referers none blocked server_names # none 是没有这个referers这个值, blocked是这个值是空;
*.nextdevops.cn nextdevops.* www.example.org/images/
~\.google\. ~\.baidu\.;
if ($invalid_referer) {
return 403;}
expires 3d; # 设置3天d的浏览器缓存。
}
ngx_http_secure_link_modle模块用于检测请求连接的真伪,保护资源未授权访问,并限制连接。
该模块提供了两种操作模式:
a) secure_link和secure_link_md5指令启用,定义URL传参的变量,从中提取md5值及有效期进行比对。
b) secure_link_secret指令启用,检查请求连接的真实性。
示例1:
location /download/ {
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri secret";
if ($secure_link = "") { ## 等于空,是不匹配
return 403; }
if ($secure_link = "0") { ## 等于0,是有效期过了
return 410; }
...
}
# 需要自己写脚本,客户端提前拿到md5值,和过期时间,生成$secure_link。
echo -n '2147483647/s/link127.0.0.1 secret' | \
openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d
6、错误页面优雅显示
403 === 一般为服务器权限配置不当所致
404 === 资源不存在
502 === 一般为代理服务器下边d的节点出了问题
error_page 404 /404.html;
代码中d的/ 是相对于站点根目录 html/www 的
error_page 400 401 402 403 http://xxxx/error1.html
error_page 500 501 502 503 http://xxxx/error2.html
7、nginx站点目录及目录权限优化
# 单机lnmp环境
所有的目录755,文件644,所有目录和文件用户和组都是root;
然后把用户上传资源的目录权限设置为755,将用户和组设置为nginx 服务用户;
最后对该目录做资源访问限制。
# 集群架构中
动态web集群,nginx+php,755,644,都是root
静态资源集群,nginx,755,644,都是root
上传资源upload集群,用户上传资源的目录权限设置为755,将用户和组设置为nginx 服务用户。
8、防爬虫优化
每个网站都有的爬虫协议说明robots.txt-->希望大家遵守的,也是防止爬虫的一种方法
# 我们可以根据客户端的user-agents信息,轻松地阻止指定的爬虫爬取我们的网站。
if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot-Modile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Yahoo! SSlurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot")
{
return 403;
}
9、利用Nginx限制http的请求方法
最常用的HTTP方法为GET,POST,我们可以通过Nginx限制HTTP请求的方法来达到提升服务器安全的目的,例如,让HTTP只能使用GET,HEAD和POST方法的配置如下:
# Only allow these request methods
if ($request_method ! ~ ^(GET|HEAD|POST)$)
{
return 501;
}
当上传服务器上传数据到存储服务器时,用户上传写入的目录就不得不给Nginx对应的用户相关权限,这样一旦程序有漏洞,木马就有可能被上传到服务器挂载的对应存储服务器的目录里,虽然我们也做了禁止PHP,SH,PL,PY等扩展名的解析限制,但还是会遗漏一些想不到的可执行文件。对于这样情况可以通过限制上传服务器的Web服务(可以具体到文件)使用GET方法,防止用户通过上传服务器访问存储内容,让访问存储渠道只能从静态或图片服务器入口进入。例如,在上传服务器上限制HTTP的GET方法的配置如下:
Only deny GET request methods ##
if ($request_method ~* ^(GET)$)
{
return 501;
}
#提示:还可以加一层location,更具体地限制文件名
10、CDN网站加速
首先要说的是,不是所有的网站都可以一上来就能用CDN的。要加速的业务数据应该存在独立的域名,例如:img1-4.yunjisuan.com/video1-4.yunjisuan.com,业务内容图片,附件,JS,CSS等静态元素,这样的静态网站域名才可以使用CDN。
;A records
img.yunjisuanl.com IN A 124.106.0.21 (企业服务器的IP)
#删除上面的记录,命令如下:
img.yunjisuanl.com IN A 124.106.0.21 (服务器的IP)
#然后,做下面的别名解析:
;CNAME records
img.yunjisuan.com IN CNAME bbs
img.yunjisuan.com 3M IN CNAME img.yunjisuan.com.cachecn.com.
提示:
这个img.yunjisuan.com.cachecn.com.地址必须是事先由CDN公司配置好的CDN公司的域名。国内较大的CDN提供商为网宿,蓝讯,快网。
11、nginx 程序架构优化
分离的最佳方式是分别使用独立的服务器(需要改动程序),如果程序实在不易更改,次选方案是在前端负载均衡器Haproxy/Nginx上,根据URI(例如目录或扩展名)过滤请求,然后抛给后面对应的服务器。
12、使用普通用户启动nginx ( 监牢模式)
useradd inca
su - inca
mkdir conf logs www #在普通用户家目录下创建nginx配置文件目录
cp /usr/local/nginx/conf/mime.types ~/conf/
echo "hehe" > www/index.html
# 在普通用户的家目录里的conf目录里创建主配置 文件 主配文件的路径全部找/home/inca
# 特权用户root使用的80端口,改为普通用户使用的端口,在1024以上.8080
[inca@nginx-web01 ~]$ cat conf/nginx.conf
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
worker_rlimit_nofile 65535;
error_log /home/inca/logs/error.log;
user inca inca;
pid /home/inca/logs/nginx.pid;
events {
use epoll;
worker_connections 10240;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
log_format main '$remote_addr-$remote_user[$time_local]"$request"'
'$status $body_bytes_sent "$http_referer"'
'"$http_user_agent""$http_x_forwarded_for"';
server {
listen 8080;
server_name www.inca.com;
root /home/inca/www;
location / {
index index.php index.html index.htm;
}
access_log /home/inca/logs/web_blog_access.log main;
}
}
/usr/local/nginx/sbin/nginx -c /home/wk/conf/nginx.conf &>/dev/null
13、控制nginx 并发连接数量
ngx_http_limit_conn_module这个模块用于限制每个定义的key值的连接数(Nginx默认已经被编译),特别是单IP的连接数。
不是所有的连接数都会被计数。一个符合计数要求的连接是整个请求头已经被读取的连接。
应用场景之一是用于服务器下载,命令如下:
location /download/ {
limit_conn addr 11;
}
上面的命令限制访问download下载目录的连接数,该连接数1.
不仅可以限制单IP的并发连接数,还可以限制虚拟主机总连接数,甚至可以对两者同时限制。
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
limit_conn_zone $binary_remote_addr zone=addr:10m; #设置参数下边才会生效
limit_conn_zone $server_name zone=perserver:10m; #设置参数下边才会生效
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html;
index index.html index.htm;
#limit_conn addr 1;
limit_conn perserver 2; #设置虚拟主机连接数为2
}
}
14、控制客户端请求nginx的速率
ngx_http_limit_req_module模块用于限制每个IP访问每个定义key的请求速率。
ab 每秒发送300个, 设置limit_req 每秒处理100个:
limit_req_zone $binary_remote_addr zone=qps:10m rate=100r/s;
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; #以请求的客户端IP作为key值,内存区域命令为one,分配10m内存空间,访问速率限制为1秒1次请求(request)
# limit_conn_zone $binary_remote_addr zone=addr:10m;
# limit_conn_zone $server_name zone=perserver:10m;
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html;
index index.html index.htm;
limit_req zone=one burst=5; #使用前面定义的名为one的内存空间,队列值为5,即可以有5个请求排队等待
# limit_conn addr 1;
# limit_conn addr 1;
}
}