deniz.in

Piyasalar

Hava durumu

Hava durumu yükleniyor

· kaynak dev.to (home feed)

Geliştirici, doğru Supabase RLS politikalarından geçen altı veri sızıntısını anlattı

dev.to'da yayınlanan çok kiracılı bir satış noktası uygulaması deneyiminde, satır bazında doğru olmalarına rağmen row-level-security politikalarının yakalayamadığı altı gerçek güvenlik açığı ve bunları sonunda ortaya çıkaran katalog kontrolleri detaylandırılıyor.

Geliştirici, doğru Supabase RLS politikalarından geçen altı veri sızıntısını anlattı

Supabase üzerinde çok kiracılı bir satış noktası sistemi işleten bir geliştirici, yaklaşık altı hafta içinde üç inceleme boyunca keşfedilen altı güvenlik açığını dev.to'da birinci ağızdan anlattı. Bunların her biri, yazıldığı haliyle doğru olan satır seviyesi güvenlik (RLS) politikalarından geçti. Temel argüman şu: RLS'yi etkinleştirmek tek bir savunma katmanıdır; Postgres ayrıcalık sisteminin üzerinde ve PostgREST'nin — Supabase'in veritabanının önüne koyduğu üretilmiş API'nin — altında yer alır ve sızıntılar bu katmanlar arasındaki boşluklarda ortaya çıkar.

Doğru politikaların yine de veri sızdırdığı altı yol

  1. Yalnızca anon rolünden EXECUTE'yi geri almak hiçbir işe yaramaz. Postgres, her yeni fonksiyonda PUBLIC'e EXECUTE yetkisi verir ve Supabase'in anon rolü PUBLIC'ten miras aldığı için, rolün kendi yetkisini kaldırmak miras alınan yetkiye dokunmaz; Postgres de hiçbir uyarı vermez. Çözüm, hem public hem anon üzerinden yetkiyi geri alıp ardından authenticated'a execute vermektir. Trigger fonksiyonları, çalışmak için hiçbir zaman EXECUTE'e ihtiyaç duymadıkları halde aynı varsayılan yetkiyi alır; çünkü Postgres bunları tablo işleminin bir parçası olarak çalıştırır. Yazar, bir incelemede açığa çıkmış trigger fonksiyonları bulduğunu, ilk grubu düzeltirken iki tane daha oluştuğunu bildiriyor.

  2. Kolon seviyesinde geri alınan yetkiler, tablo seviyesindeki veriler tarafından sessizce yutulur. Bir rolün tüm tabloda SELECT yetkisi varsa, tek bir kolondaki SELECT yetkisini geri almak hiçbir etki yaratmaz ve hata vermez. Çare, tablo geneli yetkiyi kaldırıp her role yalnızca ihtiyaç duyduğu kolonları vermektir. Bedeli bilinçlidir: select * çalışmayı bırakır ve her yeni kolonun hem yetkiye hem de sorgulara eklenmesi gerekir.

  3. Yeni kolonlar okuma ve yazmada farklı davranır. Taze bir kolondaki okumalar yetki verilene kadar engellenli kalırken, yazmalar yetki geri alınıncaya kadar başarılı olur. Yazar okumaları kolon kolon kısıtlamış ama tablo seviyesinde bir UPDATE yetkisini yerinde bırakmıştı; böylece bir tarayıcı oturumu, yeni eklenen bir fatura sayacını hatasız biçimde 54'ten 1'e sıfırlayabildi — vergi faturası dizisini sessizce yeniden başlatarak. (business_id, invoice_number) üzerinde bir trigger ve unique index bu açığı kapattı.

  4. RLS'yi okumada atlatan bir view, yazmada da atlatır. Postgres 15 ve sonrasında, security_invoker = true ile oluşturulmadıkça bir view sahip haklarıyla çalışır. Bu nedenle tek bir kısıtlı kolonu açığa çıkarmak için kurulmuş bir view, RLS'nin engelleyeceği verileri döndürdü — ve basit bir tek tablolu view otomatik olarak güncellenebilir olduğundan PostgREST bu view üzerinde INSERT, UPDATE ve DELETE'yi de açığa çıkardı. Gerçek bir çalışan hesabıyla yapılan testte, doğrudan delete sıfır satır döndürürken view üzerinden yapılan delete bir satır sildi. Kiracı kimliğini koruyan bir trigger view üzerinden hâlâ tetiklendi ama hiçbir şey silmeleri kapsamıyordu; bu yüzden çözüm, view üzerindeki tüm yetkileri geri alıp yalnızca SELECT vermek oldu.

  5. auth.role() kullanıcıyı tanımlar, bir yazının kaynağını değil. auth.role() = 'authenticated' ile korunmuş bir trigger, uygulamanın kendi satış yolunu da engellerdi; çünkü auth.role() JWT claim'lerini okur ve bu claim'ler bir SECURITY DEFINER fonksiyon içinde değişmez. current_user ise değişir: PostgREST authenticated olarak çalışırken, postgres'in sahip olduğu bir definer fonksiyonun içinde postgres olur. Tarayıcı yazmalarını incelenmiş sunucu tarafı koddan ayırmak ikinci kontrolü gerektirir.

  6. RLS politikaları satırı doğrular, satırın işaret ettiğini değil. Kiracılar arası okuma yapabilen bir admin rolü üzerinden hareket eden yazarın kodu, başka bir kiracıya ait bir ürüne, kendi kiracı kimliği damgalı bir stok partisi iliştirdi. Politika bunu doğru biçimde onayladı; çünkü yalnızca partinin çağıranın kiracısına ait olup olmadığını sordu — işaret edilen ürünün ait olup olmadığını hiç sormadı. İki tabloyu birleştiren satırların her iki tarafı kapsayan politikalara ihtiyacı vardır; yazar, partinin, ürünün ve deponun aynı kirıcıyı paylaştığını ileri süren bir trigger ekledi.

