阅读视图

发现新文章,点击刷新页面。
🔲 ⭐

把 Cloudflare WARP 转换为 http 代理

这篇文章在 2025年05月27日17:43:28 更新了哦~

Cloduflare WARP真的非常好用,并且支持代理模式。启用这个模式之后,它会在本机监听一个socks端口,应用程序可以配置到这个端口来使用代理。

对于服务器来说,一般使用 warp-cli

warp-cli proxy port 60606
warp-cli mode proxy

之后你就可以 curl

https_proxy=socks5://127.0.0.1:60606 http_proxy=socks5://127.0.0.1:60606 curl ipv4.win
IP: 104.28.157.116 CLOUDFLARE.COM CLOUDFLARE.COM

然而,Go的程序不支持 socks 代理,要手动加transport我可没那个功夫去加。

好消息是,Go默认是尊重环境变量http_proxy的。那么就要想办法给socks代理转换为http代理

这事很简单嘛!用pproxy就好了,别的不会,这个肯定很会!

pproxy -v -l http://127.0.0.1:8118 -r socks5://127.0.0.1:60606

https_proxy=http://127.0.0.1:8118 http_proxy=http://127.0.0.1:8118 curl ipv4.win
curl: (52) Empty reply from server

# pproxy logs
Serving on ipv? 127.0.0.1:8118 by http
http 127.0.0.1:45012 -> socks5 127.0.0.1:60606 -> ipv4.win:80
Unknown remote protocol from 127.0.0.1

把 Cloudflare WARP 转换为 http 代理

怎么报错了呢🤨

可能是 pproxy的问题,那么用gost

gost -L http://127.0.0.1:8118 -F socks5://127.0.0.1:60606
2024/11/03 12:32:43 route.go:700: http://127.0.0.1:8118 on 127.0.0.1:8118
2024/11/03 12:32:46 http.go:162: [http] 127.0.0.1:33284 -> http://127.0.0.1:8118 -> ipv4.win:80
2024/11/03 12:32:46 http.go:257: [route] 127.0.0.1:33284 -> http://127.0.0.1:8118 -> 1@socks5://127.0.0.1:60606 -> ipv4.win:80
2024/11/03 12:32:46 http.go:280: [http] 127.0.0.1:33284 -> 127.0.0.1:8118 : unexpected EOF

把 Cloudflare WARP 转换为 http 代理

那……Privoxy

forward-socks5 / 127.0.0.1:60606 .

也不行!

甚至直接在 Firefox里设置socks5代理,也不行🤨

把 Cloudflare WARP 转换为 http 代理

任何网站都打不开

把 Cloudflare WARP 转换为 http 代理

偶然取消 DNS请求的勾选,就成功了……突然恍然大悟,WARP可能不支持远程解析DNS

 

那么要么用回 socks4

pproxy -v -l http://127.0.0.1:8118 -r socks4://127.0.0.1:60606
gost -L http://127.0.0.1:8118 -F socks4://127.0.0.1:60606

要么给加上DNS的支持

gost -L "http://127.0.0.1:8118?dns=1.1.1.1" -F socks5://127.0.0.1:60606

人生中宝贵的几个小时就这么没了。

 

需要注意:warp-cli的proxy mode 不支持超过10秒的连接

Proxy mode has a timeout limit of 10 seconds for requests. If a request goes above the 10 second limit, Cloudflare will drop the connection.

遇到这种情况,要么不用proxy mode, 要么在 gost或pproxy那边绕过,如

gost -L http://127.0.0.1:8118 -F socks4://127.0.0.1:60606?bypass=api.openai.com

文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/warp-http-proxy.html
🔲 ⭐

使用 Cloudflare Worker获取图片元数据

这篇文章在 2024年10月05日23:31:04 更新了哦~

WebP Cloud 提供一个接口,可以用于获取图片的元数据,比如长宽、大小、色彩空间以及blurhash。这部分计算,尤其是blurhash其实还是略有压力的,我们就想能不能把这部分功能放到回源请求上。

对于 Azure Function来说,这必然不是问题,因为他几乎就是一个完整的NodeJS环境,可以用sharp的;但是对于Workers,由于他是V8,只支持NodeJS最基本的一些API,最多带上Wasm,这样用sharp就变成了几乎不可能的事情,因为要调用libvips。

最终经过了我的艰苦探索,发现一个名为 @cf-wasm/photon 的库,可以用来获取图片基础信息。首先需要 import

import { PhotonImage, SamplingFilter, resize } from '@cf-wasm/photon';

用起来也还行,首先我们需要通过 fetch获取图片,得到一个response,可以从这里拿到 ArrayBuffer

const response = await fetch(url)
const buffer = await response.arrayBuffer();

然后PhotonImage 需要Uint8Array,那先转换一下

const inputBytes = new Uint8Array(buffer);

然后加载图片

const inputImage = PhotonImage.new_from_byteslice(inputBytes);

宽高可以用 inputImage.get_width()inputImage.get_height()

色彩空间可以用 inputImage.get_image_data().colorSpace

文件大小直接 buffer.length就行

计算 blurhash建议先调整图片大小,毕竟 Worker有执行时间限制

const resized = resize(inputImage, 32, 32, SamplingFilter.Nearest);

然后计算

const blur = encode(resized.get_raw_pixels(), resized.get_width(), resized.get_height(), 4, 4);

至于图片格式,那只能靠magic header了,比如使用如下ChatGPT给我的神奇代码

function getImageFormatFromArrayBuffer(arrayBuffer) {
	const uint8Array = new Uint8Array(arrayBuffer);

	// Check for PNG (first 8 bytes: 89 50 4E 47 0D 0A 1A 0A)
	if (
		uint8Array[0] === 0x89 &&
		uint8Array[1] === 0x50 &&
		uint8Array[2] === 0x4e &&
		uint8Array[3] === 0x47 &&
		uint8Array[4] === 0x0d &&
		uint8Array[5] === 0x0a &&
		uint8Array[6] === 0x1a &&
		uint8Array[7] === 0x0a
	) {
		return 'png';
	}

	// Check for JPEG (first 3 bytes: FF D8 FF)
	if (uint8Array[0] === 0xff && uint8Array[1] === 0xd8 && uint8Array[2] === 0xff) {
		return 'jpeg';
	}

	// Check for GIF (first 6 bytes: GIF87a or GIF89a)
	if (
		uint8Array[0] === 0x47 &&
		uint8Array[1] === 0x49 &&
		uint8Array[2] === 0x46 &&
		uint8Array[3] === 0x38 &&
		(uint8Array[4] === 0x37 || uint8Array[4] === 0x39) &&
		uint8Array[5] === 0x61
	) {
		return 'gif';
	}

	// Check for BMP (first 2 bytes: 42 4D)
	if (uint8Array[0] === 0x42 && uint8Array[1] === 0x4d) {
		return 'bmp';
	}

	// Check for WebP (first 4 bytes: 52 49 46 46 and "WEBP" in bytes 8-11)
	if (
		uint8Array[0] === 0x52 &&
		uint8Array[1] === 0x49 &&
		uint8Array[2] === 0x46 &&
		uint8Array[3] === 0x46 &&
		uint8Array[8] === 0x57 &&
		uint8Array[9] === 0x45 &&
		uint8Array[10] === 0x42 &&
		uint8Array[11] === 0x50
	) {
		return 'webp';
	}

	return 'Unknown format';
}

