FixVibe

// docs / baas security / supabase rls scanner

Supabase RLS scanner: tìm các bảng thiếu hoặc bị hỏng bảo mật cấp dòng

Bảo mật cấp dòng (RLS) là thứ duy nhất ngăn cách dữ liệu khách hàng của bạn với internet khi bạn triển khai một ứng dụng dùng Supabase. Các công cụ AI lập trình tạo ra mã có hình dạng RLS — biên dịch được, triển khai được và âm thầm làm rò rỉ dữ liệu — như bảng được tạo mà không bật RLS, policy đọc dữ liệu nhưng không hạn chế gì, hoặc predicate so sánh một cột với chính nó. Bài viết này cho thấy một Supabase RLS scanner có thể chứng minh được gì từ bên ngoài, bốn dạng RLS bị hỏng xuất hiện trong các ứng dụng "vibe-code", và cách quét deployment của chính bạn trong chưa đầy một phút.

Một lượt quét RLS từ bên ngoài có thể chứng minh điều gì

Một lượt quét RLS thụ động chạy đối với endpoint PostgREST mà Supabase mở tại https://[project].supabase.co/rest/v1/. Nó chỉ sử dụng key anon có thể công bố — chính là key mà trình duyệt của bạn sử dụng — và thăm dò metadata danh sách bảng, các thao tác đọc ẩn danh và ghi ẩn danh. Nó không bao giờ xác thực với tư cách người dùng và không bao giờ chạm vào quyền service-role. Bất kỳ thứ gì nó có thể làm, một kẻ tấn công chưa xác thực trên internet cũng có thể làm.

Từ bên ngoài cơ sở dữ liệu, một scanner có thể xác nhận với độ tin cậy cao những điều sau:

  • RLS bị tắt trên một bảng. PostgREST trả về các dòng cho một lệnh SELECT ẩn danh khi RLS bị tắt hoặc khi một policy cho phép điều đó. Trường hợp nào cũng là một phát hiện.
  • Vai trò ẩn danh có thể liệt kê các bảng. Một lệnh GET /rest/v1/ với anon key trả về schema OpenAPI cho mọi bảng mà vai trò anon có bất kỳ đặc quyền nào. Các ứng dụng do AI tạo thường cấp USAGE trên schema và SELECT trên mọi bảng, làm lộ toàn bộ bản đồ schema ngay cả khi RLS từ chối các thao tác đọc thực tế.
  • Vai trò ẩn danh có thể insert. Một POST thăm dò với một dự đoán về hình dạng cột sẽ thành công nếu RLS không có policy INSERT nào từ chối — ngay cả khi SELECT đã bị khóa.
  • Service-role key có trong bundle trình duyệt. Liền kề với RLS: nếu scanner tìm thấy SUPABASE_SERVICE_ROLE_KEY hoặc bất kỳ JWT nào có role: service_role trong bundle JavaScript, RLS trở nên vô nghĩa — người sở hữu key đó bỏ qua mọi policy.

Một lượt quét từ bên ngoài không thể chứng minh điều gì

Hãy thành thật về giới hạn của scanner. Một lượt quét RLS từ bên ngoài không thể đọc bảng pg_policies, các file migration hay predicate chính xác của bất kỳ policy nào. Nó suy luận từ hành vi hộp đen, có nghĩa là đôi khi nó sẽ báo một phát hiện mà hóa ra là dữ liệu công khai có chủ đích (bảng bản tin marketing, danh mục sản phẩm công khai). Báo cáo của FixVibe đánh dấu những trường hợp này là độ tin cậy trung bình khi scanner không thể phân biệt ý định — hãy xem lại tên bảng và quyết định.

Bốn dạng RLS bị hỏng mà các công cụ AI tạo ra

Khi bạn để Cursor, Claude Code, Lovable hoặc Bolt làm việc với Supabase, bốn dạng RLS bị hỏng tương tự xuất hiện trên hàng nghìn ứng dụng. Mỗi dạng đều vượt qua type-check, biên dịch và triển khai được:

Dạng 1: RLS chưa bao giờ được bật

Chế độ thất bại phổ biến nhất. Migration tạo bảng nhưng developer (hoặc công cụ AI) quên ALTER TABLE ... ENABLE ROW LEVEL SECURITY. PostgREST vui vẻ phục vụ toàn bộ bảng cho bất kỳ ai có anon key. Sửa: ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY; ALTER TABLE public.[name] FORCE ROW LEVEL SECURITY;. FORCE là bắt buộc — không có nó, chủ bảng (và bất kỳ vai trò nào có quyền sở hữu bảng) sẽ bỏ qua RLS.

