成果報告 · EA 課程網站

一支資安影片,意外挖出你網站上最貴的那個洞

今天原本只是想確認「剛裝的資安工具有沒有用」。查完發現那個工具根本沒在運作,於是改用影片教的方法親自檢查網站——然後找到一個任何人不用登入、不用付錢就能看完你 111 支付費影片的漏洞。這份報告說明:為什麼要改、改了什麼、現在安全在哪裡,以及我自己在過程中犯了哪些錯。

日期 2026-08-31 · 對象 app.abbymt4mt5.com · 狀態 全部修復並上線、已用真實刷卡驗證

111
原本任何人都看得到的付費影片
分屬 NT$39,800 與 NT$40,800 兩堂課
0
修復後未登入能取得的影片
正式站實測,不是估計
7
今天完成的修補項目
全部已上線並驗證
0
目前已知的套件安全漏洞
修復前是 4 個高風險

01為什麼會做這件事

起點不是「網站出事了」,而是一個很單純的問題:我裝的那個資安工具,到底有沒有在保護我?

看了一支影片給非技術人員的資安教學
裝了官方資安工具Security guidance
發現它沒在跑而且能力遠不如預期
改用影片的方法
親自檢查網站
五個問題逐項對答案
挖出重大漏洞付費影片可免費觀看
修復並上線加真實刷卡驗證

那個資安工具的問題

它的原理是「檢查你寫的程式碼裡有沒有出現某幾個危險的字」,總共只有 9 條寫死的關鍵字。就像一個只會比對黑名單姓名的警衛——名字不在單子上的,他一律放行。

問題一:它根本沒有在運作

它需要一個叫 python3 的程式來啟動,但你這台 Windows 電腦上的 python3微軟商店的一個空殼捷徑,點下去什麼都不會發生。

更麻煩的是,這種工具啟動失敗時不會報錯,會直接放行。所以你以為裝了就有保護,實際上什麼都沒發生。這比沒裝更危險——它給了你一種安全感。

問題二:就算修好,也抓不到重點

把它的 9 條規則拿去掃你的課程網站,一條都沒對到。而且今天真正找到的那個大洞,它永遠抓不到——因為那不是「寫了危險的字」,而是「把不該給的東西給了不該給的人」,沒有任何可疑關鍵字。

最後的處置:刪掉這個工具,但把 python3 獨立修好(以後其他工具會用得到)。

可以帶走的一句話:評估任何防護工具時,要問的不是「它有沒有裝」,而是「它壞掉的時候,我看得出來嗎?


02今天做了什麼:一張表看完

七項全部已經上線。下面的章節只是把每一項展開講清楚,你可以挑有興趣的看。

項目原本的狀況改成什麼狀態
付費影片外流 未登入就能拿到全部影片編號,配合一個小技巧即可觀看 影片編號不再送到瀏覽器 已修復
舊網址還在漏 一個沒清乾淨的舊網址仍在提供有漏洞的舊版本 網址已關閉 已修復
資料庫多餘權限 只剩一道牆擋著,牆倒了就全開 11 張資料表的多餘寫入權限已收回 已修復
沒有流量限制 有人可以用程式無限狂送結帳請求 每分鐘/每天都設上限 已上線
沒有安全標頭 網站可被別人包進假網頁做釣魚 加上 6 條防護規則 已上線
沒有內容白名單 網頁可以從任何地方載入東西、表單可以送去任何網址 完整白名單,且已開啟強制攔截 已上線
套件安全漏洞 4 個高風險漏洞 升級後歸零 已修復

03最嚴重的那個洞:你的影片曾經是公開的

這是今天唯一一個「已經在發生中」的問題。以下每一步我都實際跑過,不是推測。

它是怎麼發生的

你的課程播放頁有一個側邊欄目錄,列出整堂課的所有單元。為了顯示這份目錄,網站把「整堂課所有單元的資料」送到瀏覽器——包含每一支影片的編號,連沒買的單元也一起送了。

免費試看單元不需要登入就能打開。兩件事湊在一起,任何人打開試看頁,就拿到了整堂課的影片編號。

用生活比喻:這就像餐廳給客人的菜單上,把保險箱密碼印在背面。菜單本身是要給大家看的沒錯,但不該連密碼一起印上去。

完整的攻擊路徑(我實際跑過一遍)

打開免費試看頁不用登入、不用付錢
拿到全部影片編號AI 課 19 支
EA 課 100 支
偽造來源標記假裝自己是從你的網站來的
成功取得影片拿到片名、片長、播放資料

為什麼 Vimeo 的保護沒有擋住

