Upgrade to Pro — share decks privately, control downloads, hide ads and more …

從 2026 年 3 月 Rails 安全更新看三個常見的設計陷阱

從 2026 年 3 月 Rails 安全更新看三個常見的設計陷阱

2026 年 3 月 23 日,Rails 一次釋出 7.2.3.1、8.0.4.1、8.1.2.1 三個版本,修補了多個 CVE,涵蓋 XSS、ReDoS、記憶體耗盡、路徑穿越、glob 注入等漏洞,是近年規模最大的一次。 本場演講不會逐一拆解 CVE,而是退一步看:這些漏洞之間是否藏著共同的設計陷阱?我會挑出最具代表性的幾個,歸納成三類:信任邊界錯置(內部狀態與外部輸入混用)、檔案系統 API 接受未過濾輸入(path traversal 與 glob injection)、以及「修一次不夠」的不完整修補。 每個陷阱會搭配實際漏洞程式碼與修補方式解說,並提供可立即套用的檢查清單。聽眾不需要資安背景,只要寫過 Rails 應用就能理解。

Avatar for cindyliu923

cindyliu923

August 08, 2026

Other Decks in Programming

Transcript

  1. COSCUP 2026 從 2026 年 3 看三個常 Rails 安全更新 的設計陷阱

    Three Common Design Pitfalls Behind Rails' March 2026 Security Update DEVCORE / COSCUP 2026 月 / 見 Cindy Liu
  2. 家好,我是 Cindy! Cindy Liu DEVCORE 開發 GitHub X 程師 cindyliu923

    cindyliu923 Blog cindyliu923.com 02 工 大 ABOUT ME
  3. THE SPARK 這則貼 ,是這場演講的起點 AI 掃描翻出了沉睡已久 的漏洞 「別忽視這 — Sam

    Saffron 波,你會後悔」 Discourse 共同創辦 · 2026 人 文 一 03
  4. 2026 / 03 / 23 · MONDAY Rails 次補了 7.2.3.1

    8.0.4.1 包 8.1.2.1 XSS · ReDoS · 記憶體耗盡 · 路徑穿越 · glob 注入 近年規模最 的 10 次 security issues 大 一 一 大 一 ↳ rubyonrails.org/2026/3/23/Rails-Versions-7-2-3-1-8-0-4-1-and-8-1-2-1... 04
  5. THE FULL LIST 這次的 10 個 CVE CVE 元件 類型

    CVE-2026-33167 Action Pack XSS CVE-2026-33168 Action View XSS CVE-2026-33169 Active Support ReDoS CVE-2026-33170 Active Support XSS CVE-2026-33176 Active Support DoS CVE-2026-33173 Active Storage Metadata CVE-2026-33195 Active Storage Path Traversal CVE-2026-33202 Active Storage Glob Injection CVE-2026-33174 Active Storage DoS CVE-2026-33658 Active Storage DoS ↳ discuss.rubyonrails.org/c/security-announcements/9 05
  6. FOCUS 先看這 個 元件 CVE 類型 CVE-2026-33167 Action Pack XSS

    CVE-2026-33168 Action View XSS CVE-2026-33169 Active Support ReDoS CVE-2026-33170 Active Support XSS CVE-2026-33176 Active Support DoS CVE-2026-33173 Active Storage Metadata CVE-2026-33195 Active Storage Path Traversal CVE-2026-33202 Active Storage Glob Injection CVE-2026-33174 Active—— Storage DoS Active Support 的 ReDoS 正則表達式的阻斷服務攻擊 CVE-2026-33658 Active Storage DoS 一 06
  7. 這個我今天不講 → 但明天有 整場專 聊 這 10 個裡的 CVE-2026-33169(Active Support

    ReDoS) 我不展開 —— 推薦這場: Kasa · 8/9( 門 一 日 ↳ coscup.org/2026/track/516?session=FYSGQ8 ) 13:30 · TR514 — 想深入 ReDoS 的明天別錯過 07
  8. FOCUS 今天聚焦這五個 CVE 元件 類型 CVE-2026-33167 Action Pack XSS CVE-2026-33168

    Action View XSS CVE-2026-33169 Active Support ReDoS CVE-2026-33170 Active Support XSS CVE-2026-33176 Active Support DoS CVE-2026-33173 Active Storage Metadata CVE-2026-33195 Active Storage Path Traversal CVE-2026-33202 Active Storage Glob Injection CVE-2026-33174 Active Storage DoS CVE-2026-33658 Active Storage DoS ↳ discuss.rubyonrails.org/c/security-announcements/9 3 個陷阱 5 個代表 歸納成 3 類 08
  9. 今天的三個陷阱 THE THREE PITFALLS A 檔案系統 API 接 user input

    限制要想兩層 內部狀態與外部輸入 path traversal 只堵 混在同 與 glob injection 永遠不夠 33195 · 33202 33174 · 33658 子 一 C 信任邊界錯置 33173 一 B 個盒 裡 個維度
  10. PITFALL A · CVE-2026-33173 信任邊界錯置 把「使 者輸入」和「程式內部狀態」放在同 個盒 裡 metadata:瀏覽器直接回報

    → 使 者可控 Browser → 瀏覽器選檔 跳過 Rails → Storage Rails 直傳儲存後端 只收 metadata Rails 只能相信瀏覽器回報的 metadata 子 一 用 用 10
  11. PITFALL A · THE BUG 問題:內部 flag 也能被塞 POST /rails/active_storage/direct_uploads

    { "blob": { "metadata": { "description": "my photo", // 以下是 Rails 內部 flag: "identified": true, "analyzed": true, "composed": true } } } 所謂 MIME 檢測 = 讀檔頭 magic bytes:PNG 89 50 4E 47 flag = true → 跳過 MIME 檢測 ↳ github.com/rails/rails/security/advisories/GHSA-qcfx-2mfw-w4cg → JPEG FF D8 FF 假 PNG 其實是 HTML PDF %PDF- → XSS 11
  12. PITFALL A · THE FIX Rails 怎麼修:filter 掉內部 flag #

    ActiveStorage::Blob PROTECTED_METADATA = %w(analyzed identified composed) def create_before_direct_upload!(...) metadata = filter_metadata(metadata) create! ..., metadata: metadata end def filter_metadata(metadata) metadata.without(*PROTECTED_METADATA) end ↳ github.com/rails/rails/commit/d9502f5 12
  13. PITFALL A · CHECKLIST 陷阱 A 我檢查 1 內部狀態與 user

    input 是否分離? 2 有 params.permit 3 「使 者不該能改」的欄位,有保護嗎? 名單, 不是整包塞進 model? 而 白 自 用 用 14
  14. PITFALL B · CVE-2026-33195 + 33202 檔案系統 API 接 user

    input 同 個 DiskService,兩種完全不同的攻擊 blob key DiskService 它當檔名。通常 Rails 產隨機 key —— 但有些 app 讓使 者影響它。 用 用 一 15
  15. PITFALL B · BUG #1 Path Traversal ① 攻擊:key 塞

    ../ 跳出 # path_for(key): 錄 blob key 拼出實體路徑 File.join(root, folder_for(key), key) # key 可能被污染 key = "../../../etc/passwd" File.join(root, folder_for(key), key) # => /etc/passwd ⚠ 目 用 ↳ github.com/rails/rails/security/advisories/GHSA-9xrj-h377-fr87 16
  16. PITFALL B · BUG #1 Path Traversal ② 修復程式碼 ——

    還少了關鍵的 def path_for(key) if key.split("/").intersect?(%w[. ..]) raise InvalidKeyError end path = File.expand_path(File.join(root, key)) # …還少了什麼? end ? 17 行 一 行 這段修復 還少了哪 ↳ github.com/rails/rails/security/advisories/GHSA-9xrj-h377-fr87 一 換你當 reviewer
  17. PITFALL B · WHY THAT LINE 字串比對 vs 正規化後比對 同樣是

    start_with?,為什麼 個中招、 個擋下? # 兩種寫法,只差在「比對前有沒有先正規化」 ❌ 比對原始字串 ✅ 先正規化再比對 path = File.join(root, key) path = File.expand_path(...) # ✓ 過關 path.start_with?(root) # 實際開的是 /etc/passwd ⚠ # ../.. 被攤平 → /etc/passwd path.start_with?(root+"/") 你檢查的字串,要和 OS 真正會開的路徑 # ✗ 擋下 致 —— 先 expand_path 正規化,再比對 ↳ github.com/rails/rails/commit/4933c1e 一 一 一 19
  18. PITFALL B · BUG #2 Glob Injection ① 攻擊:key 裡的萬

    字元被展開 Dir.glob(path_for("#{prefix}*")) 正常:prefix 是隨機 key # prefix 來 key 攻擊:prefix 塞了 * prefix = "abc123/" "#{prefix}*" => "abc123/*" prefix = "*" "#{prefix}*" => "**" # 前綴框住 → 只刪這 組 # 前綴消失 → 比對到全部 key 裡的 * 路穿過 File.join 都沒被處理,直到 Dir.glob 解讀樣式的那 自 20 一 用 一 一 ↳ github.com/rails/rails/commit/8c9676b 刻才引爆
  19. PITFALL B · BUG #2 Glob Injection ② 修復:進 Dir.glob

    前先跳脫萬 字元 def escape_glob_metacharacters(p) p.gsub(/[\[\]*?{}\\]/) { |c| "\\#{c}" } end # * ? [] {} 逐 ↳ github.com/rails/rails/commit/8c9676b 跳脫 一 用 21
  20. PITFALL B · COMPARE 同元件,兩種誤 Path Traversal Glob Injection ../

    * ? [ ] { } 跳出邊界 擴張匹配範圍 同 個 key、同 個 filesystem API —— 差別只在 key 裡藏了什麼 用 一 一 22
  21. PITFALL B · THE LESSON 使 者輸入交給 filesystem API 前

    先假設它是惡意的 這兩個 CVE 只影響地端 DiskService,且要應 把 user input 當成 blob key 用 用 23
  22. PITFALL B · CHECKLIST 陷阱 B 我檢查 1 有把 user

    input 拼進路徑嗎?(File.read/open/delete/join) 2 有 3 字串比對 vs 正規化後比對?前者擋不乾淨。 Dir.glob 嗎?pattern 含 user input 嗎? 自 用 24
  23. PITFALL C · CVE-2026-33174 + 33658 限制要想兩層 好的修補 次堵兩層 Range

    header proxy mode 代理下載,Range 讓 client 指定要哪段 bytes —— 有兩個維 度可被濫 。 用 一 25
  24. PITFALL C · 維度 單 range 太 1 → OOM

    Range: bytes=0- proxy 把整段載入記憶體 修法 路到檔尾 # unbounded, → 1GB 檔案配 1GB → streaming_chunk_max_size(預設 100MB)—— 只堵了「 」 小 大 26 一 大 一 ↳ github.com/advisories/GHSA-r46p-8f7g-vvvg 一 多送幾個就 OOM
  25. PITFALL C · 維度 range 數量太多 → 2 樣爆 Range:

    bytes=0-1,2-3,4-5,... 每個都 修法 、通過 限制 range) 樣打爆 CPU 與記憶體 + 數量 起堵 一 小 小 一 大 27 一 二 小 大 加總 streaming_max_ranges—— ↳ github.com/rails/rails/commit/bb78f8c 小 → (× 數千個
  26. PITFALL C · CHECKLIST 陷阱 C 我檢查 1 size limit

    能不能改 「數量」繞過? 2 rate limit 換個維度(IP/帳號/cookie)還擋得住? 3 修漏洞時,想過攻擊者換哪個維度繼續打嗎? 用 自 29
  27. 三個陷阱, 次複習 RECAP 信任邊界錯置 B 檔案系統 API 接 user input

    33195 · 33202 C 限制要想兩層 33174 · 33658 一 A 33173
  28. 完整檢查清單 A 信任邊界 B 檔案系統 API C 限制兩層 1 4

    user input 拼進路徑? 7 size limit 能 5 Dir.glob pattern 含 input? 8 rate limit 換維度擋得住? 6 字串比對 vs 正規化? 9 修補時想過第 內部狀態與 user input 分 離? 2 params.permit 3 保護不該被改的欄位? 名單? 數量繞過? 層? 白 二 31 用 用 TAKE A PHOTO 📸
  29. 那,怎麼知道該更新什麼? 別 的套件 的程式碼 bundler-audit Brakeman 比對 ruby-advisory-db 靜態分析,抓 SQL

    injection、 揪出有漏洞的 gem 版本 XSS、mass assignment bundle audit check --update bundle exec brakeman 更省事:Rails 7.2 起,新專案 CI 內建 Brakeman + Dependabot;Dependabot 預設每週檢查依賴更新 人 ↳ guides.rubyonrails.org/7_2_release_notes.html 己 自 TOOLING 33
  30. BUT IT'S NOT OVER 故事還沒結束 CVE-2026-41316 4 的 ERB 反序列化

    RCE 這顆在 Ruby 標準庫 ERB —— 升 Rails 沒 ,得升 Ruby 安全更新不是 次性的:框架、語 層都要顧 用 34 一 言 一 月 ↳ ruby-lang.org/en/news/2026/04/21/erb-cve-2026-41316/ 、標準庫,任何
  31. JUST DAYS AGO · 2026/07/29 上週,同 個 Active Storage 中

    CVE-2026-66066 · Critical CVSS 9.5 Active Storage variant(libvips)→ 任意檔案讀取 → RCE 修補:activestorage 7.2.3.2 / 8.0.5.1 / 8.1.3.1 · libvips ≥ 8.13 上傳惡意圖片 → 讀到 secret_key_base → 可 RCE、橫向移動 工 面 一 一 方 ↳ discuss.rubyonrails.org → CVE-2026-66066 攻擊細節與鑑識 具 35 又 官 同 個 Active Storage,不同攻擊 —— 這波真的還沒停 原本壓到 8/28 才公開細節,卻被搶先出現的 PoC 逼著提前全部公開
  32. FROM THE TRENCHES 我們現在,每週都在更新套件 Ruby 漏洞資料庫 ruby-advisory-db 每 新增筆數 222

    半年內 10 倍 135 18 25/08 漏洞揭露量暴增 50 35 這不是巧合 25/11 26/02 ↳ github.com/rubysec/ruby-advisory-db 26/05 26/06 月 37
  33. YOUR TURN — 舉 你的團隊,多久更新 下 次套件? ✋ ✋ ✋

    每週 每 每季以上 像我們 樣,緊追 固定節奏 AI 找洞越來越快 ——「頻繁更新」不再是選項, 出事才更新 是新常態 而 一 一 手 一 月 38
  34. DON'T FORGET 別忘了 Ruby 也要更新 Rails 版本 所屬系列 最低 Ruby

    版本 7.2.3.1 7.2.x Ruby ≥ 3.1.0 8.0.4.1 8.0.x Ruby ≥ 3.2.0 8.1.2.1 8.1.x Ruby ≥ 3.2.0 升 Rails 的同時,Ruby 版本也得跟上 ↳ guides.rubyonrails.org/upgrading_ruby_on_rails.html 39