2024-09-19 如何通過阿里云 OpenAPI 獲取 DCDN 節(jié)點(diǎn) IP 白名單

前言

事情的起因還得追溯到給博客加了 全站加速晕讲。

依靠全站加速登下,還減輕了一次網(wǎng)站攻擊陶舞,詳見:記一次網(wǎng)站被 DDoS(CC)攻擊 的過程和應(yīng)對(duì)方案

在設(shè)置了全站加速之后,通過域名默認(rèn)會(huì)走阿里云的 DCDN 節(jié)點(diǎn)遭铺,只有在未緩存的時(shí)候會(huì)訪問源站絮记。

此時(shí)瞪讼,源站就會(huì)遇到一個(gè)需求:最好僅允許阿里云的 DCDN 節(jié)點(diǎn)進(jìn)行訪問。

也就是說蛛壳,需要獲取到阿里云的 DCDN 節(jié)點(diǎn)的 IP 列表杏瞻,以添加到白名單中所刀。

就此,開始了折騰之路捞挥。

開始

由于之前已經(jīng)用過阿里云 OpenAPI 進(jìn)行 CDN 的管理(如何通過阿里云 OpenAPI 管理 CDN)浮创,所以這一次也采用了阿里云 OpenAP,從而實(shí)現(xiàn)自動(dòng)化設(shè)置砌函。

翻閱全站加速相關(guān)文檔可以看到一個(gè)接口:DescribeDcdnL2Ips - 查詢 L2 節(jié)點(diǎn) IP 地址

image-20240919224443348

這正是我需要的斩披。

由于文檔里沒有說前置要求,所以我想當(dāng)然的認(rèn)為只要提交工單就可以獲得權(quán)限胸嘴。

中道崩阻

結(jié)果:

image-20240919224751866

不是雏掠,大哥,你在 DCDN 的文檔中又沒有說明前置要求劣像,沒寫就是沒要求才對(duì)乡话。

再者,CDN 節(jié)點(diǎn)的 IP 是什么需要藏著掖著的東西嗎耳奕?你不公開出來我怎么設(shè)置白名單绑青?

隔壁 Cloudflare 就是把 IP 地址范圍全部公布出來的,例如 IP 地址范圍屋群。

所以什么要設(shè)置個(gè)門檻闸婴?不是很能理解。

峰回路轉(zhuǎn)

但很快啊芍躏,我又發(fā)現(xiàn)另一個(gè)接口:DescribeDcdnIpInfo - 驗(yàn)證 IP 節(jié)點(diǎn)

image-20240919225454340

雖然沒法直接獲取 DCDN 節(jié)點(diǎn)的 IP 邪乍,但是可以驗(yàn)證一個(gè) IP 是不是阿里云 DCDN 節(jié)點(diǎn)。

解決問題

所以接下來解決方案就很簡單了对竣。

我手動(dòng)把 IP 地址驗(yàn)證一遍不就完事了庇楞?

當(dāng)然了,考慮到 IPv4 一共有 42 億個(gè) IP否纬,顯然是不可能窮舉一遍的吕晌。

那么我就得找個(gè)地方獲取訪問 IP。

獲取 IP 地址

而 NGINX 的日志临燃,就是一個(gè)獲取 IP 的好地方睛驳。

以下是一個(gè)從日志中獲取 IP 地址的 TypeScript 函數(shù):

// 定義提取 IP 地址的函數(shù)
async function extractUniqueIps(logFilePath: string) {
    // 使用 Set 來存儲(chǔ)唯一的 IP 地址
    const uniqueIps = new Set<string>()

    // 使用流式讀取日志文件
    const readStream = fs.createReadStream(logFilePath, { encoding: 'utf-8' })
    const rl = createInterface({ input: readStream })

    // 逐行處理日志文件
    rl.on('line', (line) => {
        // 使用正則表達(dá)式提取 IP 地址
        const ipPattern = /\b([0-9]{1,3}\.){3}[0-9]{1,3}\b/
        const match = line.match(ipPattern)
        if (match) {
            uniqueIps.add(match[0])
        }
    })

    // 返回一個(gè) Promise,當(dāng)讀取結(jié)束時(shí)膜廊,解析為唯一的 IP 地址數(shù)組
    return new Promise<string[]>((resolve) => {
        rl.on('close', () => {
            resolve([...uniqueIps])
        })
    })
}

采用流式讀取是因?yàn)槿罩疚募赡軙?huì)有點(diǎn)大乏沸,全部讀取進(jìn)來有點(diǎn)占內(nèi)存。

