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

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

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

使用道具 举报

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

使用道具 举报

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

    本版积分规则

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

    GMT+8, 2026-7-7 12:13 , Processed in 0.095729 second(s), 24 queries , Gzip On.

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

    Powered by Discuz! X3.5

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