---
title: "PostgreSQL SECURITY DEFINER vs INVOKER: Ne Zaman Hangisini Kullanmalı?"
description: "Supabase'de yazdığınız fonksiyon RLS'yi bypass mı ediyor? SECURITY DEFINER ve INVOKER arasındaki farkı, hangi durumda hangisini kullanacağınızı basitçe..."
date: 2026-04-12
category: guvenlik
tags: ["postgresql", "security-definer", "security-invoker", "supabase", "rls", "güvenlik"]
url: https://mikroerp.dev/blog/postgresql-security-definer-vs-invoker/
---

## Sorun: Fonksiyon Tüm Verileri Gösteriyor

Supabase'de Row Level Security (RLS) kurdunuz. Her kullanıcı sadece kendi şubesinin verilerini görüyor. Her şey güzel — ta ki bir fonksiyon yazana kadar:

```sql
CREATE FUNCTION toplam_stok_sayisi()
RETURNS integer AS $$
  SELECT COUNT(*) FROM v3_stock;
$$ LANGUAGE sql;
```

Bu fonksiyonu çağırdığınızda **tüm şubelerin** stok sayısını döndürüyor. RLS çalışmıyor!

Neden? Çünkü fonksiyonun güvenlik modu yanlış.

## İki Mod Var

### SECURITY INVOKER (Varsayılan — Güvenli)

Fonksiyon, **onu çağıran kullanıcının** yetkileriyle çalışır. Yani RLS kuralları geçerlidir:

```sql
CREATE FUNCTION benim_stoklarim()
RETURNS SETOF v3_stock
LANGUAGE sql
SECURITY INVOKER   -- Çağıran kişinin yetkileri geçerli
AS $$
  SELECT * FROM v3_stock;
$$;
```

Ahmet bu fonksiyonu çağırırsa → sadece Ahmet'in görebildiği satırlar döner.

### SECURITY DEFINER (Dikkatli Kullanın!)

Fonksiyon, **fonksiyonu oluşturan kişinin** (genelde süper yetkili `postgres`) yetkileriyle çalışır. RLS devre dışı kalır:

```sql
CREATE FUNCTION tum_stoklari_getir()
RETURNS SETOF v3_stock
LANGUAGE sql
SECURITY DEFINER   -- ⚠️ postgres yetkisiyle çalışır, RLS yok!
AS $$
  SELECT * FROM v3_stock;
$$;
```

Kim çağırırsa çağırsın → **tüm satırlar** döner.

## Basit Kural

```
%90 fonksiyonunuz → INVOKER olsun (RLS korunur)
%10 fonksiyonunuz → DEFINER gerekebilir (aşağıdaki durumlarda)
```

## Ne Zaman DEFINER Kullanılır?

| Senaryo | Neden DEFINER? |
|---------|---------------|
| Audit log yazma | Kullanıcı audit tablosuna yazamaz ama fonksiyon yazabilmeli |
| Tüm şubelerin toplamını gösterme | Yönetici raporu — toplam rakam gerekli |
| Sistem bakım işlemleri | Kullanıcı tetikleyebilmeli ama tüm veriye erişmemeli |

## DEFINER Kullanırken Güvenlik

DEFINER fonksiyonlarda güvenliği **siz** sağlamalısınız. RLS size yardımcı olmaz:

```sql
CREATE FUNCTION sube_ozet_raporu(hedef_sube text)
RETURNS TABLE(toplam_stok bigint, toplam_deger numeric)
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public   -- ← Güvenlik için zorunlu
AS $$
BEGIN
  -- 1. Yetki kontrolü: Bu kullanıcı bu şubeyi görebilir mi?
  IF NOT EXISTS (
    SELECT 1 FROM kullanici_subeleri
    WHERE kullanici_id = auth.uid()
    AND sube_kodu = hedef_sube
  ) THEN
    RAISE EXCEPTION 'Bu şubeye erişim yetkiniz yok';
  END IF;

  -- 2. Yetkili — veriyi getir
  RETURN QUERY
  SELECT COUNT(*)::bigint, SUM(miktar * birim_fiyat)
  FROM v3_stock
  WHERE depo = hedef_sube;
END;
$$;
```

**3 kritik kural:**
1. `SET search_path = public` — SQL injection koruması
2. Fonksiyon içinde yetki kontrolü yapın
3. Kullanıcı girdisini doğrudan SQL'e koymayın

## Mevcut Fonksiyonlarınızı Kontrol Edin

Veritabanınızdaki fonksiyonların hangisi DEFINER, hangisi INVOKER — bir bakın:

```sql
SELECT 
  proname AS fonksiyon_adi,
  CASE prosecdef 
    WHEN true THEN '⚠️ DEFINER' 
    ELSE '✅ INVOKER' 
  END AS guvenlik_modu
FROM pg_proc
JOIN pg_namespace ON pronamespace = pg_namespace.oid
WHERE nspname = 'public'
ORDER BY prosecdef DESC;
```

DEFINER olan fonksiyonlarınız varsa, gerçekten DEFINER olmaları gerektiğinden emin olun.

## Özet

- **INVOKER** = güvenli varsayılan. RLS çalışır, her kullanıcı kendi verisini görür.
- **DEFINER** = güçlü araç ama dikkatli kullanın. RLS bypass eder.
- DEFINER kullanıyorsanız, fonksiyon içinde kendiniz yetki kontrolü yapın.

Çoğu projede INVOKER yeterlidir. DEFINER sadece özel durumlarda gerekir.

---

*Bu yazı [AstaFlow Case Study](/case-study) serisinin bir parçasıdır.*