經(jīng)過這一通折騰溃论,我拿到了一個(gè)約 28000 個(gè) IP 地址屎蜓。

有一說一,這個(gè)量還是有點(diǎn)大钥勋,50 次/秒的話要跑 560 秒炬转,約 9.3 分鐘辆苔,這個(gè)時(shí)間就有點(diǎn)久了。

所以扼劈,可以采用 IP 屬地進(jìn)行初次過濾驻啤。

獲取 IP 屬地

通過 lionsoul2014/ip2region 這個(gè)項(xiàng)目可以拿到所有 IP 的屬地。

雖然數(shù)據(jù)上可能有點(diǎn)過時(shí)荐吵,但用來初步篩選已經(jīng)夠了骑冗。

以下是一個(gè)使用 JavaScript 實(shí)現(xiàn)的查詢腳本(參考:ip2region nodejs 查詢客戶端實(shí)現(xiàn)

// 導(dǎo)入包
const Searcher = require('.')
// 指定ip2region數(shù)據(jù)文件路徑
const dbPath = 'ip2region.xdb file path'

try {
  // 創(chuàng)建searcher對(duì)象
  const searcher = Searcher.newWithFileOnly(dbPath)
  // 查詢
  const data = await searcher.search('218.4.167.70')
  // data: {region: '中國|0|江蘇省|蘇州市|電信', ioCount: 3, took: 1.342389}
} catch(e) {
  console.log(e)
}

然后從中篩選出 region 為 阿里云阿里巴巴 的 IP。

接下來先煎,再判斷是否為阿里云 DCDN 節(jié)點(diǎn)贼涩。

判斷 DCDN 節(jié)點(diǎn)

接下來就是調(diào)用 DescribeDcdnIpInfo 接口來驗(yàn)證是否為阿里云 DCDN 節(jié)點(diǎn)了。

以下是一個(gè)用 TypeScript 實(shí)現(xiàn)的 Client 封裝類薯蝎。

// This file is auto-generated, don't edit it
// 依賴的模塊可通過下載工程中的模塊依賴文件或右上角的獲取 SDK 依賴信息查看
import dcdn20180115, * as $dcdn20180115 from '@alicloud/dcdn20180115'
import OpenApi, * as $OpenApi from '@alicloud/openapi-client'
import Util, * as $Util from '@alicloud/tea-util'

export default class Client {

    /**
   * @remarks
   * 使用AK&SK初始化賬號(hào)Client
   * @returns Client
   *
   * @throws Exception
   */
    static createClient(): dcdn20180115 {
        // 工程代碼泄露可能會(huì)導(dǎo)致 AccessKey 泄露遥倦,并威脅賬號(hào)下所有資源的安全性。以下代碼示例僅供參考占锯。
        // 建議使用更安全的 STS 方式袒哥,更多鑒權(quán)訪問方式請(qǐng)參見:https://help.aliyun.com/document_detail/378664.html。
        const config = new $OpenApi.Config({
            // 必填消略,請(qǐng)確保代碼運(yùn)行環(huán)境設(shè)置了環(huán)境變量 ALIBABA_CLOUD_ACCESS_KEY_ID堡称。
            accessKeyId: process.env['ALIBABA_CLOUD_ACCESS_KEY_ID'],
            // 必填,請(qǐng)確保代碼運(yùn)行環(huán)境設(shè)置了環(huán)境變量 ALIBABA_CLOUD_ACCESS_KEY_SECRET艺演。
            accessKeySecret: process.env['ALIBABA_CLOUD_ACCESS_KEY_SECRET'],
        })
        // Endpoint 請(qǐng)參考 https://api.aliyun.com/product/dcdn
        config.endpoint = 'dcdn.aliyuncs.com'
        return new (dcdn20180115 as any).default(config)
    }

    static async DescribeDcdnIpInfoRequest(IP: string) {
        const client = Client.createClient()
        const describeDcdnIpInfoRequest = new $dcdn20180115.DescribeDcdnIpInfoRequest({
            IP,
        })
        const runtime = new $Util.RuntimeOptions({})
        try {
            // 復(fù)制代碼運(yùn)行請(qǐng)自行打印 API 的返回值
            return (await client.describeDcdnIpInfoWithOptions(describeDcdnIpInfoRequest, runtime)).body
        } catch (error) {
            // 此處僅做打印展示却紧,請(qǐng)謹(jǐn)慎對(duì)待異常處理,在工程項(xiàng)目中切勿直接忽略異常胎撤。
            // 錯(cuò)誤 message
            console.log(error.message)
            // 診斷地址
            console.log(error.data['Recommend'])

        }
    }

}

最后啄寡,把是 阿里云 DCDN 的 IP 寫入到文件。

至此哩照,就大功告成了!

生成網(wǎng)段

不過懒浮,單純的用 IP 的話實(shí)際上容易誤判飘弧,原因是阿里云 DCDN 的 IP 還是挺多的,靠從 NGINX 日志獲取的方法效率低不說砚著,還很滯后次伶。

所以,將 IP 改為網(wǎng)段更加合理一些稽穆。

以下是一個(gè)從 IP 地址列表生成 IP 網(wǎng)段的 TypeScript 腳本冠王。

/**
 *
 *
 * @author CaoMeiYouRen
 * @date 2024-09-16
 * @param ips IP地址
 * @param [netMask=24] 子網(wǎng)掩碼位數(shù)
 */
function getSubnetCounts(ips: string[], netMask = 24) {
    // 創(chuàng)建 Map 來存儲(chǔ)網(wǎng)段及其出現(xiàn)頻率
    const subnetCounts = new Map<string, number>()

    // 遍歷每個(gè) IP 地址
    for (const ip of ips) {
        // 提取前 n 段作為網(wǎng)段
        const segments = ip.split('.')
        const subnetSegments = segments.slice(0, netMask / 8)
        const subnet = `${subnetSegments.join('.')}${'.0'.repeat(4 - subnetSegments.length)}/${netMask}`

        // 如果網(wǎng)段不存在于 subnetCounts 中,初始化為 0
        if (!subnetCounts.has(subnet)) {
            subnetCounts.set(subnet, 0)
        }

        // 增加網(wǎng)段的計(jì)數(shù)
        subnetCounts.set(subnet, subnetCounts.get(subnet) + 1)
    }
    return [...subnetCounts].map(([subnet, count]) => ({ subnet, count }))
}

然后就可以生成 NGINX 的白名單了,生成的結(jié)果如下:

allow 101.133.199.0/24; # count: 66
allow 101.200.20.0/24; # count: 58
allow 101.37.183.0/24; # count: 2
allow 106.11.37.0/24; # count: 23
allow 112.124.132.0/24; # count: 30
allow 114.215.0.0/16; # count: 108
allow 114.215.72.0/24; # count: 108
allow 118.190.214.0/24; # count: 22
allow 118.190.218.0/24; # count: 14
allow 119.23.123.0/24; # count: 39
allow 119.23.91.0/24; # count: 41
allow 120.27.78.0/24; # count: 43
allow 121.199.80.0/24; # count: 37
allow 121.89.252.0/24; # count: 6
allow 139.129.78.0/24; # count: 6
allow 139.196.128.0/24; # count: 46
allow 163.181.0.0/16; # count: 562
allow 163.181.1.0/24; # count: 10
allow 163.181.126.0/24; # count: 38
allow 163.181.128.0/24; # count: 2
allow 163.181.130.0/24; # count: 22
allow 163.181.131.0/24; # count: 12
allow 163.181.132.0/24; # count: 1
allow 163.181.140.0/24; # count: 14
allow 163.181.143.0/24; # count: 3
allow 163.181.145.0/24; # count: 19
allow 163.181.146.0/24; # count: 36
allow 163.181.154.0/24; # count: 11
allow 163.181.160.0/24; # count: 16
allow 163.181.164.0/24; # count: 10
allow 163.181.166.0/24; # count: 9
allow 163.181.18.0/24; # count: 2
allow 163.181.199.0/24; # count: 20
allow 163.181.201.0/24; # count: 15
allow 163.181.22.0/24; # count: 12
allow 163.181.23.0/24; # count: 5
allow 163.181.35.0/24; # count: 24
allow 163.181.37.0/24; # count: 5
allow 163.181.38.0/24; # count: 10
allow 163.181.39.0/24; # count: 10
allow 163.181.42.0/24; # count: 11
allow 163.181.49.0/24; # count: 5
allow 163.181.50.0/24; # count: 6
allow 163.181.52.0/24; # count: 2
allow 163.181.57.0/24; # count: 12
allow 163.181.66.0/24; # count: 17
allow 163.181.67.0/24; # count: 34
allow 163.181.70.0/24; # count: 2
allow 163.181.77.0/24; # count: 23
allow 163.181.78.0/24; # count: 10
allow 163.181.79.0/24; # count: 39
allow 163.181.81.0/24; # count: 24
allow 163.181.82.0/24; # count: 4
allow 163.181.85.0/24; # count: 31
allow 163.181.88.0/24; # count: 3
allow 163.181.89.0/24; # count: 1
allow 163.181.90.0/24; # count: 14
allow 163.181.92.0/24; # count: 14
allow 163.181.94.0/24; # count: 4
allow 39.100.171.0/24; # count: 62
allow 39.103.26.0/24; # count: 1
allow 39.108.196.0/24; # count: 9
allow 39.96.152.0/24; # count: 52
allow 47.102.25.0/24; # count: 45
allow 47.104.50.0/24; # count: 46
allow 47.117.201.0/24; # count: 56
allow 47.118.223.0/24; # count: 51
allow 47.120.0.0/16; # count: 129
allow 47.120.230.0/24; # count: 77
allow 47.120.92.0/24; # count: 52
allow 47.123.117.0/24; # count: 26
allow 47.246.0.0/16; # count: 189
allow 47.246.2.0/24; # count: 14
allow 47.246.20.0/24; # count: 14
allow 47.246.22.0/24; # count: 14
allow 47.246.23.0/24; # count: 15
allow 47.246.24.0/24; # count: 14
allow 47.246.36.0/24; # count: 4
allow 47.246.37.0/24; # count: 7
allow 47.246.38.0/24; # count: 4
allow 47.246.4.0/24; # count: 28
allow 47.246.42.0/24; # count: 13
allow 47.246.44.0/24; # count: 8
allow 47.246.45.0/24; # count: 3
allow 47.246.46.0/24; # count: 7
allow 47.246.48.0/24; # count: 14
allow 47.246.49.0/24; # count: 9
allow 47.246.50.0/24; # count: 21
allow 8.132.0.0/16; # count: 206
allow 8.132.18.0/24; # count: 132
allow 8.132.19.0/24; # count: 74
allow 8.141.176.0/24; # count: 50

注釋里面的 count 是該網(wǎng)段有多少個(gè)阿里云 DCDN IP舌镶。

以上結(jié)果僅供參考柱彻,如有需要豪娜,可以參考這些 IP 網(wǎng)段。

可以看到 NGINX 的白名單中有部分還采用了 16 位子網(wǎng)掩碼哟楷,將 IP 范圍進(jìn)一步擴(kuò)大到 65536 個(gè)瘤载。

總結(jié)

以上就是如何通過阿里云 OpenAPI 獲取 DCDN 節(jié)點(diǎn) IP 白名單的具體方法。

如果你達(dá)到了調(diào)用 DescribeDcdnL2Ips - 查詢L2節(jié)點(diǎn)IP地址接口的要求卖擅,那么實(shí)際上直接調(diào)用這個(gè)接口會(huì)更加方便鸣奔。

如果你沒達(dá)到要求的話,可以參考本文的實(shí)現(xiàn)方案惩阶,雖然不夠優(yōu)雅挎狸,但應(yīng)該夠用了。


喜歡的話就點(diǎn)個(gè)關(guān)注吧~

歡迎在評(píng)論區(qū)評(píng)論~

本文作者:草梅友仁

本文地址:https://blog.cmyr.ltd/archives/8c61e292.html

版權(quán)聲明:轉(zhuǎn)載請(qǐng)注明出處断楷!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锨匆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子脐嫂,更是在濱河造成了極大的恐慌统刮,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件账千,死亡現(xiàn)場離奇詭異侥蒙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)匀奏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門鞭衩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人娃善,你說我怎么就攤上這事论衍。” “怎么了聚磺?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵坯台,是天一觀的道長。 經(jīng)常有香客問我瘫寝,道長蜒蕾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任焕阿,我火速辦了婚禮咪啡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘暮屡。我一直安慰自己撤摸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著准夷,像睡著了一般钥飞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冕象,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天代承,我揣著相機(jī)與錄音,去河邊找鬼渐扮。 笑死论悴,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的墓律。 我是一名探鬼主播膀估,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼揭措,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼蹬铺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起褐桌,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤针肥,失蹤者是張志新(化名)和其女友劉穎饼记,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慰枕,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡具则,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了具帮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片博肋。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蜂厅,靈堂內(nèi)的尸體忽然破棺而出匪凡,到底是詐尸還是另有隱情,我是刑警寧澤掘猿,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布病游,位于F島的核電站,受9級(jí)特大地震影響稠通,放射性物質(zhì)發(fā)生泄漏礁遵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一采记、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧政勃,春花似錦唧龄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讽挟。三九已至,卻和暖如春丸冕,著一層夾襖步出監(jiān)牢的瞬間耽梅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工胖烛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留眼姐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓佩番,卻偏偏與公主長得像众旗,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子趟畏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容