sql
ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.[name] FORCE  ROW LEVEL SECURITY;

Dạng 2: RLS được bật, không có policy

Một chế độ thất bại tinh vi hơn. RLS được bật nhưng không có policy nào được viết. Mặc định trong PostgreSQL là từ chối, vì vậy người dùng đã xác thực không thấy gì — và developer thêm USING (true) để ứng dụng hoạt động, điều này cho phép tất cả mọi người đọc tất cả. Sửa: viết một policy giới hạn theo auth.uid(): CREATE POLICY "select_own" ON public.[name] FOR SELECT USING (auth.uid() = user_id); và một policy tương ứng cho INSERT/UPDATE/DELETE.

sql
CREATE POLICY "select_own"
  ON public.[name]
  FOR SELECT
  USING (auth.uid() = user_id);

Dạng 3: Policy so sánh cột với chính nó

A copy-paste artefact. The developer writes <code>USING (user_id = user_id)</code> — which is always true — instead of <code>USING (auth.uid() = user_id)</code>. Type-checks pass; the policy permits every row. <strong>Fix:</strong> always compare a column to a function call (<code>auth.uid()</code>, <code>auth.jwt()->>'org_id'</code>, etc.), never to itself or to a constant.

Dạng 4: Policy trên SELECT nhưng không trên INSERT/UPDATE

Developer khóa thao tác đọc nhưng quên thao tác ghi. Policy RLS là theo từng lệnh. FOR SELECT chỉ bảo vệ thao tác đọc; một client ẩn danh vẫn có thể INSERT nếu không có policy nào từ chối. Sửa: viết một policy cho mỗi lệnh, hoặc dùng FOR ALL với mệnh đề USINGWITH CHECK rõ ràng.

Cách Supabase RLS scanner của FixVibe hoạt động

Check baas.supabase-rls chạy theo ba giai đoạn, mỗi giai đoạn có mức độ tin cậy rõ ràng:

  1. Giai đoạn 1 — fingerprint. Scanner crawl ứng dụng đã triển khai, phân tích bundle JavaScript của nó và trích xuất URL dự án Supabase cùng anon key từ cấu hình runtime. Không đoán DNS, không brute force — nó đọc những gì trình duyệt đọc.
  2. Giai đoạn 2 — phát hiện schema. Một lệnh GET /rest/v1/ duy nhất với anon key trả về schema OpenAPI cho mọi bảng mà vai trò anon có thể thấy. Scanner ghi lại tên bảng nhưng không đọc dữ liệu hàng ở giai đoạn này.
  3. Giai đoạn 3 — thăm dò đọc và ghi. Với mỗi bảng được phát hiện, scanner phát một SELECT ẩn danh với limit=1. Nếu các dòng trả về, RLS đang cho phép. Scanner dừng tại đó — nó không liệt kê các dòng, không phân trang, không sửa đổi dữ liệu. Thăm dò INSERT được kiểm soát phía sau xác minh quyền sở hữu tên miền và opt-in rõ ràng; chúng không bao giờ chạy đối với mục tiêu chưa xác minh.

Mỗi phát hiện đi kèm với URL yêu cầu chính xác, trạng thái phản hồi, hình dạng phản hồi (chỉ header) và tên bảng. Prompt sửa lỗi AI ở cuối phát hiện là một khối SQL sao chép-dán mà bạn chạy trong Supabase SQL editor.

Phải làm gì khi scanner tìm thấy thứ gì đó

Mỗi phát hiện RLS là một trường hợp khẩn cấp ở môi trường runtime. Endpoint PostgREST công khai bị kẻ tấn công quét trong vài phút. Quy trình khắc phục mang tính máy móc:

  1. Kiểm toán mọi bảng. Chạy SELECT schemaname, tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public'; trong Supabase SQL editor. Bất kỳ dòng nào có rowsecurity = false đều là vấn đề.
  2. Bật RLS trên mọi bảng public. Mặc định dùng ENABLE ROW LEVEL SECURITYFORCE ROW LEVEL SECURITY trên mọi bảng được tạo — biến nó thành mẫu migration.
  3. Viết policy theo từng lệnh. Đừng dùng FOR ALL USING (true). Viết các policy rõ ràng cho SELECT, INSERT, UPDATE, DELETE — mỗi cái giới hạn theo auth.uid() hoặc một cột org-id từ auth.jwt().
  4. Xác minh bằng tài khoản thứ hai. Đăng ký với tư cách người dùng khác, thử đọc bản ghi của người dùng khác qua REST API trực tiếp. Nếu phản hồi là 200, policy đã hỏng.
  5. Quét lại. Sau khi áp dụng bản sửa, chạy lại lượt quét FixVibe với cùng URL. Phát hiện baas.supabase-rls sẽ biến mất.
