|
" ]. J: u! r5 s+ Y+ X 基础配置经常会有针对某个版本的nginx安全漏洞出现,隐藏nginx版本号就成了主要的安全优化手段之一,当然最重要的是及时升级修复漏洞http {
: T |0 r# T& x" |( a server_tokensoff;
8 W0 h8 L5 `$ H& D }Header头设置。 ! |+ p2 H5 L% q9 l$ k8 m; P+ s
在通常的请求响应中,浏览器会根据Content-Type来分辨响应的类型,但当响应类型未指定或错误指定时,浏览会尝试启用MIME-sniffing来猜测资源的响应类型,这是非常危险的X-Frame-Options。 - a/ d; w1 C0 \5 W
:响应头表示是否允许浏览器加载frame等属性,有三个配置DENY禁止任何网页被嵌入,SAMEORIGIN只允许本网站的嵌套,ALLOW-FROM允许指定地址的嵌套X-XSS-Protection:表示启用XSS过滤(禁用过滤为X-XSS-Protection: 0),mode=block表示若检查到XSS攻击则停止渲染页面
2 d) u0 P# Z0 e. Z- ~( K0 K X-Content-Type-Options:响应头用来指定浏览器对未指定或错误指定Content-Type资源真正类型的猜测行为,nosniff 表示不允许任何猜测例如一个.jpg的图片文件被恶意嵌入了可执行的js代码,在开启资源类型猜测的情况下,浏览器将执行嵌入的js代码,可能会有意想不到的后果
3 n- u, o) v- Q+ s1 L2 r% m add_header X-Frame-Options SAMEORIGIN;7 y! j; C- T8 f: ^( a+ N: L
# 禁止嗅探文件类型add_header X-Content-Type-Options nosniff;add_header
% A) P+ q, x0 ?5 h4 N. k4 n X-XSS-Protection "1; mode=block"; 开启HSTS统一https访问add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" 6 _8 x7 S+ e0 l: {5 J. W
;账号认证server {
; f! G* S" ?# Z' { m location / {
9 x* R& l8 H; K0 C) G auth_basic"please input user&passwd";
! G; Y; j" C G ]! e- c auth_basic_user_file / n' E- |& _/ {* l3 P% C
key/auth.key;
/ w! |: |' Y8 X, o; a P. q2 Z }$ A, P' p0 z; P$ x* q! R
}限制请求方法$request_method能够获取到请求nginx的method这里配置只允许GET/POST方法访问,其他的method返回405if ($request_method + z7 K$ O* [, n2 p
!~ ^(GET|POST)$ ) {
9 e" n4 z5 G+ z# U. W return405;2 y. e" d) z8 Y$ W
}拒绝指定User-Agent可能有一些不法者会利用wget/curl等工具扫描我们的网站,我们可以通过禁止相应的user-agent
3 @- C7 U! ^# t+ q 来简单的防范Nginx的444状态比较特殊,如果返回444那么客户端将不会收到服务端返回的信息,就像是网站无法连接一样#禁止Scrapy等工具的抓取if ($http_user_agent~* (Scrapy|Curl|HttpClient))
( t3 i ]% S4 H, Z& T/ w& M" A {
- C ?* D) A: L* Q; Y! x return444;
8 b O3 O. ]5 D. F0 S0 l$ m }
8 O1 t3 e( z" D/ Z #禁止指定UA及UA为空的访问if ($http_user_agent~ "WinHttp|WebZIP|FetchURL|node-superagent|java/|FeedDemon|Jullo|JikeSpider|Indy 8 H' l1 Q, e4 H
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/ + N! X. V3 m' x9 {" y& Z
0.1|YandexBot|FlightDeckReports|Linguee Bot|^$" ) {5 l s+ N6 L2 |4 i6 A- u5 e
return 444;4 t& Y3 D# {4 s2 m; e- v- v( I& v& z6 j
}图片防盗链location /images/ {
7 V) a( S) N- l$ c/ l* _5 p
9 Q/ m W0 j6 h k2 z valid_referersnoneblocked www.host.com;" Q2 o& z3 C) G: k1 `9 j6 X* q; p
if ($invalid_referer) {9 M$ ?* o3 {) s
return403;
6 z* c/ V6 [( J }
& g5 M1 g% c( Z- ]: X( T- f5 K }valid_referers
! ?9 `6 Y6 ?2 T- Y* w : 验证referer,其中none允许referer为空,blocked允许不带协议的请求,除了以上两类外仅允许referer为 www.host.com 时访问images下的图片资源,否则返回403 " {# V7 B- T! f* n# |1 u
当然你也可以给不符合referer规则的请求重定向到一个默认的图片,比如下边这样location /images/ {
1 I; q1 P; F/ { valid_referersblocked www.host.com" Q/ t" u1 `' Z
if ( : {4 s7 o2 j0 ]' t0 W
$invalid_referer) {) C0 T, r6 ~9 O, W2 d
rewrite ^/images/.*.(gif|jpg|jpeg|png)$ /static/qrcode.jpg last;3 N0 R- q. t, D: L# V; B7 }
}6 o6 R4 ?5 {$ _; N! u
}限制并发及请求数 & O \9 t" t3 h& W- x
网站安全配置(Nginx)防止网站被CC攻击(包括使用了CDN加速之后的配置方法)Nginx 有 2 个模块用于控制访问“数量”和“速度”简单的说,控制你最多同时有 多少个访问,并且控制你每秒钟最多访问多少次, 你的同时并发访问不能太多,也不能太快,不然就“杀无赦”。
/ r+ \7 y! h% U! U HttpLimitZoneModule 限制同时并发访问的数量HttpLimitReqModule 限制访问数据,每秒内最多几个请求现在我们面对的最直接的问题就是, 经过这么多层加速,我怎么得到“最前面普通用户的 IP 地址”呢? " U& ?8 `9 F' x: K" \# [0 e
当一个 CDN 或者透明代理服务器把用户的请求转到后面服务器的时候,这个 CDN 服务器会在 Http 的头中加入 一个记录X-Forwarded-For : 用户IP, 代理服务器IPX-Forwarded-For : 用户IP, 代理服务器1-IP, 代理服务器2-IP, 代理服务器3-IP, …. " I- d) X3 {* y8 D0 L
可以看到经过好多层代理之后, 用户的真实IP 在第一个位置, 后面会跟一串 中间代理服务器的IP地址,从这里取到用户真实的IP地址,针对这个 IP 地址做限制就可以了,标准配置Nginx 里面设置一个限制,配置如下: $ ]" L3 f; s; G# C0 A7 |6 y
## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址最多有 50 个并发连接## 你想开 几千个连接 刷死我? 超过 50 个连接,直接返回 503 错误给你,根本不处理你的请求了
* p, I5 n) i: a; S3 U5 h0 H0 { limit_conn_zone$binary_remote_addr zone=TotalConnLimitZone:10m ;
6 @; Z' p" Z6 M0 [- v% L limit_conn TotalConnLimitZone 50;
( c2 k0 B( D. M; C0 v1 i8 ] 5 Y, T! W, ~, T9 O1 I
limit_conn_log_levelnotice;9 a J1 d* a) I( m
## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址每秒处理 10 个请求## 你想用程序每秒几百次的刷我,没戏,再快了就不处理了,直接返回 503 错误给你
. K/ t1 ^& G0 I9 A1 e limit_req_zone$binary_remote_addr zone=ConnLimitZone:10m rate=10r/s;
# k$ h5 N+ K4 o1 {) \ f& d limit_req_log_levelnotice;9 J8 c3 _! G5 U
## 具体服务器配置
4 u& _. w" I% g1 a server {4 C# J& I F: b% Q3 S# s: [9 P
listen80;$ r' S2 t: a0 i) b, m
location~ \.php$ {
6 k1 K# i! D/ W: x, o6 D& d # 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了
z `& m' G8 K9 i/ u* u$ W, v limit_req zone=ConnLimitZone burst=5 nodelay;
; f; r2 k# f, X' e, K5 t9 q# W fastcgi_pass127.0.0.1:9000;
# U. A5 B( M- d5 N; e fastcgi_index
- `! h: G/ }. F; I. m" E/ m7 U5 y index.php;
& u3 o/ H \& m5 ?# w4 C include fastcgi_params;6 c' t, s0 S4 y: ? y9 e# E
}' c5 D/ G* C W1 f- X/ F+ R
}这样一个最简单的服务器安全限制访问就完成了,这个基本上你 Google 一搜索能搜索到 90% 的网站都是这个例子,而且还强调用“$binary_remote_addr”可以节省内存之类的废话
. N) ^" {3 I% n+ i! t# ~4 I: y 经过多层CDN之后取得原始用户的IP地址Nginx 配置取得用户的原始地址map $http_x_forwarded_for $clientRealIp {
y; G# Q/ z! ?- i& O ## 没有通过代理,直接用 # k. z+ S* u# I6 C/ t3 d' k
; k) j# _" h O6 N- d/ E1 R
remote_addr "" $remote_addr;; |0 F# y5 O, Q
## 用正则匹配,从 x_forwarded_for 中取得用户的原始IP ## 例如 X-Forwarded-For: 202.123.123.11, 208.22.22.234, 192.168.2.100,...
/ Q+ E0 }, j4 q) @# i ## 这里第一个 202.123.123.11 是用户的真实 IP,后面其它都是经过的 CDN 服务器
) W/ d" |0 Z) G9 E) \5 n ~^(?P[0-9\.]+),?.*$ $firstAddr;
- d: c, {; ?9 _1 X$ j) L0 l }
+ h9 }2 A% w" u( r! I% V5 J . x/ q- q9 I4 K6 V! t1 a$ Y
## 通过 map 指令,我们为 nginx 创建了一个变量 $clientRealIp ,这个就是 原始用户的真实 IP 地址,## 不论用户是直接访问,还是通过一串 CDN 之后的访问,我们都能取得正确的原始IP地址 ; T; B: ^2 P( V. n8 L/ I6 b
根据用户的真实 IP 做连接限制下面是修改之后的 Nginx 配置:CDN环境下 Nginx 的安全配置Shell## 这里取得原始用户的IP地址map$http_x_forwarded_for $clientRealIp { . @' ]7 A5 r1 ]4 }
""$remote_addr; ~^(?P[0-9\.]+),?.*$ $firstAddr;}## 针对原始用户 IP 地址做限制limit_conn_zone$clientRealIp zone=TotalConnLimitZone:20m ; ' X7 I& v+ e3 n- m5 M) O, o
limit_connTotalConnLimitZone 50;limit_conn_log_levelnotice;## 针对原始用户 IP 地址做限制limit_req_zone$clientRealIp zone=ConnLimitZone:20m rate=10r/s;
! J- m$ P- I% D _; g8 [ #limit_req zone=ConnLimitZone burst=10 nodelay;limit_req_log_levelnotice;## 具体服务器配置server{ listen80;
* R+ b% F' i$ v& y) u8 d* g+ @ location~ \.php$ { ## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了 limit_req
) E$ Z$ x. Q7 B: c/ M* k+ ~ zone=ConnLimitZone burst=5 nodelay;}} 1 ~6 l/ b, B2 ], {
( M" X6 `( J% K
) C& ?( p e; j5 x) h4 n
! B$ D, R. U. y, ?7 J( g
+ v ?$ \9 e4 \* S7 ^& `$ q
|