你的影片在 Vimeo 上設了「只有我的網站能播」的限制。聽起來很安全,但這個機制的判斷方式是——看訪客自己填的一張「我從哪裡來」的紙條

問題是那張紙條是訪客自己寫的,想寫什麼就寫什麼。我實測了三種情況:

測試方式結果意義
不填紙條,直接開影片擋下看起來有保護
紙條填「我從你的網站來」放行,拿到影片保護形同虛設
紙條填其他隨便的網址擋下確認機制只看那張紙條

我進一步確認真的能拿到影片內容,取得了片名「AI課程2-1_ini設定檔介紹」、片長 642 秒、以及實際的影片串流資料。這不是理論上可行,是實際做到了。

這不是你設定錯。這是 Vimeo 這個功能本身的已知弱點,資安研究單位早就公開發表過,官方文件也寫明它是靠那張「來源紙條」判斷的。

修好了:前後對照

修復前
119 支影片編號
未登入即可從網頁原始碼取得
(AI 課 19 支 + EA 課 100 支)
修復後(正式站實測)
0 支
側邊欄目錄功能完全正常
單元數、章節、鎖頭圖示都在

修法比原訂計畫更徹底

原本的計畫是「只對沒買課的人隱藏影片編號」。但我在讀程式碼時發現:那個目錄其實只用影片編號來判斷「這一課是影片還是文字」,根本不需要真正的編號。

所以改成只傳一個「有沒有影片」的是/否標記。這樣一來連已經買課的學員也拿不到編號清單,順便堵掉「學員把清單整串貼到網路上」這條路。

為什麼這件事值得多做?把一串編號貼上網是 3 秒的事,錄下 100 支影片要好幾天。兩者的難度差距非常大。同樣的修改幅度,多堵掉一條路。


04先說好消息:你的網站底子其實很好

這次體檢照著影片的五個問題逐項對答案。除了影片那一項,其他都通過,而且有幾項做得比多數商業網站還紮實。

✅ 別人的訂單和個資,訪客一筆都看不到

我直接用「未登入訪客」的身分去資料庫撈資料,實測結果:

折扣碼      → 0 筆
訂單        → 0 筆
會員個資    → 0 筆
課程開通紀錄 → 0 筆
操作紀錄    → 連碰都碰不到

全站 22 張資料表的隔離保護全部開啟,沒有一張漏網

✅ 付款重複計算的問題,防得很專業

影片特別強調的「同一毫秒送十個請求」問題,你的網站用的是資料庫層級的搶單機制——同時進來的請求,只有一個搶得到,另一個自動退出。

不會重複開通、期限不會被疊加兩次、折扣碼不會被多算一次。

✅ 後台每一頁、每一個功能都有守門

11 個後台頁面 + 7 個後台功能,全部都會先檢查身分,沒有一個漏掉。被擋下來還會留下紀錄。

「指派管理員」這種高權限操作,另外要求必須是擁有者本人。

✅ 金額一律後端重算,不相信瀏覽器

結帳時,價格和折扣完全由伺服器自己算,不採信瀏覽器送來的任何金額。條款同意也是後端強制驗證,不是只把按鈕變灰色。

另外全站沒有任何常見的網頁注入風險寫法,金鑰也沒有外洩到前端。

用影片的五個問題對答案

影片提出的問題白話說明你的網站
① 盤點資產哪些東西絕對不能外流通過
② 權限控制誰可以碰哪些資料通過
③ 信任邊界不要相信瀏覽器送來的東西影片那條破了,已修
④ 安全鐵律例如「同一筆訂單只能開通一次」通過
⑤ 攻擊面對外的門有幾道、有沒有限流原本沒有,今天補上

05其他六項修補

這些不像影片那項那麼急,但都是實際存在的缺口。

一、差點被繞過:一個沒清乾淨的舊網址

修好影片漏洞、部署上線之後,我在收尾檢查時發現:你的文件寫著「舊網址已於 6/15 全部刪除」,但實際上還有三個活著,其中一個還停在兩個月前的舊版本——實測仍然在洩漏 19 支影片編號

也就是說,如果沒發現這個,今天所有的修補都可以被這個舊網址整個繞過。已關閉(現在打開會顯示 404)。

教訓:修完程式碼之後,一定要回頭確認「還有哪些入口指向舊版本」。這一步比修程式本身還關鍵。

二、資料庫的多餘鑰匙

你的資料庫有 11 張表,對「一般訪客」和「已登入會員」發了可以寫入資料的權限。目前寫不進去,因為還有另一道規則擋著——但擋住它的只剩這一道牆

你在 6 月就被這個組合咬過一次(會員可以自己把自己升級成管理員)。當時修了那一條,但其他表的多餘鑰匙沒一起收。今天全部收回了。

