nginx 反代了很多服务,域名在 cf 上托管这,可以用 cf 的 WAF 规则来屏蔽机器人或者限制国家地区的访问,以及可以限制 10 秒内访问次数( ratelimit )。
但是你的服务器还会开放 80/443 端口,看 nginx 的 access.log 日志发现仍然有一些爬虫去扫目录,基本上是扫你 .env 或者一些敏感数据,99% 的访问都是 404 ,因为没有这些文件。虽然不怕被扫,但还是有点担心万一哪天忽略了什么东西放进里面,很容易被扫到。
对于 ssh 可以用 fail2ban-client 这种工具防止登录,会拉黑(使用 iptables)失败登录的 ip 。
但 nginx 呢?判断 UA 么?但伪造浏览器 UA 太容易了,甚至发现有人扫 nginx 时候竟然使用 UA 打广告(类似于在你日志里留下 xxx 到此一游)。
1
dzdh 1 天前 https://www.cloudflare.com/zh-cn/ips/
https://api.cloudflare.com/client/v4/ips https://github.com/cevin/cloudflare-ip-sync nginx 只允许这些 ip 访问就行了。 还有一种类似 cf 的 5 秒盾 https://anubis.techaro.lol/docs/ git.kernel.org 都在用 |
2
pckillers 1 天前
改 80 443 默认端口为其他非常规端口+ ip 直接访问返回空页面 能挡掉大量机器人扫描。
如果还是不行就只能订阅 waf 的 ip 列表然后只给 waf 开白名单了 |
4
evill 1 天前 fail2ban-client 可以根据 nginx 日志拉黑
这是我的一些配置 # nginx-sensitive.conf [Definition] failregex = <HOST> -.*"(GET|POST).*\.env(\?|$) HTTP/.*" <HOST> -.*"(GET|POST).*/(_|\.)?env(\?|$) HTTP/.*" <HOST> -.*"(GET|POST).*/\.git/(HEAD|config|index|objects|info)[^ ]*(\?|$)? HTTP/.*" <HOST> -.*"(GET|POST).*/\.ht(access|passwd)(\?|$) HTTP/.*" <HOST> -.*"(GET|POST).*(config\.ya?ml|config\.json)(\?|$) HTTP/.*" <HOST> -.*"(GET|POST).*(composer\.(json|lock))(\?|$) HTTP/.*" <HOST> -.*"(GET|POST).*wp-config\.php(\?|$) HTTP/.*" <HOST> -.*"(GET|POST).*(database|dump)\.sql(\?|$) HTTP/.*" <HOST> -.*"(GET|POST).*(backup|db)\.(zip|tar|gz)(\?|$) HTTP/.*" <HOST> -.*"(GET|POST).*\.(bak|old|swp|~)(\?|$) HTTP/.*" # nginx-404.conf [Definition] failregex = ^<HOST> -.*"(GET|POST).*" 404 # nginx-404.conf [Definition] failregex = ^<HOST> -.*"(GET|POST).*" 404 ignoreregex =root@tx-beijing:/etc/fail2ban/filter.d# cat nginx-bad-request.conf # Fail2Ban filter to match bad requests to nginx [Definition] # The request often doesn't contain a method, only some encoded garbage # This will also match requests that are entirely empty failregex = ^<HOST> - \S+ \[\] "[^"]*" 400 datepattern = {^LN-BEG}%%ExY(?P<_sep>[-/.])%%m(?P=_sep)%%d[T ]%%H:%%M:%%S(?:[.,]%%f)?(?:\s*%%z)? ^[^\[]*\[({DATE}) {^LN-BEG} journalmatch = _SYSTEMD_UNIT=nginx.service + _COMM=nginx 基本规则就是访问敏感文件直接永封,连续 404 或 400 关 7 天 |
5
killva4624 1 天前
fail2ban 也可以用来拦截扫描异常 HTTP 路径访问的 IP ,是一个通用工具,不限于 SSH
|
6
spritecn 1 天前
我也有 1 楼的想法,既然走了 cf 就直接点
|
7
importmeta 1 天前
# . files
location ~ /\.(?!well-known) { deny all; } |
8
songco 1 天前 via Android
返回 zip 炸弹之内的可行吗?哈哈
|
10
WoneFrank 1 天前
不对外服务的可以加个 basic auth
|
11
julyclyde 1 天前
你已经用了 cdn 还用 iptables ?
|
12
benjaminliangcom 1 天前
有 CF WAF 也够了
|
13
ethusdt OP @benjaminliangcom 只能防域名爬虫,但防不了对 vps ip 直连的请求。
|
14
hero0earth 1 天前
过 2 周,我就把 WAF 开源了,相信能解决你的问题👍
|
15
studyingss 1 天前 1 楼的回复基本就是标准答案了,op 自动无视是有什么顾虑么
|
16
scegg 1 天前
既然用了 cf ,可以不要给 nginx 开 80/443 给公网了。用 cf tunnel 吧。
|
17
sslyxhz 1 天前
加一层 waf ,雷池, samwaf 之类的
|
18
anjing01 1 天前
梳理日志,用 ipset 过滤 ip 地址
|
19
ethusdt OP @studyingss 我找到方案了。用 1 楼给的 CF ip 列表(set_real_ip_from+X-Forwarded-For),然后搭配 fail2ban 规则(4 楼)。
|
21
abc0123xyz 1 天前
只允许 cf ip 和自己的 ip 访问。
其他 ip 直接断掉请求,啥都不返回。甚至可以用 cf 给的哪个 15 年证书。 |
22
abc0123xyz 1 天前
|
23
scegg 1 天前
@lizhenda 至少我用了一段时间还没遇到问题。
经验: ( 1 )由于 tunnel 直接负责连接了,所以本地 nginx 都不用 https 的边缘证书,直接走 http 就行。 ( 2 )如果你的服务端本身有 http 服务,那 nginx 都不用了。 ( 3 )如果用了 docker ,可以把 tunnel 也放在同一个网络内,直接在 cf 通过 container 的名字去访问服务就好。 |
24
malusama 1 天前 我遇到奇怪的爬虫是我挂了一大堆的 jav 直接暴露在公网我想让 115 同步过去, 然后 google 给我视频全部下了, 他一个搜索引擎下我视频文件干嘛? 他想索引啥。。你索引你收录地址得了,你下载干嘛
|
27
nvksie 1 天前 via iPhone
如果不想让别人访问,cf 用 tunnel 和 access 。
效果就是需要用邮箱验证码登陆才能访问,ssh 也可以走这个 access 从 web 登陆,vps 就可以 drop 所有公网入站 tcp 了,有问题从云厂商的串口或者预备一个 wireguard 隧道登陆救援 |
28
xyz5378 1 天前
@hero0earth 为什么不是今天
|
31
cj323 10 小时 21 分钟前
我是在云提供商上仅在本机( 0.0.0.0/32 )放行 443/22 ,然后通过高位端口的代理口后入本机。这样只有走后门才可以访问 443 。这样达到 L3 级别的隔离,绝对清净,access log ,last 不管什么时候看都只有自己(别人能进那就真后门了哈哈)。
|
32
Explr 7 小时 50 分钟前 via Android
cf 回源可以带客户端证书,在 nginx 上配置双向 TLS 认证,只允许 cf 回源就好了
|
33
lemonda 3 小时 49 分钟前
Nginx 设置频率限制
超过限制 Fail2ban 把 IP 加入 Cloudflare IP list 对于 List 中的 IP ,Cloudflare 设定 Managed Challenge 过了半年多,我已经完全想不起来这套的缺陷在哪儿了,好像是不能动态加载白名单,有但是在一个小项目上工作良好我就没管了。 ``` # 1.1.1.1 测试版 #!/bin/bash IP=$1 TIME=$(date '+%Y-%m-%d %H:%M:%S') if [ "$IP" = "1.1.1.1" ]; then # 测试用数据 INFO='{ "ip": "1.1.1.1", "country_name": "Test Country", "asn": "AS13335", "org": "Test Organization" }' else INFO=$(curl -s "https://ipapi.co/$IP/json/") fi COUNTRY=$(echo $INFO | jq -r '.country_name') ORG=$(echo $INFO | jq -r '.org') ASN=$(echo $INFO | jq -r '.asn') # Log and mail separately { echo "$TIME | IP: $IP | Country: $COUNTRY | ASN: $ASN | Org: $ORG" >> /var/log/fail2ban-ip.log echo "IP: $IP has been banned at $TIME Country: $COUNTRY ASN: $ASN Organization: $ORG" | mail -s "IP Banned Alert" [email protected] } &> /dev/null # Output clean JSON for jq processing echo "{\"ip\":\"$IP\",\"time\":\"$TIME\",\"country\":\"$COUNTRY\",\"asn\":\"$ASN\",\"org\":\"$ORG\"}" # 创建 Fail2ban 动作配置文件 /etc/fail2ban/action.d/cloudflare-ip-list.conf [Definition] actionstart = actionstop = actioncheck = actionban = IP="<ip>"; \ INFO=$(/usr/local/bin/ip-info.sh <ip>); \ TIME=$(echo $INFO | jq -r '.time'); \ COUNTRY=$(echo $INFO | jq -r '.country'); \ ASN=$(echo $INFO | jq -r '.asn'); \ ORG=$(echo $INFO | jq -r '.org'); \ curl -X POST "https://api.cloudflare.com/client/v4/accounts/<your_account_id>/rules/lists/<your_list_id>/items" \ -H "Authorization: Bearer <your_api_token>" \ -H "Content-Type: application/json" \ --data "[{\"ip\": \"$IP\", \"comment\": \"Banned at $TIME | Country: $COUNTRY | ASN: $ASN | Org: $ORG\"}]" # 移除 actionunban ,这样 IP 就不会被自动解封 actionunban = IP="<ip>"; \ ITEM_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/<your_account_id>/rules/lists/<your_list_id>/items" \ -H "Authorization: Bearer <your_api_token>" \ -H "Content-Type: application/json" | jq -r --arg IP "$IP" '.result[] | select(.ip == $IP) | .id'); \ if [ ! -z "$ITEM_ID" ]; then \ curl -X DELETE "https://api.cloudflare.com/client/v4/accounts/<your_account_id>/rules/lists/<your_list_id>/items" \ -H "Authorization: Bearer <your_api_token>" \ -H "Content-Type: application/json" \ --data "{\"items\":[{\"id\":\"$ITEM_ID\"}]}"; \ fi [Init] ``` |
34
hero0earth 3 小时 28 分钟前
@xyz5378 那是因为还没有开源版,今天剥离出来一个版本 https://github.com/Flmelody/open-website-defender.git 😂
|