找回密码
 加入怎通
查看: 141|回复: 1

Nginx 防攻击安全配置方案(nginx防dos)

[复制链接]
我来看看 发表于 2023-03-22 06:54:06 | 显示全部楼层 |阅读模式
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
回复

使用道具 举报

coffee 发表于 2026-03-16 03:54:43 | 显示全部楼层
说得很实在,没有夸大其词,这种真实分享太难得了
回复 支持 反对

使用道具 举报

    您需要登录后才可以回帖 登录 | 加入怎通

    本版积分规则

    QQ|手机版|小黑屋|网站地图|真牛社区 ( 苏ICP备2023040716号-2 )

    GMT+8, 2026-5-15 05:14 , Processed in 0.027632 second(s), 23 queries , Gzip On.

    免责声明:本站信息来自互联网,本站不对其内容真实性负责,如有侵权等情况请联系420897364#qq.com(把#换成@)删除。

    Powered by Discuz! X3.5

    快速回复 返回顶部 返回列表