三、流量限制:擋掉惡意灌爆

原本主站完全沒有任何流量限制——有人寫個小程式每秒送 100 次結帳請求,你的資料庫和金流帳單就會爆掉。

保護的功能每分鐘上限每天上限為什麼設這個數字
結帳建單5 次30 次真人一分鐘按不到 5 次結帳
折扣碼試算10 次100 次試算會反覆按,放寬一些
課程資源下載10 次200 次一堂課的檔案數量有限

實測結果(連續呼叫 7 次):

第 1 次 → 放行   今日剩餘 29
第 2 次 → 放行   今日剩餘 28
第 3 次 → 放行   今日剩餘 27
第 4 次 → 放行   今日剩餘 26
第 5 次 → 放行   今日剩餘 25
第 6 次 → 擋下(60 秒後可重試)
第 7 次 → 擋下(60 秒後可重試)

刻意不限制的地方:綠界的付款通知。那是綠界主動打進來告訴你「客人付款了」的,如果限流,真實付款會被擋掉。它本身已有簽章驗證保護。

四、內容白名單(今天最花時間的一項)

這是一張「只准從這些地方載入東西、表單只准送去這些網址」的清單,附在網站每一次回應裡交給瀏覽器。就像大樓門口的訪客名單。

它的價值在於:就算哪天有壞東西進到你的頁面,它也送不出去——沒辦法把偷到的資料傳去別的伺服器,也沒辦法把你的付款表單改成送去假的收款頁。

這一項有一個會直接弄壞金流的地雷。你的結帳是「自動送出表單到綠界的網域」。名單如果漏掉綠界,所有付款會在送出的那一刻被瀏覽器擋掉,而且客人只會看到頁面沒反應,你完全不會收到錯誤通知。

所以我的做法是分兩階段,而不是一次開到底:

先只記錄不擋違規只寫進紀錄
不影響任何功能
量測有沒有誤擋10 個頁面 + 後台
+ 雙向對照測試
你實際刷一筆確認付款真的送得出去
才切成真的攔截今天 18:44 完成

為什麼「沒出現問題」不等於「沒問題」

我做了雙向對照測試,這是關鍵:

  • 把表單送去綠界沒有被記為違規 ✅
  • 把表單送去一個隨便的網域被記為違規 ✅

只做第一項是不夠的——「沒出現違規」也可能是因為這條規則根本沒生效。加上第二項才能分辨「它放行了綠界」和「它根本沒在看」。

五、六條安全標頭

包括:強制使用加密連線、禁止別人用外框把你的網站包起來做釣魚頁、禁止瀏覽器亂猜檔案類型、關閉網站用不到的相機麥克風權限等。

六、套件漏洞歸零

修復前:高風險漏洞4 個
修復後:高風險漏洞0 個

網站框架從 16.2.9 升到 16.3.3。這是小版本更新,不是大改版,但仍然實際重測了 10 個頁面加上你的真實刷卡。


06真實刷卡驗證:正式環境自己演了一次

今天傍晚你實際刷了一筆 NT$50。這是唯一能證明「金流沒被改壞」的方法,沒有替代方案。以下是從資料庫撈出來的完整紀錄。

18:29:58
試算折扣碼成功
18:31:28
建立訂單,金額 NT$50
18:33:41
付款成功
18:33:41
課程自動開通「外匯保證金初級玩家」
18:33:41
學員購買通知信送出
18:33:41
管理員新訂單通知送出(2 位)
18:33:43
綠界重複回傳,系統正確略過 ← 見下方說明

🎯 最後那一行是今天最好的證據

綠界會用兩條路通知你「客人付款了」:一條是把瀏覽器導回你的網站,另一條是伺服器直接通知。這兩條路幾乎同時到達。

今天的紀錄顯示:伺服器通知在瀏覽器那條路已經完成開通後 2 秒才進來,而系統正確認出這是重複的,直接略過

如果沒有這個機制,這一筆會被開通兩次、課程期限被多加一次、折扣碼被多算一次。這不是我測出來的,是正式環境自己跑出來的。

同時也驗證了流量限制真的接上正式流量——你操作的每一步都被記錄下來:

折扣碼試算  18:29:58
結帳        18:30:10
折扣碼試算  18:31:23
結帳        18:31:28

全程零警告、零嚴重錯誤。


07我自己在過程中犯的錯

報喜不報憂的報告沒有價值。這些錯全部都被抓出來並修正了,但你應該知道它們發生過——尤其是有幾個如果沒發現,會留下真正的問題。