部署

npm install @cf-wasm/photon
npm install blurhash
wrangler deploy 

就可以了。wrangler会自动打包,把依赖和wasm也一起上传上去

Azure Function

如果你使用的是Azure Function,那么事情就简单多了,直接安装并使用 sharp 就行。需要注意的一点是,Azure Function可以选择运行的环境是Linux还是Windows。所以本地也要安装好正确的sharp然后才可以部署。

npm install --cpu=x64 --os=linux sharp

详情可以参考Cross-platform

最终结果

需要注意 Workers 有内存限制,小心图片太大直接报错

原来是打算把 Worker和Function 用同一套代码库的,但是由于 Worker的限制,即使不同情况下使用不同的import,Worker还是没法兼容 Function🫠

所以只能分开两个分支了。

使用 Cloudflare Worker获取图片元数据

Cloudflare Workers 太弱智了,害我失去了人生中宝贵的三个小时使用 Cloudflare Worker获取图片元数据


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/worker-image-metadata.html
🔲 ⭐

使用 InfluxDB 存储QPS数据

我跑了,换到clickhouse存了,性能更好,详见 https://dmesg.app/one-api-clickhouse.html

一个月之前做了一个 Open AI的接口站,用 locust 压力测试了一下,发现在 1C 2G 的 Hetzner Cloud 上,QPS 只能有大概20左右的样子

使用 InfluxDB 存储QPS数据

后来花了一晚上时间,一边看电视一边优化,成功把 QPS 提升到了几百,短期内应该足够用了。

在做完这个优化之后,我就一直在想那么我在正常情况下遇到的 QPS 究竟有多少?

我的应用 one-api 是用 Go 写的,是 Gin,那应该只有这几个问题:

  1. 何时加入 QPS 计算代码:通过中间件就可以了
  2. 何时写入数据库,攒够一定数量批量写入为最佳
  3. Grafana 展示数据

写入数据到 InfluxDB

写入数据很简单,我用的是 InfluxDB 1.8 所以也要使用旧版本的库,也不需要 tag 所以 nil 即可

import "github.com/influxdata/influxdb/client/v2"
 
func writeInflux() {
    c, _ := client.NewHTTPClient(client.HTTPConfig{
       Addr:     "https://host",
       Username: "user",
       Password: "pass",
    })

    bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
       Database:  "burn",
       Precision: "ns",
    })

    fields := map[string]interface{}{"value": 1}
    pt, _ := client.NewPoint("qps", nil, fields, time.Now())
    bp.AddPoint(pt)

    _ = c.Write(bp)
    _ = c.Close()
}

但是每个请求都写一次这个成本太高了。不如攒够几百个一起写,这样最经济,节约IO嘛。

展示数据

这部分就非常简单了。这样就可以查询 QPM

SELECT COUNT(value) FROM "qps" GROUP BY time(1m)

QPS是这样的

SELECT COUNT(value) FROM "qps" GROUP BY time(1s)

那么现在问题只剩下三个了,定时器、积攒数据、消费数据。消息队列之类的办法当然可以,但是可能有点小题大做了。

定时器

一种办法是用 time.NewTicker

func QPSTicker() {
    logger.SysLog("Starting QPS ticker...")
    var ticker = time.NewTicker(time.Second * 10)
    for {
       select {
       case <-ticker.C:
          writeInflux()
       }
    }
}

另外一种就是很传统的开一个死循环,然后在循环里 sleep 非常简单

func SleepTicker() {
    for {
       time.Sleep(10 * time.Minute)
       // do something
    }
}

在启动web服务器之前 go QPSTicker 即可

收集方法1:追加时间戳到 slice 中

var DataPoints []time.Time

var mutex = sync.Mutex{}

func QPS() func(c *gin.Context) {
    return func(c *gin.Context) {
       mutex.Lock()
       config.DataPoints = append(config.DataPoints, time.Now())
       mutex.Unlock()
       c.Next()
    }
}

需要注意的是,由于我们可能会在竞争状态下写数据,所以要用一个互斥锁

消费数据

func writeInflux() {
    const batchSize = 500
    if len(config.DataPoints) < batchSize {
       return
    }
    //....
    for _, v := range config.DataPoints[:batchSize] {
       pt, _ := client.NewPoint("qps", nil, fields, v)
       bp.AddPoint(pt)
    }
    // ....
    config.DataPoints = config.DataPoints[batchSize:]
}

收集方法2: channel

方法1确实简单,但是需要互斥锁,而且处理完还需要改变数据,可能内存消耗会比较大。如果能用channel 那么就更好了。也很简单!

var DataPoints = make(chan time.Time, 1000)

在中间件中,使用非阻塞的 select 去给channel里送数据

func QPS() func(c *gin.Context) {
    return func(c *gin.Context) {
       select {
       case config.DataPoints <- time.Now():

       default:
          logger.SysError("Channel is full!!!")
       }
       c.Next()
    }
}

如果直接

config.DataPoints <- time.Now()
c.Next()

那么channel满了整个服务也就卡住了,因此要用 select,丢数据总比卡住强

消费数据

也没啥差别,就是循环不一样,并且不用考虑修改数据

for i := 0; i < batchSize; i++ {
    v := <-config.DataPoints
    pt, _ := client.NewPoint("qps", nil, fields, v)
    bp.AddPoint(pt)
}

最终结果


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/influxdb-qps.html
🔲 ⭐

Stripe 如何安全收款并避免盗刷与测卡

警告⚠️
在大多数国家和地区,盗刷信用卡都是犯罪行为,数额巨大甚至是重罪。请不要以身试法

使用Stripe进行收款是一件非常简单的事情,用起来非常舒适,不想写代码就无代码,会写代码还想自己设计前后端可以用 Stripe Elements。

当你把事情做好了,把你的在线服务上线了,这个时候就一定要考虑一个问题:盗刷与测卡(卡号测试、银行卡测试)。

盗刷很好理解,用偷来的信用卡资料去你的网站上购物;测卡则是用小额交易或者其他方式来确定盗窃来的信用卡是可用的,然后后续再大额诈骗中使用这些信用卡。

