找回密码
 加入怎通
查看: 189|回复: 4

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

[复制链接]
我来看看 发表于 2023-03-22 06:54:06 | 显示全部楼层 |阅读模式
( `* m$ ~; }% n p* @6 N* K

基础配置经常会有针对某个版本的nginx安全漏洞出现,隐藏nginx版本号就成了主要的安全优化手段之一,当然最重要的是及时升级修复漏洞http {, E" V0 x5 d. w1 i$ u* ]! c' l server_tokensoff;7 M$ t" P, D: k T/ | }Header头设置。

! H/ @3 M5 f) G8 E% \+ \/ J

在通常的请求响应中,浏览器会根据Content-Type来分辨响应的类型,但当响应类型未指定或错误指定时,浏览会尝试启用MIME-sniffing来猜测资源的响应类型,这是非常危险的X-Frame-Options。

e# B4 z7 v0 r$ D& D# y8 C

:响应头表示是否允许浏览器加载frame等属性,有三个配置DENY禁止任何网页被嵌入,SAMEORIGIN只允许本网站的嵌套,ALLOW-FROM允许指定地址的嵌套X-XSS-Protection:表示启用XSS过滤(禁用过滤为X-XSS-Protection: 0),mode=block表示若检查到XSS攻击则停止渲染页面

! b1 [; \2 x! H

X-Content-Type-Options:响应头用来指定浏览器对未指定或错误指定Content-Type资源真正类型的猜测行为,nosniff 表示不允许任何猜测例如一个.jpg的图片文件被恶意嵌入了可执行的js代码,在开启资源类型猜测的情况下,浏览器将执行嵌入的js代码,可能会有意想不到的后果

& a8 a5 [! t5 ~

add_header X-Frame-Options SAMEORIGIN;+ Q& `$ w: B. t* H& [ # 禁止嗅探文件类型add_header X-Content-Type-Options nosniff;add_header

) s: I! c# W! s/ [

X-XSS-Protection "1; mode=block"; 开启HSTS统一https访问add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"

1 x3 T2 g+ l- m; D& n- _

;账号认证server { 5 {8 r/ N0 s& D* A& E location / {. E3 k8 v8 U/ M) B, y auth_basic"please input user&passwd"; . W, V b* M, O# @/ T auth_basic_user_file

2 {7 t3 w* ]& P

key/auth.key;& U# S+ f2 X4 n8 |) w( l: N& v }5 _4 F9 T8 J$ x- n$ }% k }限制请求方法$request_method能够获取到请求nginx的method这里配置只允许GET/POST方法访问,其他的method返回405if ($request_method

9 ]6 g: J4 \, c, j4 |4 k; p

!~ ^(GET|POST)$ ) { % J( k3 i) N5 U, a! g return405;. ?8 b% \% U5 V" d }拒绝指定User-Agent可能有一些不法者会利用wget/curl等工具扫描我们的网站,我们可以通过禁止相应的user-agent

& h2 K* o% z' R8 q

来简单的防范Nginx的444状态比较特殊,如果返回444那么客户端将不会收到服务端返回的信息,就像是网站无法连接一样#禁止Scrapy等工具的抓取if ($http_user_agent~* (Scrapy|Curl|HttpClient))

0 _' S6 x; ~2 z. Z: n

{& J& e- k- \ x" w4 V3 _ return444; y4 i+ z. e0 Y, A9 g } ! G2 n6 Z$ l C4 Y #禁止指定UA及UA为空的访问if ($http_user_agent~ "WinHttp|WebZIP|FetchURL|node-superagent|java/|FeedDemon|Jullo|JikeSpider|Indy

/ ~3 u) d& h$ E8 a2 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/

9 |1 C) c% t" F% p6 V8 N# H

0.1|YandexBot|FlightDeckReports|Linguee Bot|^$" ) {' \; I# W' D; x" Q! |9 q return 444; ) k) X6 r- W2 s/ m [* d6 m, q* t }图片防盗链location /images/ { & D/ k3 a6 m% }' g

- C" i6 u9 p: I/ D5 V