Sorunları sonunda yakalayan ne oldu

Gönderiye göre politikeri okumak altı açığın hiçbirini bulamadı. Üç pratik buldu. Kataloğu — pg_proc, pg_policies, pg_class ve information_schema.role_table_grants — her migration'dan sonra çalıştırılan salt-okunur bir betikle sorgulamak, SQL editöründe oluşturulmuş terk edilmiş bir SECURITY DEFINER fonksiyonu yakaladı: anon tarafından çağrılabilen, bir maliyet kolonuna yazan ve yalnızca var olmayan bir tabloyu referans aldığı için henüz istismar edilmemiş bir fonksiyon. JWT claim'leri ayarlayarak gerçek bir düşük ayrıcalıklı kullanıcıyı taklit etmek ve her tablodaki satırları saymak, bir mağaza sahibinin e-posta adresini ve bekleyen bir PIN'i yaklaşık iki dakikada kasiyer seviyesi hesaplara açığa çıkardı. Yazar ayrıca, migration'ların yaptığını iddia ettiğine değil veritabanının gerçek durumuna güvenmeyi ve SQL editöründe yapılan geçici çalışmaları oluşturuldukları oturumda silmeyi öğütüyor; çünkü bunlar hiçbir incelemeden geçmez ve hiçbir diff'te görünmez.

Neden önemli

RLS, Supabase ekosisteminde kiracı izolasyonuna varsayılan yanıt haline geldi ve bu anlatı, doğru politikaların gerekli ama hiçbir şekilde yeterli olmadığını gösteriyor. Anlatılan hata modları Postgres temelleridir — varsayılan yetkiler, yetki önceliği, view sahipliği semantiği, oturum değişkenleri — ve Postgres tabanlı her API bunlara yakalanabilir; ama PostgREST'nin tabloları, view'ları ve fonksiyonları otomatik açığa çıkarması her birini tarayıcıdan erişilebilir bir uç noktaya dönüştürüyor. Pratik dersler Supabase'yi aşar: tasarlanan şemayı değil sistem kataloğunu denetleyin, en düşük ayrıcalıklı gerçek kullanıcınız olarak test edin ve her yeni fonksiyon, view ve kolonu rutin bir şema değişikliği değil bir güvenlik kararı olarak değerlendirin.

  • #supabase
  • #postgresql
  • #security
  • #multi-tenancy
  • #row-level-security

İlgili yazılar