毫无疑问,只要是在线电子商务,就一定无法避免盗刷与测卡的。

一个非常重要的事情是,商户、卡组织与Stripe都有责任与义务阻止盗刷和测卡。

也许有人不理解,为什么商户也有责任与义务阻止盗刷和测卡?我就是把 Stripe 的一个Payment Link放到了网上,某个不怀好意的人看到了去盗刷,主动给我送钱,我为什么要负责?

切勿贪小便宜!真正的持卡人发现了异常的付款记录,他们会去找发卡行争议,发卡行就会找到 Stripe,商户就需要应对争议,这期间不仅要承担争议费,在争议比例过高时Stripe还会封号、甚至罚款。

Stripe 如何安全收款并避免盗刷与测卡

所以,遇到来源不明的欺诈付款,一定要全额退款,可不能贪小便宜。

不过如果对方是用支付宝、微信付款的那就不用管了,因为这俩应该是不支持争议的😂


前不久,我“惹毛”了一个黑产论坛。这个黑产论坛的人就开始盗刷+测卡。

Stripe 如何安全收款并避免盗刷与测卡

比如这种,人在新加坡用墨西哥的卡🤨,再考虑到我的用户的大部分都是中国人,所以看起来怎么都很像盗刷。

后来他们盗刷不成还恼羞成怒开始DoS我了,峰值竟然有5500万。

至于我是怎么“惹毛”这群人的,以后也许可以写一篇来说说这件事,我觉得这其中的乐趣会比听相声还搞笑🤣,不笑我倒贴你100块。如果你还是想先了解一下,那么看这个Twitter就够了


本文的主题是,已经使用了Stripe,如何防患于未然,避免盗刷与测卡?假如在遭遇盗刷,需要立刻做什么事情?

Radar

Stripe Radar 是Stripe提供的一个反欺诈工具,基于强大的机器学习实现,并且可以自定义许多规则。比如ChatGPT不允许中国的卡付款,类似这样的规则,就可以Radar的规则实现。

Radar不收月费,而是从每笔交易里抽成,Stripe还是很良心而且很会赚钱的。

在遭遇盗刷的时候,立刻要做的事情就是开启 Radar,并且根据自己的情况调整灵敏度。同时,审核所有已经通过的付款,如果怀疑是盗刷的,要立刻全额退款,全额退款无法争议。在处理完之后,联系 Stripe客户表明自己的情况,要求他们提供协助和建议。

以新加坡为例,Radar风控团队版每笔交易 0.1新币,机器学习版每笔0.08新币。强烈建议开启团队版。

开启了Radar之后,我们可以在 Risk Control里调整Radar的灵敏度

Stripe 如何安全收款并避免盗刷与测卡

根据自己的情况调整即可,比如我在面临大量盗刷的时候,把灵敏度调到了50,意味着所有风险分数高于50的付款都会被拒绝。

3DS

在某些地方,你可能会看到 Stripe 2D 的说法。这里的2D指的是在线刷卡的时候只要输入卡号、有效期、CVV并且无需进行身份验证(通常是短信或者App推送)。对应的需要验证的则是3DS

在开启了 Radar之后,就可以强制开启3DS了,这样对于盗刷的情况基本可以拦截一大部分,毕竟他们没有卡主的手机。

Radar – Rules- Authenticate Rules,三个默认的3DS规则全部打开

Stripe 如何安全收款并避免盗刷与测卡

自定义阻止规则

每个人的业务都不同,比如我的这个业务下,美国人不太可能来用,更别提那些非常小众东南亚、加勒比海和非洲国家了。因此对于我来说,我只要允许中国、最多再包含港澳台的银行卡就可以了。

那么我们就可以添加一个这样的自定义阻止规则,表达式这么写,NOT要写最前面而不是写IN之前

NOT (:card_country: IN ('CN','HK','MO','TW'))

不想接受预付费卡,那么可以这样写

:card_funding: = 'prepaid'

只想接受中港澳台,允许任何国家的Apple Pay、Google Pay(这俩安全系数很高,不太可能是盗刷),那就这么写

Block if NOT (:card_country: IN ('CN','HK','MO','TW')) AND NOT(:digital_wallet: IN ('android_pay','apple_pay'))

3DS通过就接受,无所谓发卡国,可以这么写

NOT :is_3d_secure_authenticated:

某人在某黑产论坛:真不敢c cn的卡

在Stripe平台上,我们能做的事情差不多只有这么多了。为了防止测卡,我们还需要在自己的集成方式上下点功夫。

测卡的方式

测卡一般分两种,一种是授权,类似你在某些网站如Cloudflare绑定你的信用卡,并不会真正的扣款,App上一般能看到记录,但是每月账单上未必会有;另外一种则是付款,一般是小额付款,确认卡片有效准备来波大的。

Stripe 如何安全收款并避免盗刷与测卡

检测测卡

首先当然是要检测到测卡。显著增加的拒绝交易其实就可以用来识别测卡。

  • 尝试查看付款详情的时候,能看到Stripe会自动屏蔽测卡,如上面的这张截图
  • Developers的overview页面图表能发现很多失败

Stripe 如何安全收款并避免盗刷与测卡

  • 在 Developers – Logs 里查找402,也会发现大量记录

在发现被搞了之后,我们要赶紧采取措施。哪怕赶紧找到测卡的人的IP给屏蔽了也是办法。当然坏人没那么笨,简单的防火墙规则未必会管用的。

保护 API Key

Stripe的API Key分为两种,一种是Publishable Key可以公开的;另一种是Secret Key,有这个Key就可以访问Stripe的系统和全球金融网络,所以万万不能泄漏

遇到测卡建议无论是否泄漏 secret key,都去吊销生成一个新的,并且添加IP访问白名单

Stripe 如何安全收款并避免盗刷与测卡

优化集成方式

使用 Stripe有很多集成方式,使用 Stripe Payment Link、Stripe Checkout、Stripe Elements是推荐的方式

Stripe 如何安全收款并避免盗刷与测卡

用这种集成方式, Radar能够自动捕获到更多的信息,更容易判断盗刷测卡。

其他的方式可能就需要自己手动提供信息了。

添加captcha

在请求创建 PaymentIntent之前可以加上一个验证码,比如 Cloudflare的turnstile就是非常好的选择。 这样对于大部分的垃圾请求都可以过滤了。

需要注意,turnstile是需要客户端+服务端实现的。只有客户端是不完整的。

频率限制

一般来说,单个IP创建 PaymentIntent 不应该太频繁,可以加上频率限制降低被刷概率。

登录会话

登录了才能购买,类似这种可以降低被刷成本

自定义规则

根据自己的业务情况,使用不同的规则来屏蔽测卡。甚至还可以根据IP地理位置和发卡国组合,就看想象力了

