API 金鑰放前端安全嗎?前端祕密與 Supabase RLS 圖解
瀏覽器是使用者自己的電腦,送到那裡的程式碼和資料,使用者都能打開來看、改了再送回來。這頁用兩台機器說明,祕密金鑰為什麼只能放在伺服器,以及可以公開的 Supabase 金鑰,為什麼還要配 RLS 才擋得住人。
送到瀏覽器的東西,每個訪客都拿得到
請 AI 幫你串 OpenAI 時,它常把金鑰寫成 NEXT_PUBLIC_OPENAI_KEY 或 VITE_OPENAI_KEY。這兩種前綴的用途就是讓前端讀得到,Next.js 和 Vite 會在建置時,把值直接寫進送給瀏覽器的 JS 檔。點下面四個步驟,看金鑰放在兩個地方的差別。
有些金鑰本來就該公開:Supabase 的兩種金鑰
Supabase 讓前端直接讀寫資料庫,所以它發兩種金鑰給你,一種給瀏覽器用,一種只能留在伺服器。舊的 anon、service_role 金鑰還能用,Supabase 預計 2026 年底前淘汰。
| 項目 | Publishable key | Secret key |
|---|---|---|
| 開頭 | sb_publishable_ | sb_secret_ |
| 舊名稱 | anon | service_role |
| 可以放哪裡 | 網頁、App、公開的程式碼 | 只能放伺服器 |
| 能做什麼 | 只碰得到 RLS 允許的資料 | 繞過 RLS,整個資料庫都能讀寫 |
publishable key 像貼在大樓門口的大門密碼,誰都進得了大廳。你能打開哪一格信箱,看的是每一格自己的鎖,也就是 RLS(Row Level Security,列層級安全)。資料庫回傳每一筆資料之前,會先檢查發出請求的這個人能不能看這一筆。
每一格都要上鎖:RLS 怎麼擋住別人的資料
下面這面信箱牆是一張資料表,每一格是一筆資料,你住 102 號。先關著 RLS 讀自己的信,再把號碼改成 105,然後一次全部讀出來;最後打開 RLS,同樣的請求再送一次。
改個號碼就讀到別人的資料,叫做越權存取(IDOR)。OWASP 2025 年版的十大網站風險,第一名仍是存取控制失效。RLS 的規則要寫成「只給本人」,例如 using ((select auth.uid()) = user_id);只檢查有沒有登入不夠,登入的 A 一樣讀得到 B 的資料。
在 Supabase 後台的 Table Editor 建的表,預設會開 RLS;用 SQL 建的表要自己加 alter table 表名 enable row level security,再寫政策。開了 RLS 卻一條政策都沒寫,從前端誰都讀不到,你自己的帳號也一樣。
重點回顧
- 1前端沒有祕密送到瀏覽器的檔案,訪客都能打開。NEXT_PUBLIC_ 和 VITE_ 開頭的變數會在建置時寫進這些檔案。
- 2祕密留在伺服器前端只送請求,伺服器收到後自己帶金鑰去呼叫外部服務。
- 3公開的金鑰要配每一格的鎖Supabase 的 publishable key 可以公開,前提是每張表都開 RLS,規則寫成「只給本人」。