valid_referersnoneblocked www.host.com;8 C" _2 \; ~2 |# H if ($invalid_referer) {' G$ V9 U* h+ T: G, a return403; ) `$ x+ o/ A% _/ e- R$ V }& t5 D9 n" N3 K$ R. v; E% N }valid_referers

( m/ V O7 R2 a. n! P& V' g

: 验证referer,其中none允许referer为空,blocked允许不带协议的请求,除了以上两类外仅允许referer为 www.host.com 时访问images下的图片资源,否则返回403

7 @1 _! A4 O& F/ ^! x

当然你也可以给不符合referer规则的请求重定向到一个默认的图片,比如下边这样location /images/ { ! K1 C8 y& p- e" k1 b* O valid_referersblocked www.host.com4 S, Z3 p5 @# P, ] if (

# ~0 ]) k9 {4 e. r: d5 e5 b

$invalid_referer) { 6 |; x G8 e9 p/ ?' @. h1 d rewrite ^/images/.*.(gif|jpg|jpeg|png)$ /static/qrcode.jpg last;' p: q" k5 t. F W3 k4 O } " t4 O4 D0 w, a' K x, z) { }限制并发及请求数

2 |8 H! {: A# v9 n8 `$ R$ ?# R* i

网站安全配置(Nginx)防止网站被CC攻击(包括使用了CDN加速之后的配置方法)Nginx 有 2 个模块用于控制访问“数量”和“速度”简单的说,控制你最多同时有 多少个访问,并且控制你每秒钟最多访问多少次, 你的同时并发访问不能太多,也不能太快,不然就“杀无赦”。

6 v6 R# Q. p" }5 T3 {

HttpLimitZoneModule 限制同时并发访问的数量HttpLimitReqModule 限制访问数据,每秒内最多几个请求现在我们面对的最直接的问题就是, 经过这么多层加速,我怎么得到“最前面普通用户的 IP 地址”呢?

X5 }5 v/ _! u* \! {; _" |

当一个 CDN 或者透明代理服务器把用户的请求转到后面服务器的时候,这个 CDN 服务器会在 Http 的头中加入 一个记录X-Forwarded-For : 用户IP, 代理服务器IPX-Forwarded-For : 用户IP, 代理服务器1-IP, 代理服务器2-IP, 代理服务器3-IP, ….

' ^7 E$ e& m! f7 Z k2 H! L. s

可以看到经过好多层代理之后, 用户的真实IP 在第一个位置, 后面会跟一串 中间代理服务器的IP地址,从这里取到用户真实的IP地址,针对这个 IP 地址做限制就可以了,标准配置Nginx 里面设置一个限制,配置如下:

3 X2 S+ m! h$ g4 t$ F

## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址最多有 50 个并发连接## 你想开 几千个连接 刷死我? 超过 50 个连接,直接返回 503 错误给你,根本不处理你的请求了

( a* Y! |, [* L% K# R

limit_conn_zone$binary_remote_addr zone=TotalConnLimitZone:10m ;; _% x S) u+ ^+ ?) l4 Y limit_conn TotalConnLimitZone 50; 5 S2 k5 F3 x" b- y' l" J( N( J# q

9 R. x' w1 o' @8 E

limit_conn_log_levelnotice; . C; z+ K# e5 I1 ]( ? ## 用户的 IP 地址 $binary_remote_addr 作为 Key,每个 IP 地址每秒处理 10 个请求## 你想用程序每秒几百次的刷我,没戏,再快了就不处理了,直接返回 503 错误给你

! j: a( T- c, b5 q- t7 Y

limit_req_zone$binary_remote_addr zone=ConnLimitZone:10m rate=10r/s; % b% C" w& G, D }4 _+ O limit_req_log_levelnotice;+ k0 U2 t+ e! e ## 具体服务器配置

0 n6 _8 K$ \9 n c% o/ y5 F& t

server {& c6 v9 `) b ^+ l4 F! e listen80;) w a% o1 _/ x( U7 X8 A& g location~ \.php$ { . _1 g. {3 q" e% [% c( w2 M # 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了

& V$ E: i- o; ]7 k$ }6 u

limit_req zone=ConnLimitZone burst=5 nodelay;1 Q" `$ ?5 p1 _: ^! A2 o' E fastcgi_pass127.0.0.1:9000; % B8 W# U n+ { fastcgi_index

: a* o& q* @3 P% d. m8 R( K; B

index.php; 9 } @: m1 e6 f+ @0 g2 u- T: L: n include fastcgi_params; 4 O% d3 Z# |7 m& J } n: P% V, ^) N }这样一个最简单的服务器安全限制访问就完成了,这个基本上你 Google 一搜索能搜索到 90% 的网站都是这个例子,而且还强调用“$binary_remote_addr”可以节省内存之类的废话

) p9 T- J ?# c: z5 _- J+ k

经过多层CDN之后取得原始用户的IP地址Nginx 配置取得用户的原始地址map $http_x_forwarded_for $clientRealIp { 0 T3 d' J3 d( G. X ## 没有通过代理,直接用

3 q. t) F3 ~0 m% P( \

% O/ N# S" s! `) a remote_addr "" $remote_addr;0 e; J& `( L8 e" P. b2 I/ Q/ f ## 用正则匹配,从 x_forwarded_for 中取得用户的原始IP ## 例如 X-Forwarded-For: 202.123.123.11, 208.22.22.234, 192.168.2.100,...

% y- t5 p* Y# T1 s# Q4 _

## 这里第一个 202.123.123.11 是用户的真实 IP,后面其它都是经过的 CDN 服务器 + q. Y! e% K( W& D- p ~^(?P[0-9\.]+),?.*$ $firstAddr; : D+ r' y7 M. @$ D } 4 k0 C6 T+ q( i. ^# B* ]

; `; m0 ]- n( M+ T

## 通过 map 指令,我们为 nginx 创建了一个变量 $clientRealIp ,这个就是 原始用户的真实 IP 地址,## 不论用户是直接访问,还是通过一串 CDN 之后的访问,我们都能取得正确的原始IP地址

" f3 N1 r% Y. U6 d5 F# X

根据用户的真实 IP 做连接限制下面是修改之后的 Nginx 配置:CDN环境下 Nginx 的安全配置Shell## 这里取得原始用户的IP地址map$http_x_forwarded_for $clientRealIp {

. R$ c8 W3 s! s- f' A) }2 w

""$remote_addr; ~^(?P[0-9\.]+),?.*$ $firstAddr;}## 针对原始用户 IP 地址做限制limit_conn_zone$clientRealIp zone=TotalConnLimitZone:20m ;

0 g" R2 |; g _& J x2 W$ P# y

limit_connTotalConnLimitZone 50;limit_conn_log_levelnotice;## 针对原始用户 IP 地址做限制limit_req_zone$clientRealIp zone=ConnLimitZone:20m rate=10r/s;

6 K" k# b, Q8 y

#limit_req zone=ConnLimitZone burst=10 nodelay;limit_req_log_levelnotice;## 具体服务器配置server{ listen80;

3 ]5 v" d i3 m& X

location~ \.php$ { ## 最多 5 个排队, 由于每秒处理 10 个请求 + 5个排队,你一秒最多发送 15 个请求过来,再多就直接返回 503 错误给你了 limit_req

0 A( S. H5 X- ?

zone=ConnLimitZone burst=5 nodelay;}}

, Z8 p) v3 ?! R: z 1 T6 @0 b( z( s( _% @ ) ^. F7 I* q3 f" `" j1 h6 u# G3 b7 x- ?, p" o* I5 B k' Q$ e$ ?2 V: V8 O

暂时无法加载帖子列表

回复

使用道具 举报

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

使用道具 举报

chen131029 发表于 2026-07-26 09:44:32 | 显示全部楼层
蹲了这么久,终于看到有价值的讨论,支持一下!
回复

使用道具 举报

za131717945 发表于 2026-08-30 12:25:49 | 显示全部楼层
这个思路很新颖,打开了新世界的大门,谢谢分享
回复

使用道具 举报

秒收录.卡母 发表于 2026-09-06 08:19:24 | 显示全部楼层
刚好遇到类似问题,看完这个帖子心里有底了
回复

使用道具 举报

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

    本版积分规则

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

    GMT+8, 2026-9-13 06:18 , Processed in 0.056678 second(s), 24 queries , Gzip On.

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

    Powered by Discuz! X3.5

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