战果

这是屏蔽的付款,看这个时间这么接近,人在美国用着泰国、甚至一些奇怪的小国家的卡,风险系数非常高

Stripe 如何安全收款并避免盗刷与测卡

大概拦截了3000欧,恐怖啊😂 最开始规则配置的不太正确,估计误杀了一部分

Stripe 如何安全收款并避免盗刷与测卡

总结

  1. Stripe的文档还是挺不错的,SDK用起来也非常舒服。无论是stripe.js还是python bindings,写满了 type annotations,想用错都难
  2. Stripe的客服也很专业,响应非常迅速
  3. 坏人太多啦

文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/stripe-fraud.html
☑️ ⭐

隐藏于 Cloudflare 的全球网络之中

做一个网站是很简单的事情。买一个域名,买一个服务器,A记录解析过去就好了。

这样做其实有一个非常大的安全隐患,不怀好意的人可以拿到你的服务器的IP,然后就可以做很多坏事,比如 (D)DoS、暴力破解SSH之类的。

一个很简单的办法,就是用 Cloudflare之类的CDN,这样可以隐藏源站IP。这样他们无法直接攻击你的服务器,只能疯狂打 Cloudflare。


就像我前不久一样,遭遇了人生中第一次DoS,峰值大概有5500万请求的样子,基本上都被Cloudflare的规则拦住了。

隐藏于 Cloudflare 的全球网络之中

有趣的是,攻击来自于 AS4983 ,归属于 Intel。我猜更有可能和Intel® Developer Cloud有关,而不是Intel的内部网络被黑或者员工做坏事。

然而即使使用了 Cloudflare也并不是100%安全。如果使用方式不正确,也有可能暴露源站IP的。如果被抓到了源站IP,那么坏人就可以疯狂给这个IP发起请求,你的Cloudflare规则配置的再好都没有用。


泄漏源站IP的方式

网络空间测绘

有一些安全公司,如censys、shodan之类的。他们会扫描整个IPv4的地址,然后尝试连接各种常用端口来确定这个IP上都跑了什么服务。

比如说我随便输入一个域名,即使这个域名在Cloudflare之后,也可能看到相关的结果

隐藏于 Cloudflare 的全球网络之中

点进去,通过证书信息就能确认,这个IP大概率是这个网站的,那还不快打?

钓鱼泄漏

利用目标网站的功能来执行服务器端请求。例如,如果一个网站允许用户输入一个 URL 来获取该 URL 的内容(如网页抓取或 URL 预览功能),可以提供一个由自己控制的 URL。

比如 WebP Cloud Services吧,这个服务是做网站图片加速的,那么自然要去用户给的地址去获取图片,这样IP也就会被泄露啦。当然了聪明如 Nova Kowk怎么会让这种事情发生?

其他泄漏方式

子域名

有一些程序可以通过常用的词语来暴力猜测子域名,有可能配置的时候不小心忘记点亮小云朵,或者自己持有的其他域名解析不小心忘记打码,那么就暴露了。

历史DNS记录

有些网站提供历史DNS记录,有概率找到

邮件MX记录

如果自建邮件服务器,那么是肯定会暴露IP了。

Cloudflare信息泄露或者内部作案

这个概率应该很低。


隐藏IP的方式

屏蔽censys并不完美

网上一搜censys 你就会发现有很多种办法,说根据UA屏蔽啦,根据IP屏蔽啦等等。

这种做法治标不治本的。今天屏蔽了censys,明天还有densys,甚至简单写个代码,花最多几百G的流量扫一遍全球的IPv4地址也没什么难度。

只允许 Cloudflare的访问很麻烦

Cloudflare公开了他们的IP地址,因此一种办法是把他们的全部IP地址加入白名单中,然后其他所有的IP地址的请求全部拒绝。

这是一种切实可行的办法,然而有如下缺点:

  1. 需要跟踪 Cloudflare IP变化
  2. 需要配置繁琐的iptables、nginx或者WAF等规则,配置起来会比较麻烦
  3. 80和443的规则都要配一遍
  4. 费心费时费力
  5. 一不小心手抖配置错了可能自己都没法SSH
  6. 如果你用docker,还会发现docker能给你的iptables开个洞 🤦

Cloudflare Argo Tunnel是未来

Argo Tunnel会在你的服务器和Cloudflare 之间创建一个加密的安全隧道,然后这个隧道可以用来承载很多不同种类型的流量,比如 http,tcp,ssh,smb,rdp,甚至是 unix 套接字都可以

你的机器没有公网IP都没关系的,只要你的服务器能够连接到Cloudflare的网络就可以。用起来很简单,甚至都不用学习奇奇怪怪的命令。

去 Cloudflare Zero Trust – Networks – Tunnel 创建 Tunnel,服务器安装 cloudflared,然后添加 Public hostname就可以了

隐藏于 Cloudflare 的全球网络之中

你的应用程序甚至只用监听在 localhost而不是0.0.0.0,也就是说你的服务器只开一个SSH就够了

隐藏SSH

更进一步,我们可以连SSH都隐藏起来。在public hostname那里创建一个域名,如果担心子域名被扫到,那就起个随机的子域名

协议选择 SSH,URL选择 127.0.0.1:22

然后在你的电脑上运行 cloudflared建立隧道

cloudflared access ssh --hostname something.dmesg.app --url 127.0.0.1:10022
# 接到你的服务器
ssh root@127.0.0.1 -p 10022 

之后去厂商的WAF里,比如 Azure是这样的,入网全部拒绝

隐藏于 Cloudflare 的全球网络之中

Vultr是这样的,随便添加一个dummy 入网规则

隐藏于 Cloudflare 的全球网络之中

这样你的IP在其他人看来完全是黑洞,ping不通,什么端口都没开,就像没被使用一样,只有 Cloudflare知道背后的真相。

隐藏应用程序向外发起的请求

如果你的应用程序会向外发请求,而这个外部是可以被用户自定义的,那么就存在被钓鱼的情况。即使你配置的再好,那么也会被抓到IP。

这种情况下,要做的事情自然是全方面审查代码,如果遇到会被钓鱼的地方,那么需要让流量走代理。

至于走什么代理,一种方式是走商业VPN,比如Surfshark之类的,通过wireguard转socks5;另一种方式是走 Cloudflare WARP,WARP可以运行在 proxy mode而不是接管全局流量

warp-cli register
# warp 监听本地的11111端口
warp-cli set-proxy-port 11111

# warp proxy mode
warp-cli set-mode proxy

# 永久开启
warp-cli enable-always-on

对于Go的应用,这样就可以了

https_proxy=socks5://127.0.0.1:11111 http_proxy=socks5://127.0.0.1:11111 go run main.go

