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

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

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

使用道具 举报

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

使用道具 举报

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

    本版积分规则

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

    GMT+8, 2026-4-4 03:34 , Processed in 0.149537 second(s), 22 queries , Gzip On.

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

    Powered by Discuz! X3.5

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