|
! @/ r n, {; [/ O" o% s& z
基础配置经常会有针对某个版本的nginx安全漏洞出现,隐藏nginx版本号就成了主要的安全优化手段之一,当然最重要的是及时升级修复漏洞http {
1 a+ u& W' B: k. @, T8 l- [ server_tokensoff;( }0 k6 U, g# V6 S
}Header头设置。 1 d& f* W1 ]' A" c' e
在通常的请求响应中,浏览器会根据Content-Type来分辨响应的类型,但当响应类型未指定或错误指定时,浏览会尝试启用MIME-sniffing来猜测资源的响应类型,这是非常危险的X-Frame-Options。
& p G/ U; @( o( E :响应头表示是否允许浏览器加载frame等属性,有三个配置DENY禁止任何网页被嵌入,SAMEORIGIN只允许本网站的嵌套,ALLOW-FROM允许指定地址的嵌套X-XSS-Protection:表示启用XSS过滤(禁用过滤为X-XSS-Protection: 0),mode=block表示若检查到XSS攻击则停止渲染页面
0 S) e$ s: t; L! u# X% X X-Content-Type-Options:响应头用来指定浏览器对未指定或错误指定Content-Type资源真正类型的猜测行为,nosniff 表示不允许任何猜测例如一个.jpg的图片文件被恶意嵌入了可执行的js代码,在开启资源类型猜测的情况下,浏览器将执行嵌入的js代码,可能会有意想不到的后果
9 X1 w! p7 @& M3 j0 \6 `6 K3 M add_header X-Frame-Options SAMEORIGIN;
; p$ v% H1 q1 A C0 ? # 禁止嗅探文件类型add_header X-Content-Type-Options nosniff;add_header
2 U" l- y0 E* `) i: b5 b" p X-XSS-Protection "1; mode=block"; 开启HSTS统一https访问add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
7 u! Q# H, V5 _$ k' q* C0 Z1 l ;账号认证server {
+ K- U) T$ o1 ~+ I location / {' E# C3 N3 i$ G, i" H* H
auth_basic"please input user&passwd";# h- C4 G8 S0 S/ }) [* G
auth_basic_user_file ' d$ o% n1 g, N+ x; l- j7 y- y
key/auth.key;6 c( m: s7 R, K1 Y) o
}7 e9 v/ x; q6 }9 ~' [
}限制请求方法$request_method能够获取到请求nginx的method这里配置只允许GET/POST方法访问,其他的method返回405if ($request_method
2 _4 C; M. i; E: m; S9 [+ x$ \- p !~ ^(GET|POST)$ ) {
& G* X* B/ e6 N' I- c return405;
6 p6 A3 ~: G. R; l* K3 H }拒绝指定User-Agent可能有一些不法者会利用wget/curl等工具扫描我们的网站,我们可以通过禁止相应的user-agent / G/ V( a- ~8 q6 {) T
来简单的防范Nginx的444状态比较特殊,如果返回444那么客户端将不会收到服务端返回的信息,就像是网站无法连接一样#禁止Scrapy等工具的抓取if ($http_user_agent~* (Scrapy|Curl|HttpClient)) 8 k7 `9 k' k8 ^6 A3 y0 C* a* V4 Q
{1 [$ \" u" G/ }: X! `( V6 y! \
return444;
3 W, i% C: k- j/ C }6 t. Y4 \, e/ r. ^5 h5 \
#禁止指定UA及UA为空的访问if ($http_user_agent~ "WinHttp|WebZIP|FetchURL|node-superagent|java/|FeedDemon|Jullo|JikeSpider|Indy
. f7 [+ q* j) Y g9 K! ^7 ~$ | r 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/
) l) g: N0 x" X$ \# p5 r 0.1|YandexBot|FlightDeckReports|Linguee Bot|^$" ) {! u; v8 t" d- `/ y8 Z
return 444;
8 v) j% u1 g A5 }3 A }图片防盗链location /images/ {! A" x; _* s9 P+ v+ T7 H' R. z% r
+ R5 {! x6 w# O" E valid_referersnoneblocked www.host.com;
% r" }, ^% q/ V6 J% [: f if ($invalid_referer) {
+ M+ P: D3 A( r# B% ]& a3 D return403;' R& j. h y) E$ F
}
3 c& f4 v6 D' |0 J }valid_referers
1 B3 A1 e- ^! `' X : 验证referer,其中none允许referer为空,blocked允许不带协议的请求,除了以上两类外仅允许referer为 www.host.com 时访问images下的图片资源,否则返回403 & a: L" _' h; n/ P$ D. Y9 V: q
当然你也可以给不符合referer规则的请求重定向到一个默认的图片,比如下边这样location /images/ {6 Z+ D" Z% J& E( `7 y3 T8 M' x
valid_referersblocked www.host.com
$ n: B7 B$ [ w if ( ( `; R8 Q3 ?) k, t2 y
$invalid_referer) {0 i' T1 z3 z7 Z/ M4 i, G
rewrite ^/images/.*.(gif|jpg|jpeg|png)$ /static/qrcode.jpg last;
5 d' x3 ~; w. O$ ]# W; Y) T }
5 }1 f, E. ] {7 \; u' _ }限制并发及请求数 , s7 r4 o* y8 Q2 _! t3 p* K$ v
网站安全配置(Nginx)防止网站被CC攻击(包括使用了CDN加速之后的配置方法)Nginx 有 2 个模块用于控制访问“数量”和“速度”简单的说,控制你最多同时有 多少个访问,并且控制你每秒钟最多访问多少次, 你的同时并发访问不能太多,也不能太快,不然就“杀无赦”。 " P% w9 V( b' F" P4 z, T; R# m
HttpLimitZoneModule 限制同时并发访问的数量HttpLimitReqModule 限制访问数据,每秒内最多几个请求现在我们面对的最直接的问题就是, 经过这么多层加速,我怎么得到“最前面普通用户的 IP 地址”呢? ; p( X- {) Q% X8 T% y
当一个 CDN 或者透明代理服务器把用户的请求转到后面服务器的时候,这个 CDN 服务器会在 Http 的头中加入 一个记录X-Forwarded-For : 用户IP, 代理服务器IPX-Forwarded-For : 用户IP, 代理服务器1-IP, 代理服务器2-IP, 代理服务器3-IP, …. : Q5 R/ D( X C& g. b
可以看到经过好多层代理之后, 用户的真实IP 在第一个位置, 后面会跟一串 中间代理服务器的IP地址,从这里取到用户真实的IP地址,针对这个 IP 地址做限制就可以了,标准配置Nginx 里面设置一个限制,配置如下: 1 J3 m, i( C7 S5 |% a
## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址最多有 50 个并发连接## 你想开 几千个连接 刷死我? 超过 50 个连接,直接返回 503 错误给你,根本不处理你的请求了
3 B1 W/ I$ m# _' S% U limit_conn_zone$binary_remote_addr zone=TotalConnLimitZone:10m ;9 l( B2 v- J* n* }, D& O
limit_conn TotalConnLimitZone 50;
3 A* S4 y" ]3 t9 U p. o! J 8 V8 E7 q+ F1 g+ n- _# r$ }/ S! p1 H
limit_conn_log_levelnotice;
F3 w# k% \# O; Q( N' U ## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址每秒处理 10 个请求## 你想用程序每秒几百次的刷我,没戏,再快了就不处理了,直接返回 503 错误给你
1 l5 P% n4 n6 D# M limit_req_zone$binary_remote_addr zone=ConnLimitZone:10m rate=10r/s;
1 @. b: S4 R7 Q% O' E( l limit_req_log_levelnotice;
3 y& S+ M6 i% T8 C2 F% R ## 具体服务器配置 : c( g3 w0 l' V" t$ f" o; s
server {
4 ^) T C. q% G3 S) U- G listen80;" X7 P( E3 ]1 B
location~ \.php$ {( v# F* R, D$ \4 K: O; y
# 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了 8 P! _1 z, u1 n: C& Z
limit_req zone=ConnLimitZone burst=5 nodelay;8 O. D# J8 s5 L
fastcgi_pass127.0.0.1:9000;
* P# g# c1 |6 K, P fastcgi_index
( W7 d; S( t, A8 k6 e& c2 k! Y+ o index.php;2 p. |* f* ~8 z/ G: u9 P
include fastcgi_params;
, z3 O7 [% f. h. I" D8 I: F1 j# @ }! \4 a) q8 k& H; G7 M- X- B
}这样一个最简单的服务器安全限制访问就完成了,这个基本上你 Google 一搜索能搜索到 90% 的网站都是这个例子,而且还强调用“$binary_remote_addr”可以节省内存之类的废话
$ c1 X$ T; f5 k" |6 A$ A 经过多层CDN之后取得原始用户的IP地址Nginx 配置取得用户的原始地址map $http_x_forwarded_for $clientRealIp {) W6 W. W+ n N8 ~- V. ?6 ~
## 没有通过代理,直接用
* b) f) V$ W" g% Y4 {9 {- n% H* J
) r2 n Y1 r" r3 F# a0 O+ V0 ^ remote_addr "" $remote_addr;+ I2 {5 @1 f( l
## 用正则匹配,从 x_forwarded_for 中取得用户的原始IP ## 例如 X-Forwarded-For: 202.123.123.11, 208.22.22.234, 192.168.2.100,...
( p7 ?" l! Z+ V2 o ## 这里第一个 202.123.123.11 是用户的真实 IP,后面其它都是经过的 CDN 服务器! l4 q# z: U! z7 M
~^(?P[0-9\.]+),?.*$ $firstAddr;
7 L; B0 C, x) l$ g. a* R0 I/ n }" l. f6 ^+ K8 D/ F4 A$ _
0 h2 a1 R& w6 J! h4 A
## 通过 map 指令,我们为 nginx 创建了一个变量 $clientRealIp ,这个就是 原始用户的真实 IP 地址,## 不论用户是直接访问,还是通过一串 CDN 之后的访问,我们都能取得正确的原始IP地址
+ c2 B0 d O. P$ F- j. f- [ 根据用户的真实 IP 做连接限制下面是修改之后的 Nginx 配置:CDN环境下 Nginx 的安全配置Shell## 这里取得原始用户的IP地址map$http_x_forwarded_for $clientRealIp { 9 {3 [) `/ N# K5 Z
""$remote_addr; ~^(?P[0-9\.]+),?.*$ $firstAddr;}## 针对原始用户 IP 地址做限制limit_conn_zone$clientRealIp zone=TotalConnLimitZone:20m ; / `( w9 h1 \- w, F* l* y5 r s
limit_connTotalConnLimitZone 50;limit_conn_log_levelnotice;## 针对原始用户 IP 地址做限制limit_req_zone$clientRealIp zone=ConnLimitZone:20m rate=10r/s; * R- _0 V% [) A- v; q6 O
#limit_req zone=ConnLimitZone burst=10 nodelay;limit_req_log_levelnotice;## 具体服务器配置server{ listen80; * h% w5 O& A3 O+ o( t
location~ \.php$ { ## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了 limit_req ; H2 ]9 R& Y$ ]& h- K9 r2 f( V
zone=ConnLimitZone burst=5 nodelay;}}
7 B g* a% A' V7 a
8 v" ~0 y" W5 o. P6 V6 r
( u5 y: G+ `$ W
/ M4 ?$ R9 L, W: B' d
! ^$ ]' b4 }, Z& }2 }/ K5 k |