还有一种方式是使用 Cloudflare Workers,请求由Workers转发,代码很简单

export default {
  async fetch(request: Request): Promise {
    /**
     * Replace `remote` with the host you wish to send requests to
     */
    const remote = "https://example.com";

    return await fetch(remote, request);
  },
};

更具体的使用方式可以看下面的参考阅读

总结

哎这个世界上坏人真的太多了,但是 Cloudflare 真的帮助了我很多,更重要的是这一切还都是免费的!

不得不感慨,「At Cloudflare, we have our eyes set on an ambitious goal — to help build a better Internet.」,真的不仅仅是一句口号。

—— Nova Kowk

参考阅读

 


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/hide-in-cf.html
🔲 ⭐

救命!我的 Azure Front Door WAF 规则不生效怎么办!

这篇文章在 2024年09月27日21:17:41 更新了哦~

最近在用 Front Door加速网站访问,想添加一个这样的规则:只允许 /v1下的路径和特定国家的IP,其他全部禁止。

这其实很简单的!只要创建两条 WAF规则,一个禁止全部优先级低,一个允许特定路径,优先级高。

100优先级的允许规则

救命!我的 Azure Front Door WAF 规则不生效怎么办!

看起来一点问题都没有吧,非常简单容易理解

500 优先级阻止规则

救命!我的 Azure Front Door WAF 规则不生效怎么办!

也很好理解,阻止全部

没用!

配置下来就是不生效,所有的请求都被阻止了。给阻止规则停用,就全部能访问。

azure-cli里看下WAF的配置,避免他们前端有bug

{
    "rules": [
        {
            "action": "Allow",
            "enabledState": "Enabled",
            "groupBy": [],
            "matchConditions": [
                {
                    "matchValue": [
                        "/v1"
                    ],
                    "matchVariable": "RequestUri",
                    "negateCondition": false,
                    "operator": "BeginsWith",
                    "transforms": []
                },
                {
                    "matchValue": [
                        "CN"
                    ],
                    "matchVariable": "SocketAddr",
                    "negateCondition": false,
                    "operator": "GeoMatch",
                    "transforms": []
                }
            ],
            "name": "Allow",
            "priority": 100,
            "rateLimitDurationInMinutes": 1,
            "rateLimitThreshold": 100,
            "ruleType": "MatchRule"
        },
        {
            "action": "Block",
            "enabledState": "Enabled",
            "groupBy": [],
            "matchConditions": [
                {
                    "matchValue": [],
                    "matchVariable": "RequestUri",
                    "negateCondition": false,
                    "operator": "Any",
                    "transforms": []
                }
            ],
            "name": "Deny",
            "priority": 500,
            "rateLimitDurationInMinutes": 1,
            "rateLimitThreshold": 100,
            "ruleType": "MatchRule"
        }
    ]
}

从结果来看,完全没问题。给规则从 begins with 改成 contains又可以,但是那也意味着https://cn-test.burn.hair/login?id=v1也会允许,而这不太行

救命!我的 Azure Front Door WAF 规则不生效怎么办!

看看 log

没办法了,开 log 试试看吧,不行就联系 Azure Support

先要去 Log Analytics workspaces 里开一个记录日志的奇怪的东西

救命!我的 Azure Front Door WAF 规则不生效怎么办!

然后去 Diagnostic settings 里 把这个东西和 Front Door、Workspaces关联起来

救命!我的 Azure Front Door WAF 规则不生效怎么办!

然后去log页面运行这样的一个查询,绝了连看日志都得学习查询语法😓

AzureDiagnostics
| where ResourceProvider == "MICROSOFT.NETWORK" and Category == "FrontdoorWebApplicationFirewallLog"

然后就能看到 WAF的日志了

救命!我的 Azure Front Door WAF 规则不生效怎么办!

什么??

WTF?谁家 requestUri这么写啊 还带端口的,怪不得我配置的 begins with /v1 不好用,但是contains就行……

救命!我的 Azure Front Door WAF 规则不生效怎么办!

火速去 WAF 里,改一下规则,给matches value改成完整的路径就好了

https://cn-test.burn.hair:443/v1

救命!我的 Azure Front Door WAF 规则不生效怎么办!

😢 问题解决了,开的各种东西可以去 Resource Group 里删除了


「不愧是 Azure,从定价,到文档,到使用,没一个符合直觉」

—— Nova Kowk


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/azure-waf.html
🔲 ⭐

警惕USDT-TRC20 数字货币诈骗

最近看到一种很有趣的数字货币诈骗方法,有人有意无意在群里、论坛或者其他公开的地方,泄漏自己的助记词,往往是Tron这个链,然后这个钱包里有大概几十到几百USDT,比如下图这样

警惕USDT-TRC20 数字货币诈骗

一般来说这种钱包TRX会比较少,多一点的也有,其实没关系的。

众所周知,进行 USDT 转账是需要 TRX做燃料的。有些人可能就想到了……

  1. 既然有助记词,那么就可以导入到自己的钱包里
  2. 从别的地方转进来几十 TRX做gas
  3. 然后把这几百USDT转走,白嫖成功

事情哪有那么简单!

偷取燃料费

当你把 TRX 转进来之后,还没等这笔钱热乎,就会被瞬间转走!

比如在上图中我们看到的这个例子,他的地址是 TAvwgoX6zbExfotsgP351QxxCoHGH8mmyb ,通过查询 tronscan我们可以查询一个地址的所有交易记录,我这里用不同颜色的做了标记:

警惕USDT-TRC20 数字货币诈骗

我们可以很清楚地看到,受害者向 mmyb的地址转账,慢则5分钟,快则几十秒,这笔TRX就会被转到 Mh4J 的地址。截止到目前为止,这个地址已经骗了$90了。

我还有另外一个例子,也是一样的手段

警惕USDT-TRC20 数字货币诈骗

拼手速?

假如你也会写点代码,你可能在想,哎不就是拼手速嘛!转点TRX进去,然后瞬间再转走 USDT,全程代码操作延迟1秒,那不就白嫖成功了嘛!

有这种想法不得不说非常聪明,然而骗子也早就想到了这一点,骗子也不想偷鸡不成蚀把米。如果你注意看 tronscan地址下的提示信息:

警惕USDT-TRC20 数字货币诈骗

The current account’s "Owner Permission" is authorized to:TDtwL9uggJ1qBhWW83z6q7ssNdhi12356L

The current account’s "Active Permission" is authorized to:TDtwL9uggJ1qBhWW83z6q7ssNdhi12356LView Account Permission

Tron的一个特性之一是,可以把自己地址的权限转移给另一个地址。权限本身是独立的、唯一归属的,要么归你要么归我。

通常来说我们使用这个地址对应的私钥签名的,但是把权限转移给另外一个地址之后,就可以用那个地址的私钥签名了。