sql
-- Audit every table for missing RLS. Run in the Supabase SQL editor.
SELECT schemaname, tablename, rowsecurity
FROM   pg_tables
WHERE  schemaname = 'public'
ORDER  BY rowsecurity, tablename;

So sánh với các scanner khác

Hầu hết các công cụ DAST chung (Burp Suite, OWASP ZAP, Nessus) không biết PostgREST là gì. Chúng sẽ crawl ứng dụng của bạn, bỏ qua đường dẫn /rest/v1/ và báo cáo về các trang HTML mà chúng hiểu được. SnykSemgrep là công cụ phân tích tĩnh — chúng tìm các file migration trong repo của bạn có thiếu lệnh gọi RLS, nhưng không thể chứng minh cơ sở dữ liệu đã triển khai đang bị cấu hình sai. FixVibe nằm trong khoảng trống đó: thụ động, hiểu BaaS, tập trung vào những gì một kẻ tấn công chưa xác thực có thể chứng minh từ URL công khai.

Câu hỏi thường gặp

Scanner có đọc hoặc sửa đổi dữ liệu của tôi không?

Không. Các lượt quét thụ động phát tối đa một lệnh SELECT ... limit=1 cho mỗi bảng được phát hiện để xác nhận xem RLS có cho phép đọc ẩn danh không. Scanner ghi lại hình dạng phản hồi, không phải nội dung dòng. Thăm dò INSERT, UPDATE và DELETE được kiểm soát phía sau xác minh quyền sở hữu tên miền và không bao giờ chạy đối với mục tiêu chưa xác minh.

Cái này có hoạt động nếu dự án Supabase của tôi bị tạm dừng hoặc dùng tên miền tùy chỉnh không?

Các dự án bị tạm dừng trả về 503 cho mọi yêu cầu — scanner báo cáo dự án không truy cập được. Tên miền tùy chỉnh hoạt động miễn là ứng dụng đã triển khai vẫn tải SDK client Supabase trong trình duyệt; scanner trích xuất URL dự án từ bundle dù sao đi nữa.

Điều gì xảy ra nếu anon key của tôi được xoay vòng hoặc publishable key thay đổi?

Hãy chạy lại lượt quét. Scanner trích xuất lại key từ bundle hiện tại trong mỗi lần chạy. Việc xoay vòng chỉ làm vô hiệu hóa báo cáo trước đó, không phải trạng thái policy của cơ sở dữ liệu.

Scanner có kiểm tra mô hình publishable-key mới của Supabase (<code>sb_publishable_*</code>) không?

Có. Bộ phát hiện nhận diện cả JWT anon kế thừa và các key sb_publishable_* mới hơn, và xử lý chúng như nhau — cả hai đều được thiết kế để công khai và đều để RLS là tuyến phòng thủ duy nhất.

Các bước tiếp theo

Chạy một lượt quét FixVibe miễn phí với URL production của bạn — check baas.supabase-rls được bật trên mọi gói kể cả gói miễn phí. Để hiểu sâu hơn về những gì khác có thể rò rỉ từ một dự án Supabase, xem Supabase service role key bị lộ trong JavaScriptDanh sách kiểm tra bảo mật storage bucket Supabase. Để có cái nhìn tổng quát trên tất cả các nhà cung cấp BaaS, đọc BaaS misconfiguration scanner.

// quét bề mặt baas của bạn

Tìm bảng dữ liệu mở trước khi người khác tìm thấy.

Dán vào một URL production. FixVibe sẽ liệt kê các nhà cung cấp BaaS mà ứng dụng của bạn kết nối tới, fingerprint các endpoint công khai của họ và báo cáo những gì một client chưa xác thực có thể đọc hoặc ghi. Miễn phí, không cần cài đặt, không cần thẻ.

  • Gói miễn phí — 3 lượt quét/tháng, không cần thẻ khi đăng ký.
  • Fingerprinting BaaS thụ động — không cần xác minh tên miền.
  • Supabase, Firebase, Clerk, Auth0, Appwrite và nhiều nữa.
  • Prompt sửa lỗi bằng AI trên mỗi phát hiện — dán lại vào Cursor / Claude Code.
Chạy quét BaaS miễn phí

không cần đăng ký

Supabase RLS scanner: tìm các bảng thiếu hoặc bị hỏng bảo mật cấp dòng — Docs · FixVibe