|
7 w9 Q: }- y! M. {7 `
基础配置经常会有针对某个版本的nginx安全漏洞出现,隐藏nginx版本号就成了主要的安全优化手段之一,当然最重要的是及时升级修复漏洞http {
& k4 A6 L' r, [1 ]9 h) z9 X server_tokensoff;+ U% r0 ]* z" u: k' c9 C$ R2 q
}Header头设置。 ; ?! Q' }) S% Z+ p& H7 Y
在通常的请求响应中,浏览器会根据Content-Type来分辨响应的类型,但当响应类型未指定或错误指定时,浏览会尝试启用MIME-sniffing来猜测资源的响应类型,这是非常危险的X-Frame-Options。 " b* D& F9 S; | {
:响应头表示是否允许浏览器加载frame等属性,有三个配置DENY禁止任何网页被嵌入,SAMEORIGIN只允许本网站的嵌套,ALLOW-FROM允许指定地址的嵌套X-XSS-Protection:表示启用XSS过滤(禁用过滤为X-XSS-Protection: 0),mode=block表示若检查到XSS攻击则停止渲染页面
- G' R. `: E" U2 @# v( k( I X-Content-Type-Options:响应头用来指定浏览器对未指定或错误指定Content-Type资源真正类型的猜测行为,nosniff 表示不允许任何猜测例如一个.jpg的图片文件被恶意嵌入了可执行的js代码,在开启资源类型猜测的情况下,浏览器将执行嵌入的js代码,可能会有意想不到的后果
; F# P1 e2 p) F5 W add_header X-Frame-Options SAMEORIGIN;
" l; D! S8 W: d* r5 x # 禁止嗅探文件类型add_header X-Content-Type-Options nosniff;add_header 2 I) U6 t( i! p0 |. M6 z
X-XSS-Protection "1; mode=block"; 开启HSTS统一https访问add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
3 N* Z. E% ~: V" P; ^ ;账号认证server {
% ^0 p6 z/ C" S3 I2 L0 h$ C8 C# W location / {% s9 n# M9 V/ f& P' V: ?, o
auth_basic"please input user&passwd";
4 e- o- q8 q6 A9 R7 B' j! X8 A auth_basic_user_file k; Q3 x* c6 E" a
key/auth.key;/ N% Q; s/ C; ~! M
}7 W1 A/ i& v' F' X3 r* ?
}限制请求方法$request_method能够获取到请求nginx的method这里配置只允许GET/POST方法访问,其他的method返回405if ($request_method ; o/ V, @" V) M
!~ ^(GET|POST)$ ) { H4 f, M& I! o* j- V( ~# K) o
return405;
+ y! [# O* ], V) E; @- X5 E1 O* P }拒绝指定User-Agent可能有一些不法者会利用wget/curl等工具扫描我们的网站,我们可以通过禁止相应的user-agent 0 h6 k- O% y* T9 e2 X: R
来简单的防范Nginx的444状态比较特殊,如果返回444那么客户端将不会收到服务端返回的信息,就像是网站无法连接一样#禁止Scrapy等工具的抓取if ($http_user_agent~* (Scrapy|Curl|HttpClient)) + E# ^1 t: N* l( A- o" i
{& Z( f n: M7 ?) f
return444;
5 W+ X9 M" \' p }
E& j3 w t/ [, S& F+ Z6 ~3 U9 o #禁止指定UA及UA为空的访问if ($http_user_agent~ "WinHttp|WebZIP|FetchURL|node-superagent|java/|FeedDemon|Jullo|JikeSpider|Indy 9 B$ t/ O% a* g
Library|Alexa Toolbar|AskTbFXTV|AhrefsBot|CrawlDaddy|Java|Feedly|Apache-HttpAsyncClient|UniversalFeedParser|ApacheBench|Microsoft URL Control|Swiftbot|ZmEu|oBot|jaunty|Python-urllib|lightDeckReports Bot|YYSpider|DigExt|HttpClient|MJ12bot|heritrix|EasouSpider|Ezooms|BOT/ , H( F& N7 e+ Q8 N# g; n8 ?; b
0.1|YandexBot|FlightDeckReports|Linguee Bot|^$" ) { F7 v2 P1 j" N$ ]
return 444;
) a( G9 r. F Z }图片防盗链location /images/ {
7 p2 J h% S6 H6 V 8 U4 p8 Z0 H) R3 R) o9 X+ j
valid_referersnoneblocked www.host.com;
1 h8 Q# k4 e0 h- I8 z if ($invalid_referer) {
$ S9 S0 ?: x7 @$ r$ x return403;
) J( ~ @& N9 A4 s }
: L0 v H' x2 e J, C0 G }valid_referers
) A' x1 J* s8 \8 \ : 验证referer,其中none允许referer为空,blocked允许不带协议的请求,除了以上两类外仅允许referer为 www.host.com 时访问images下的图片资源,否则返回403
3 y2 Q& _0 S2 C# }. o 当然你也可以给不符合referer规则的请求重定向到一个默认的图片,比如下边这样location /images/ {
, \/ n% w6 W s& T valid_referersblocked www.host.com
9 r6 \2 a8 x: Z5 x7 P% k+ Z6 L if (
2 v; J) V" F; ?$ e9 w $invalid_referer) {* L8 N0 f3 S1 @! N# y# e
rewrite ^/images/.*.(gif|jpg|jpeg|png)$ /static/qrcode.jpg last;
/ S" _6 g, ~ O: a3 [7 ^ }) k$ V4 o, J" O. t; F) S
}限制并发及请求数
1 _ j/ n2 {0 f 网站安全配置(Nginx)防止网站被CC攻击(包括使用了CDN加速之后的配置方法)Nginx 有 2 个模块用于控制访问“数量”和“速度”简单的说,控制你最多同时有 多少个访问,并且控制你每秒钟最多访问多少次, 你的同时并发访问不能太多,也不能太快,不然就“杀无赦”。
! J" i/ \6 ]/ P# N8 p9 L HttpLimitZoneModule 限制同时并发访问的数量HttpLimitReqModule 限制访问数据,每秒内最多几个请求现在我们面对的最直接的问题就是, 经过这么多层加速,我怎么得到“最前面普通用户的 IP 地址”呢?
0 F; j# c; a9 Z1 R( h1 K- ?4 s% U 当一个 CDN 或者透明代理服务器把用户的请求转到后面服务器的时候,这个 CDN 服务器会在 Http 的头中加入 一个记录X-Forwarded-For : 用户IP, 代理服务器IPX-Forwarded-For : 用户IP, 代理服务器1-IP, 代理服务器2-IP, 代理服务器3-IP, ….
, P' ~' z1 m& W% a3 i0 a8 \5 Q 可以看到经过好多层代理之后, 用户的真实IP 在第一个位置, 后面会跟一串 中间代理服务器的IP地址,从这里取到用户真实的IP地址,针对这个 IP 地址做限制就可以了,标准配置Nginx 里面设置一个限制,配置如下: 9 y& b* D2 Q8 k
## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址最多有 50 个并发连接## 你想开 几千个连接 刷死我? 超过 50 个连接,直接返回 503 错误给你,根本不处理你的请求了 3 Y0 ?) `$ F X5 b1 Y
limit_conn_zone$binary_remote_addr zone=TotalConnLimitZone:10m ;
2 r C, W& Q7 W8 Q limit_conn TotalConnLimitZone 50;0 c+ M1 d( O T
* F5 X& o# r( Z# x2 j- u
limit_conn_log_levelnotice;
' a/ t. e8 I, @/ X. v8 M1 H S ## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址每秒处理 10 个请求## 你想用程序每秒几百次的刷我,没戏,再快了就不处理了,直接返回 503 错误给你 0 g) j0 g# l9 k% N1 _* Q- l- m
limit_req_zone$binary_remote_addr zone=ConnLimitZone:10m rate=10r/s;
/ E" z6 w7 L/ t; X& t7 l' g) z limit_req_log_levelnotice;
' t' ]5 `" i" G ## 具体服务器配置
6 O: g, K4 N0 [% _) c2 K( R3 _ server {
( p9 o( Y% l; X. ^ listen80;0 B" R/ N: ]" m1 A" e
location~ \.php$ {
, _/ G0 i% L. g7 i) n5 G7 r3 D/ T # 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了 ! X6 O# O; t% K! z: [8 y
limit_req zone=ConnLimitZone burst=5 nodelay;
* I( X: \& D. o8 H fastcgi_pass127.0.0.1:9000;
3 C1 [ V% r; X4 q+ N fastcgi_index
0 @8 C, `/ e, X" _7 G/ M2 _ index.php;% z% G! a4 N; c8 |" T! F; d' v
include fastcgi_params;
9 a- x1 j) p6 }! V& U! ]6 j }' {) S& @; i/ i* B7 v& f
}这样一个最简单的服务器安全限制访问就完成了,这个基本上你 Google 一搜索能搜索到 90% 的网站都是这个例子,而且还强调用“$binary_remote_addr”可以节省内存之类的废话
9 p4 T- t; q2 y+ V0 S; Q1 o0 i! B 经过多层CDN之后取得原始用户的IP地址Nginx 配置取得用户的原始地址map $http_x_forwarded_for $clientRealIp {
5 @& O- X2 J: i7 \' X ## 没有通过代理,直接用
; X" T& l- R! A2 `/ j' ~. G8 f7 K6 m ( m: u. N- Y$ [; m) x
remote_addr "" $remote_addr;
1 U ]" Z. ^0 R( T' y& d ## 用正则匹配,从 x_forwarded_for 中取得用户的原始IP ## 例如 X-Forwarded-For: 202.123.123.11, 208.22.22.234, 192.168.2.100,...
3 E) w& u& A) |" r* C2 t+ h% c ## 这里第一个 202.123.123.11 是用户的真实 IP,后面其它都是经过的 CDN 服务器
" ]2 A( t' z9 B# l3 O+ A) \" m+ A ~^(?P[0-9\.]+),?.*$ $firstAddr;' \' F5 s( q- H7 @9 v3 {: M/ e0 c
}$ ?4 }) `# _) |, A- q
4 \3 B" P* B& o# H& e4 {' ~! t4 D
## 通过 map 指令,我们为 nginx 创建了一个变量 $clientRealIp ,这个就是 原始用户的真实 IP 地址,## 不论用户是直接访问,还是通过一串 CDN 之后的访问,我们都能取得正确的原始IP地址 : P# G2 |! H0 y! w. s
根据用户的真实 IP 做连接限制下面是修改之后的 Nginx 配置:CDN环境下 Nginx 的安全配置Shell## 这里取得原始用户的IP地址map$http_x_forwarded_for $clientRealIp { % Y+ V; P2 u& i. T
""$remote_addr; ~^(?P[0-9\.]+),?.*$ $firstAddr;}## 针对原始用户 IP 地址做限制limit_conn_zone$clientRealIp zone=TotalConnLimitZone:20m ;
( K4 a: a% Q/ r; H2 B( n limit_connTotalConnLimitZone 50;limit_conn_log_levelnotice;## 针对原始用户 IP 地址做限制limit_req_zone$clientRealIp zone=ConnLimitZone:20m rate=10r/s;
3 |7 b& _: a- c #limit_req zone=ConnLimitZone burst=10 nodelay;limit_req_log_levelnotice;## 具体服务器配置server{ listen80;
$ f) P7 d' }( U9 e% V location~ \.php$ { ## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了 limit_req
4 r# I) \ r3 A f+ L zone=ConnLimitZone burst=5 nodelay;}} % S$ N- {7 y5 A* P G
s4 b7 w3 I) v' t+ w: z; o* g- G! ^ j
5 @/ R( j- r e) R! a/ Y- Y c) Z+ z! \
, A3 F8 p- I, p9 k v" g |