在这个例子中,这个蜜罐地址 mmyb 的全部权限都被转移给了另外一个 356L的地址,mmyb的私钥因为缺失权限,是无法签名交易的。

更进一步,Tron还可以设置mult-sig(多重签名),需要多个私钥+权重计算才可以完成某个操作,有点像大家开会表决。

😂所以,即使你手速够快,也会发现自己没权限动这个资金。

当然了,如果你发现一个地址的权限没有被更改过,那可能确实是天上掉馅饼了。

我被骗了吗

哈!😏😏😏

警惕USDT-TRC20 数字货币诈骗

哈,你终于领悟了成为传奇的诀窍……拿上你的家伙,咱们走。


我可是传奇,想要骗我可没那么容易😉😉😉

参考阅读

https://www.exodus.com/support/en/articles/8598817-what-crypto-scams-should-i-watch-out-for#honeypot

 


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/usdt-trc20-scam.html
🔲 ⭐

Telegram Login Widget 如何验证用户数据

使用Telegram 做OAuth是一件很容易的事情,毕竟整个 Telegram API 都相当开放。

需要注意的一件事情就是,我们需要验证用户的数据确实是来自于 Telegram而不是第三方伪造的。无论是在回调函数还是回调URL中,Telegram都会提供如下参数:
id, first_name, last_name, username, photo_url, auth_date, hash
根据官方文档的说法,验证数据分如下几步:

  1.  把这些字段按照字母顺序排序,组成一个字符串,每一个键值对之间用换行符隔开,如 'auth_date=<auth_date>\nfirst_name=<first_name>\nid=<id>\nusername=<username>'
  2. 计算 bot token 的 sha256
  3. 计算 HMAC_SHA256,明文是上面的这个字符串,密码是bot token 的sha256,然后计算这个结果的hex,比对与他提供的 hash是否相等

看起来很简单是不是,随便丢给 ChatGPT就能出结果。甚至官方还给了个PHP的代码

但是很抱歉的是,这样并不能给保证100%验证成功,甚至可能会完全无法验证。以下是我踩的两个坑

hash字段要排除

在组装字符串的时候,记得排除hash字段,要不然是不可能计算出正确的结果的。

值是空的字段要排除

在 Telegram 中,username、photo_url 等字段不是必须的。在计算时,这种类型的字段如果为空,那么不需要考虑

可怕的是,无论是官方文档,还是PHP示例代码,都没有提到值是空的字段不参与计算的事情。😢

示例代码

Go 的示例代码