我做錯什麼怎麼發現的影響
把錯的修法寫進了長期筆記
修 python3 的方法我寫了「放在某資料夾、一個檔案就好」——實際動手才發現資料夾沒有寫入權限,而且需要兩個檔案不是一個
真的動手做的時候連撞兩次牆 已回頭改正
否則下次會照著錯的做
說你的網站「沒有 middleware」
實際上有,只是新版框架把它改了名字叫 proxy
建立新檔案時系統報錯「已經有一個了」 影響輕微
但這個判斷曾寫進體檢結論
誤判正式網站「畫面壞掉了」
看到截圖排版怪異就先喊停
去量實際數值,發現是瀏覽器視窗被縮窄,顯示的是正常的手機版排版 虛驚一場
差點把開發模式的測試結果當成正式結果
開發模式量到「需要放寬某項限制」,如果照抄就會為了本機工具永久降低正式站的安全性
改用正式版本重測,發現那是開發模式特有的假訊號 已避免
這個如果沒發現會留下真的缺口
把自己的測試殘留當成程式 bug
測流量限制時 7 次全被擋,一度以為寫錯了
去查資料表,發現是前一次測試已經用掉 5 次額度,屬於正確行為 虛驚一場
誤報一個不存在的問題
說組合結帳頁不會顯示錯誤訊息
再查一次,訊息其實有顯示,只是寫在另一個檔案裡 已更正
多建了一個重複的設定檔
沒先查就新建,其實早就有一份
啟動時系統讀的是舊的那份 已清除
一度把既有問題當成自己造成的
正式站出現一個技術警告,我先前判斷「只是測試殘留」
兩個月前的舊版本做對照,證實舊版也有一模一樣的警告 既有問題
不是今天造成的

從這些錯誤裡整理出的三條原則:

  • 「給了方法」不等於「方法可行」——要驗到「動作真的能完成」,不是只驗「前提成立」。
  • 要量就量真正上線的那個版本——開發環境的測試結果會騙人。
  • 看到異常先量再喊——今天有三次「以為出事了」,查完全部都是誤判。

08如果出問題,怎麼退回去

每一項改動都可以還原。這些指令不用你自己記——把這一段給任何 AI 看,它就知道怎麼做。

要退回什麼怎麼做會不會有損失
整個網站退回今天之前Vercel 後台一鍵回滾到舊版本不會,舊版本都還留著
內容白名單(怕擋錯東西)CSP_ENFORCE 改回 false 重新部署不會,退回「只記錄不擋」
流量限制移除資料庫裡新增的那張表與函式不會,都是今天新增的
資料庫權限重新發放權限即可不會,一行指令
python3 修正刪掉新增的那兩個檔案不會
# 退回內容白名單(改完要重新部署)
# 檔案:proxy.ts
const CSP_ENFORCE = false;

# 重新部署
cd C:\Users\COSH\dev\course-site
npx vercel --prod --yes

一個要記得的新規則:內容白名單現在會真的攔東西。以後要加任何新的外部服務(新的分析工具、新的字型、換金流商),都必須先加進白名單,否則會被靜默擋掉——不會報錯,只是那個功能就是不會動。


09還沒處理的事

都不緊急,但你應該知道它們存在。

1. 影片本身仍然沒有「自我防衛能力」

今天堵掉的是「未登入就能拿到編號」這條路。但買了課的學員仍然拿得到自己那堂課的編號,理論上可以外流。

要根本解決,需要影片本身能認人(例如每次播放發一張會過期的通行證)。但我查證過:你的 Vimeo 方案做不到——這個功能只在企業方案,加購價約每年 2,000 美元。

現階段的決定:不處理。理由是你目前的學員數是個位數,花這筆錢不划算。三個回頭評估的時機:學員數破 100 / 發現實際外流跡象 / 要開更高價的課。

2. 一個技術警告(既有問題,非今天造成)

播放頁在正式站會出現一個技術警告。我用兩個月前的舊版本對照過,舊版也有一模一樣的警告,不是今天造成的。它不影響任何功能(系統會自己修正重畫),值得之後單獨排查。

3. 兩筆測試資料建議清掉

  • 一筆沒付款的訂單 AQ178817221056244(你第一次建單但沒完成的那筆)
  • 你今天建的 test2430 折價券還是啟用狀態——建議停用,免得外流

比照 6/16 清測試資料的做法即可。

4. Vercel 上累積了 19 個以上的舊部署

純整理事項,跟資安無關。但今天的教訓提醒我們:舊部署配上沒清乾淨的網址,就會變成繞過所有修補的後門。建議之後排一次清理。

Ctrl+E 切換 · Ctrl+S 存檔