跳到主要內容
wen aidev

API 金鑰放前端安全嗎?前端祕密與 Supabase RLS 圖解

瀏覽器是使用者自己的電腦,送到那裡的程式碼和資料,使用者都能打開來看、改了再送回來。這頁用兩台機器說明,祕密金鑰為什麼只能放在伺服器,以及可以公開的 Supabase 金鑰,為什麼還要配 RLS 才擋得住人。

送到瀏覽器的東西,每個訪客都拿得到

請 AI 幫你串 OpenAI 時,它常把金鑰寫成 NEXT_PUBLIC_OPENAI_KEY 或 VITE_OPENAI_KEY。這兩種前綴的用途就是讓前端讀得到,Next.js 和 Vite 會在建置時,把值直接寫進送給瀏覽器的 JS 檔。點下面四個步驟,看金鑰放在兩個地方的差別。

伺服器瀏覽器
目前狀態金鑰位置:瀏覽器收到的 JS 檔
前端瀏覽器(玻璃櫃)後端伺服器(保險箱)工具DevTools(放大鏡)
步驟 1 / 4金鑰跟著網頁一起送進瀏覽器用 NEXT_PUBLIC_ 或 VITE_ 開頭的環境變數把金鑰帶進前端,建置時這個值會被直接寫進送給瀏覽器的 JS 檔,等於把鑰匙放進玻璃櫃。
已經放上去的金鑰,刪掉程式碼不夠,舊版的 JS 檔和 git 紀錄裡都還找得到。先到服務後台撤銷那把金鑰、換一把新的,再把新金鑰放到伺服器。這種外洩很常見,GitGuardian 統計 2025 年公開 GitHub 程式碼裡新外洩的祕密有 2,865 萬組,其中 AI 服務的金鑰約 127 萬組,比 2024 年多 81%。

有些金鑰本來就該公開:Supabase 的兩種金鑰

Supabase 讓前端直接讀寫資料庫,所以它發兩種金鑰給你,一種給瀏覽器用,一種只能留在伺服器。舊的 anon、service_role 金鑰還能用,Supabase 預計 2026 年底前淘汰。

項目Publishable keySecret key
開頭sb_publishable_sb_secret_
舊名稱anonservice_role
可以放哪裡網頁、App、公開的程式碼只能放伺服器
能做什麼只碰得到 RLS 允許的資料繞過 RLS,整個資料庫都能讀寫

publishable key 像貼在大樓門口的大門密碼,誰都進得了大廳。你能打開哪一格信箱,看的是每一格自己的鎖,也就是 RLS(Row Level Security,列層級安全)。資料庫回傳每一筆資料之前,會先檢查發出請求的這個人能不能看這一筆。

每一格都要上鎖:RLS 怎麼擋住別人的資料

下面這面信箱牆是一張資料表,每一格是一筆資料,你住 102 號。先關著 RLS 讀自己的信,再把號碼改成 105,然後一次全部讀出來;最後打開 RLS,同樣的請求再送一次。

// 選一個請求送出
101102103104105106回傳給你的資料
資料庫回應還沒送出請求
你的102 號的門牌與信外洩被拿出來的別人的信
你是 102 號住戶,publishable key 讓你進得了大廳。選一個請求送出去,看哪幾格會打開。

改個號碼就讀到別人的資料,叫做越權存取(IDOR)。OWASP 2025 年版的十大網站風險,第一名仍是存取控制失效。RLS 的規則要寫成「只給本人」,例如 using ((select auth.uid()) = user_id);只檢查有沒有登入不夠,登入的 A 一樣讀得到 B 的資料。

2025 年 3 月,研究者 Matt Palmer 掃描用 Lovable 做出來的 1,645 個專案,其中 170 個專案、303 個 API 端點因為 RLS 沒設好,不用登入就能讀寫整張表,外洩的有 email、電話、住址、付款紀錄,還有存在資料庫裡的其他 API 金鑰。這個漏洞編號 CVE-2025-48757。那些專案的 publishable key 公開沒有錯,錯在每一格沒上鎖。

在 Supabase 後台的 Table Editor 建的表,預設會開 RLS;用 SQL 建的表要自己加 alter table 表名 enable row level security,再寫政策。開了 RLS 卻一條政策都沒寫,從前端誰都讀不到,你自己的帳號也一樣。

重點回顧

  1. 1前端沒有祕密送到瀏覽器的檔案,訪客都能打開。NEXT_PUBLIC_ 和 VITE_ 開頭的變數會在建置時寫進這些檔案。
  2. 2祕密留在伺服器前端只送請求,伺服器收到後自己帶金鑰去呼叫外部服務。
  3. 3公開的金鑰要配每一格的鎖Supabase 的 publishable key 可以公開,前提是每張表都開 RLS,規則寫成「只給本人」。

隨堂檢測

1. 你在 Vercel 設了 NEXT_PUBLIC_OPENAI_KEY,程式碼沒有把它印出來,也沒有 commit 到 GitHub。這把金鑰安全嗎?

提示:想想建置完成後,這個值會出現在哪些檔案裡。

2. 你的 orders 表已經開了 RLS,規則寫成「登入的人都能讀」。使用者 A 登入後,把請求裡的訂單編號改成 B 的,會發生什麼?

提示:這條規則檢查的是「有沒有登入」,還是「是不是本人」?

參考資料