type TelegramAuthData struct {
	Id        int    `json:"id"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Username  string `json:"username"`
	PhotoUrl  string `json:"photo_url"`
	AuthDate  int    `json:"auth_date"`
	Hash      string `json:"hash"`
}

func verifyTelegramAuthData(data TelegramAuthData) bool {
	// Extracting fields and preparing for sorting.
	fields := map[string]string{
		"auth_date":  strconv.Itoa(data.AuthDate),
		"first_name": data.FirstName,
		"last_name":  data.LastName,
		"id":         strconv.Itoa(data.Id),
		"photo_url":  data.PhotoUrl,
		"username":   data.Username,
	}

	// Sorting the fields to create the data-check-string.
	var keys []string
	for key := range fields {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	var dataCheckString string
	for _, key := range keys {
		if fields[key] != "" {
			dataCheckString += fmt.Sprintf("%s=%s\n", key, fields[key])
		}
	}
	dataCheckString = dataCheckString[:len(dataCheckString)-1] // Remove the last newline character

	// Calculate the SHA256 hash of the bot's token.
	hasher := sha256.New()
	hasher.Write([]byte(botToken))
	secretKey := hasher.Sum(nil)

	// Compute the HMAC-SHA-256 signature.
	hmacHasher := hmac.New(sha256.New, secretKey)
	hmacHasher.Write([]byte(dataCheckString))
	computedHash := hex.EncodeToString(hmacHasher.Sum(nil))

	// Compare the computed HMAC with the received hash.
	return computedHash == data.Hash
}

Python 版本

def verify_telegram_authdata(data: dict) -> bool:
    # Extracting fields and preparing for sorting
    fields = {
        "auth_date": data.get("auth_date"),
        "first_name": data.get("first_name"),
        "last_name": data.get("last_name"),
        "id": data.get("id"),
        "photo_url": data.get("photo_url"),
        "username": data.get("username"),
    }

    # Sorting the fields to create the data-check-string
    keys = sorted(fields)
    data_check_string = "\n".join(f"{key}={fields[key]}" for key in keys if fields[key])

    # Calculate the SHA256 hash of the bot's token
    hasher = hashlib.sha256()
    # bot token token
    hasher.update("token".encode("utf-8"))
    secret_key = hasher.digest()

    # Compute the HMAC-SHA-256 signature
    hmac_hasher = hmac.new(secret_key, data_check_string.encode("utf-8"), hashlib.sha256)
    computed_hash = hmac_hasher.hexdigest()

    # Compare the computed HMAC with the received hash
    return computed_hash == data.get("hash")


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/telegram-login-widget-verify-data.html
🔲 ⭐

沉浸感

我很喜欢玩赛博朋克2077,在往日之影发布之前很久已经清完了所有的支线和委托。往日之影发布之后,我熬了两个晚上,玩完了全部四个分支。

随后我就出去旅游了。往日之影的结局是在是太让我感到无力了,那个时候我就坐在酒店的阳台上发呆。为什么会这样啊,我很难过。与其这样生活,真的不如再活半年,或者把身体留给强尼,至少这样不会失去朋友啊。

人们总是很容易把艺术作品中的情形代入到自己的生活中,或者反之。

那个时候我在日记里写道

这也像极了现在的我。我在一点点失去我的朋友,我找不到生活的目标,这样的生活,远远不如以前开心。可生活不是游戏,没办法轻松重新选择故事走向。每次重新选择,都要承担巨大的代价和后果。

在赛博朋克之后,我再也没有精力去如此品玩任何其他的游戏。可能是怕试错成本太高,很难找到符合我的喜好的游戏。Game Pass Ultimate过期之后也没有再续费,因为感觉自己完全找不到能玩的游戏。

在影视作品中,我有些时候也会有这种感觉。

最近白嫖了 Apple TV+,然后熬了三四个晚上看完了灵异女仆。 电视剧的节奏挺慢的,至少说在惊悚悬疑题材里这个节奏很慢,还好我没有追剧。

沉浸感

我很喜欢女主Leanne的人设和演员的演绎,Leanne只不过是童年破碎的受害者,她把自己对亲生母亲的期望全部投射到Dorothy身上。 男主一家人里如果有一个人能稍微正常点,那么结局会不会好一点? 只有厨师小弟对 Leanne 很好,没有理由也没有利益的羁绊,只是可惜那场约会永远也不会到来……

沉浸感

哎所以我总是很怕这样。一方面是怕自己陷得太深,另一方面是怕自己以后很难发现更好的文艺作品。

我毫不犹豫的熬夜,只是想把自己沉浸在这些作品所营造的背景和氛围之内,这样我就可以暂时忘记发生在现实生活中的种种烦恼与问题,这样我就可以忽略问题,像鸵鸟一样把头埋在沙子里。 然而一旦看完这部电影,玩通那个游戏,这样的沙子也就不复存在,也就只能面对现实和无奈。🤷

有时候可能看看爽剧,玩一玩那些无脑爽游戏(比如最近几年的使命召唤),只是娱乐放松而没有沉浸,这样可能会对我的心理状态有更好的帮助。沉浸感太强,有的时候可能也不是一件好事🫠


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/immersion.html
🔲 ⭐

2023 年终总结

这篇文章在 2024年01月08日21:30:43 更新了哦~

很多年没有写年终总结了。有很多事情都是2022年年底的发生的,四舍五入也算2023年的吧!

博客

2023年一共写了16篇博文,从数量上看起来比较少,从质量上看则更是堪忧🙃️

2023 年终总结

这一年学习到了很多有用没用的知识。

在这之后,我的博客就停更了差不多半年左右。这半年里我和 Nova 还有 Tuki 开发并运营了 WebP Cloud Services。这个想法来自于3年前的WebP Server Go,区别是Cloud Services功能更多更强大,而且是托管的SaaS服务。

这半年里我也写了博文,只不过放在了 WebP Cloud Services Blog 上。为了增加受众,并且我们的目标是出海,我们还用 ChatGPT 翻译了英文版本的。

然后,我就又回到了🥔不好吃

这一年的写作到这里就结束了。

工作

换了一份工作,薪水比上份工作多一些。然而我觉得这份工作并没有上一份工作那么令我满意,主要集中在以下这几点吧:

  • 工作流程:上一份工作的公司刚刚被某芯片大厂收购,工作流程非常规范(因此也很慢),任何变更要通过 PR来,需要2个 review,Test Coverage大概有个70-80%左右
  • 技术栈的变化:前司是Python + Clarity + PostgreSQL,我还接手了一个 Java的Play framework 的东西,感谢老板对我的信任,我都没想到能弄明白🤣 现在则是 Nodejs + Angular+ Elm 。JavaScript 懂得都懂黑点无数,大家也乐此不疲的黑JS,但是无论怎么说JS还是发展非常迅速的一门语言,生态也挺不错。Elm那我只能😄啦,只提一点:标准库上次更新是2021年2月。
  • 氛围和企业文化:这个没什么可说的,都很棒,同事们都挺好的。也没有什么996的事,到点就走。但是不知为何我还是更喜欢前司😂

别的倒也没什么,俗话说钱难挣嘛,这个道理都懂……

旅游

从来不爱旅游的我,今年竟然破天荒的去了5个城市旅游。收获了什么忘记了,无论是「这个楼也太他妈牛逼了」还是「落霞与孤鹜齐飞」都不记得了。 我也没写xxx游记,只记得买了很多明信片😓

开源项目

  • YYeTs:基本没什么太大的变化,dependabot的commit比我还多。前段时间转手给别人之后我更是不管了
  • WebP Server Go:虽然有持续的更新,并且有一些 issue,但是主要都是 Nova 大佬在处理,我基本打酱油了
  • ytdlbot:更新了一大堆东西,每天跑 200G 流量。收获0.
2023 年终总结

总体来看,基本上可以说还是那些,没什么新的变化,“僵尸”状态可能是一个比较恰当的形容词。

游戏

电子阳痿

等了很久的《往日之影》发布了,熬夜两天玩完,后劲太大直接让我郁闷的好几天。假如我是V,我会怎样做出选择?接受治疗活下去,然后失去一切。真的是一切都变了,物是人非,曾经的V震天甚至还会被街边的小混混揍,而这只是短短的两年。

2023 年终总结

曾经的V可是这样的啊(这套服装是往日之影里那个法国黑客奥罗尔的复刻,还蛮好看的,我好喜欢。这把刀好像叫爪磨?)

与其这样生活,真的不如再活半年,或者把身体留给强尼。甚至,不如信了荒坂。

人呐难免会把艺术作品中的事情联想到自己身上,这个高塔结局说的不就是现在的我吗?

2023 年终总结

Steam Deck

买了个 Steam Deck,淘了个显示器键盘和1 TB SSD,然后装了个双系统。这玩意就是一个标准的x86机器,所以装双系统甚至三系统这种事情对于我来说自然不在话下。惊叹于 Windows 11,和Windows 10比起来还是变化了很多的。

装完系统我也没怎么用,看起来也电子阳痿了。

影视作品

看了挺多,大部分都是 Netflix上的

  • VIVANT: 堺雅人主演的电视剧,前几集挺好看,后面略差。堺雅人的英文不太好,可能不如中文吧
  • 石子和羽男 :有村架纯真的是太可爱了,我好爱她😍
  • V世代:黑袍纠察队的衍生电视剧,很不错
  • 上载新生第三季:略差了,但是比第二季好多了
  • 最后生还者:改编于同名游戏,那个被魔山捏爆脑子的王子还真是挺忙
  • 曼达洛人第三季:电视剧总体水平还不错,但是不知道为何我不太喜欢了,可能毕竟不是星战粉吧。主演还是上面那个王子
  • 阿妮亚传奇啊不,间谍过家家:我很少看动漫,但是这部动漫竟然坚持下来了
  • 赛博朋克 边缘行者:听说看完这部动漫的人都打开游戏锤爆亚当·重锤,我也不例外😂
  • 噬亡村:柳乐优弥和吉冈里帆主演的电视剧。吉冈妹子真的好美,不知道第二季什么时候,这都快一年了
  • 弥留之国的爱丽丝:第二季不太行……
  • 甜蜜家园第二季:更不行
  • 谁是被害者:台剧,还不错嗷
  • 模仿犯:也是台剧,不错
  • 罪后真相:台湾电影,还好,看预告片不错
  • 黑暗荣耀:宋慧乔主演的,不错
  • 黑镜第六季:琼糟透了、海之彼岸还不错,其他的一般般
  • 关注者:不知道讲了什么,全程被池田 エライザ吸引🤩
  • 初恋:这年头的纯爱剧,还真的能看进去(其中有一点点18🈲️镜头哈哈哈),主题曲和灵感均是宇多田光的 First Love,光妹真的浑身发光啊
  • 重启人生:假如我能重启人生,那么我要做的事情会不会是,在高考结束之后的那天,把上交的志愿改掉?

还有一堆乱七八糟的,不记得了想不起来了

音乐

新增了很多 OST,都是赛博朋克的,最喜欢的还是 Gate K9(往日之影)和 The Rebel Path(单挑荒坂塔)

剩下的歌曲基本都是日本流行乐,基本全是 uru,我最喜欢的可能是 「ドライフラワー 」吧,这种小小伤感的歌曲最让我喜欢了:

  • なんでもないよ
  • ドライフラワー
  • 無機質
  • 再会
  • ポジティ部入部
  • ランドマーク
  • 紙一重
  • 君の幸せを
  • セレナーデ

2023 年终总结

还是挺恩爱的。但是酸奶后背脱毛了😫,并且从昨天开始呕吐腹泻😫😫😫

2024的期待

猫咪身体健康就可以了,看起来已经恢复了,但是似乎饿瘦了🫠

2023 年终总结


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/2023-end.html
☑️ ⭐

Steam Deck 启动游戏卡 logo

最近买了个 Steam Deck,在玩游戏的时候发现一个很奇怪的bug。当休眠之后再次打开游戏,就会不停转 steam logo,如下图所示

Steam Deck 启动游戏卡 logo

但是如果按菜单键,会发现游戏已经加载成功了

Steam Deck 启动游戏卡 logo

重启之后可以解决,但是不能每次都重启啊。

后来发现,在 设置-自定义-用作唤醒影片 这个关掉就可以了 😂

 

这种 Bug 也是绝了😓

参考链接

https://steamcommunity.com/app/1675200/discussions/1/6348431004268742880/


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/steam-deck-stuck.html
☑️ ⭐

这是人人影视分享站被黑的最惨的一次

这篇文章在 2023年03月15日08:04:33 更新了哦~

最近这段时间,我的人人影视分享站不怎么太平,不是被恶意爬虫就是被CC攻击。不知道是遭遇了竞争对手还是怎么的。

3月7日中午,收到cloudflare邮件说服务器无法连接

这是人人影视分享站被黑的最惨的一次

SSH看一下日志,果然,有很多莫名其妙的搜索,

这是人人影视分享站被黑的最惨的一次

这些请求主要有如下特点:

40秒内200多个请求,分布在60个不同的IP地址上,还全都是中国民用家宽的IP。

  1. 使用中国各个地区、各个运营商的民用家宽IP,比如上图40秒内200多请求,分布在60个不同的IP地址上
  2. 同一个IP的UA还会变,一会是Chrome一会是Firefox,这看起来很不正常
  3. 即使到了下半夜也还在大量请求,正常人都是要睡觉的
  4. 搜索内容大致为某些综艺的名字+集数或演员名字,没有referer,正常搜索浏览器是一定会带referer的,因此应该是机器人直接发出的请求
  5. 他直接请求的!要是跑的selenium我也就认啦,就当给我点广告了

我尝试了如下解决方案:

  1. 根据IP去cloudflare上拉黑,结果发现IP太多,根本拉不过来
  2. 用Cloudflare的 rate limit去限制请求频率,结果因为他们IP实在是太多了,全都分散开了,没用
  3. 开cloudflare的DDoS 防护规则也没用,因为IP太多了,在cf 看来基本就是正常请求,至少免费版来看是这样的

发现以上办法似乎都没有什么用,于是开了三秒墙,所有用户在打开网站的时候都会有浏览器检查,大概这样

这是人人影视分享站被黑的最惨的一次

机器人自然无法完成JS challenge,于是这一波下来稳了。

我的数据库是公开的,这么爬很不地道,动了这么多IP也一定没少破费。何必呢?我也不是什么竞争对手,我只不过是开了一个很普通的个人站,全靠网友贡献。挺累的。


几天之后星期五,我发现网站竟然又挂了!开着三秒墙也能被打挂?看了一眼日志……

这是人人影视分享站被黑的最惨的一次

Vultr的美国机,竟然用这种随机无意义的字符串来搜索,竟然还绕过了三秒墙,也绕过了rate limit。🤣于是MongoDB炸了,nginx也基本要炸了。

去cloudflare上添加了黑名单,并没有效果。哦豁?难道是cloudflare又bug了……想了一下,不对,是我的源站IP被找到了,怪不得三秒墙和rate limit都没效果😓

这种情况下只能去机器上添加防火墙,或者机器的供应商那里添加安全组之类的了。不幸的事情来了:

  1. 没有安全组可用
  2. 我的nginx是docker启动的,这也就意味着一般的在INPUT链拉黑IP的办法不管用
  3. 在尝试调解docker和nginx的过程中,一不小心写错了iptables规则。出门没带钥匙嘛。
  4. 我不知道SSH的密码是什么,应该是16位的hex,去grub改init然后修改密码很麻烦毕竟是VNC

这是人人影视分享站被黑的最惨的一次

不幸之外还有一些好消息:

  1. 我没有持久化iptables规则,意味着只要去控制面板重启一下,我刚刚写错的规则就会消失了!
  2. 我可以换IP,至少能够暂时化解这种情况

于是问题就这么解决了。这是我做这个小破站被黑的最惨的一次。在这次经历中,我学习到了如下经验教训:

  1. 爬虫死全家,尤其是45.32.227.75 😄
  2. docker会破坏基于iptables为后端的防火墙。Docker跑的应用,如果绑定了端口,那么会给iptables打洞,意味着常规堵INPUT链的办法不管用,要PRE ROUTTING、改DOCKER-USER或者让docker和ufw一起工作,巨麻烦,心智负担非常大。
  3. 网站躲在cloudflare后也可能被抓到源站IP,比如说censys,全网扫IP+443然后找证书,或者IP+80比对特征
  4. 应该拒绝全部非cloudflare IP对80和443的请求,甚至直接通过argo tunnel之类的来解决,连nginx都用不上
  5. 保护好自己的IP,毕竟只要IP被抓到了,14亿中国人一人一个ping你也受不了🇨🇳
  6. 在MongoDB中使用正则模糊查询,如/.*keyword.*/是非常慢的,全文检索的话,我记得是Atlas专有,而且一旦涉及到CJK,也有可能完犊子
  7. 容器如果一直不停地yyetsbot_web_1 exited with code 137,记得检查下是不是有什么奇奇怪怪的保活监测脚本
  8. 配置路由表、iptables规则时务必小心,务必给自己留后门。我之前留的后门是只能通过console登录的root权限用户,密码不是很复杂,通过VNC之类的东西输入还是可以的
  9. MongoDB的aggregation很强大,可以做到跨集合查询,自定义查询字段名称等等
  10. 遇到问题不要慌,记得先撸猫再解决问题

这是人人影视分享站被黑的最惨的一次

 


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/yyets-hack.html
❌