Veritabanı sunucunuz ele geçirildiğinde, sadece veri kaybetmezsiniz; itibarınızı, müşteri güvenini ve çoğu zaman işinizi kaybedersiniz. PostgreSQL, açık kaynak dünyasının en güvenilir veritabanı sistemlerinden biri olmasına rağmen, varsayılan kurulum ayarları production ortamı için kesinlikle yeterli değildir. Bu rehberde, gerçek dünya saldırı senaryolarını göz önünde bulundurarak PostgreSQL’i katman katman nasıl sertleştireceğinizi ele alacağız.
Neden PostgreSQL Sertleştirme Şart?
Varsayılan PostgreSQL kurulumunu düşünün: postgres kullanıcısı şifresiz çalışıyor, dinleme adresi localhost ile sınırlı ama ağ yapılandırması değiştirildiğinde her yerden erişim açılabiliyor, pg_hba.conf dosyası trust metoduyla geliyor. Bu yapıyla bir production sunucusu ayağa kaldırmak, kasisiz bir kasada para saklamak gibi.
Shodan üzerinde yapılan araştırmalar, internet üzerinde erişilebilir durumda binlerce PostgreSQL sunucusunun olduğunu gösteriyor. Bunların büyük çoğunluğu ya default konfigürasyonla çalışıyor ya da basit şifreler kullanıyor. Siz bu kategoride olmayacaksınız.
İlk Adım: Sistem Seviyesi Güvenlik
PostgreSQL güvenliği veritabanı konfigürasyonuyla başlamadan önce işletim sistemi seviyesinde temeller atılmalı.
PostgreSQL Kullanıcısını İzole Edin
# postgres kullanıcısının shell erişimini kısıtlayın
usermod -s /bin/false postgres
# Sadece gerektiğinde su ile geçiş yapın
sudo -u postgres psql
# postgres kullanıcısının home dizin izinlerini kontrol edin
ls -la /var/lib/postgresql/
chmod 700 /var/lib/postgresql/
Veri Dizini İzinleri
# PostgreSQL veri dizini sadece postgres kullanıcısına ait olmalı
PGDATA=/var/lib/postgresql/14/main
ls -la $PGDATA
# drwx------ olmalı, başka bir şey kabul edilemez
chmod 700 $PGDATA
chown postgres:postgres $PGDATA
# Konfigürasyon dosyalarının izinleri
chmod 600 $PGDATA/postgresql.conf
chmod 600 $PGDATA/pg_hba.conf
chmod 600 $PGDATA/pg_ident.conf
Gereksiz Paketleri Kaldırın
PostgreSQL kurulumunda contrib paketlerinin tamamı gelmez ama yüklüyse kullanmadıklarınızı kaldırın. Her açık fonksiyon potansiyel bir saldırı yüzeyi oluşturur.
# Yüklü PostgreSQL paketlerini listeleyin
dpkg -l | grep postgresql
# Kullanmadığınız contrib paketlerini kaldırın
apt remove postgresql-contrib-14 # Gerçekten ihtiyacınız yoksa
# Aktif extension'ları kontrol edin
psql -U postgres -c "SELECT name, default_version, installed_version FROM pg_available_extensions WHERE installed_version IS NOT NULL;"
postgresql.conf Sertleştirmesi
Ana konfigürasyon dosyası güvenlik açısından kritik parametreler içeriyor. Her birini anlamlı bir şekilde yapılandırın.
Ağ Bağlantısı Kısıtlamaları
# postgresql.conf dosyasını düzenleyin
nano /etc/postgresql/14/main/postgresql.conf
Düzenlenecek parametreler:
- listen_addresses: Sadece gerekli IP adreslerini yazın.
*asla kullanmayın. Uygulama sunucunuzun IP’si neyse onu yazın, örneğin'192.168.1.10,127.0.0.1' - port: Default 5432’yi değiştirmek security through obscurity olsa da otomatik tarama araçlarını yavaşlatır. 5433 veya başka bir port düşünebilirsiniz
- max_connections: İhtiyacınızdan fazla bağlantı açık tutmayın. Çok fazla açık bağlantı kaynak tüketir ve potansiyel saldırı vektörü oluşturur
- superuser_reserved_connections: Superuser için rezerv bağlantı sayısını makul tutun, en az 3
# Konfigürasyon değişikliklerini uygulayın
systemctl reload postgresql
# veya
psql -U postgres -c "SELECT pg_reload_conf();"
SSL/TLS Zorunlu Kılın
Şifreli bağlantı olmadan ağ üzerinden geçen tüm veriler düz metin olarak okunabilir.
# SSL sertifikası oluşturun (production için Let's Encrypt veya kurumsal CA kullanın)
openssl req -new -x509 -days 365 -nodes
-out /etc/postgresql/14/main/server.crt
-keyout /etc/postgresql/14/main/server.key
-subj "/CN=db.sirketiniz.com"
chmod 600 /etc/postgresql/14/main/server.key
chown postgres:postgres /etc/postgresql/14/main/server.key
chown postgres:postgres /etc/postgresql/14/main/server.crt
postgresql.conf’ta SSL parametreleri:
- ssl:
onolarak ayarlayın - ssl_cert_file: Sertifika dosyasının yolu
- ssl_key_file: Private key dosyasının yolu
- ssl_min_protocol_version:
TLSv1.2minimum olmalı, mümkünseTLSv1.3 - ssl_ciphers: Güvenli cipher suite listesi,
HIGH:MEDIUM:+3DES:!aNULLbaşlangıç noktası olabilir
Loglama Parametreleri
Güvenlik olaylarını takip etmek için kapsamlı loglama şart.
# postgresql.conf loglama bölümü
log_destination = 'stderr'
logging_collector = on
log_directory = '/var/log/postgresql'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_age = 1d
log_rotation_size = 100MB
# Güvenlik açısından kritik log parametreleri
log_connections = on
log_disconnections = on
log_duration = on
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_statement = 'ddl' # Tüm DDL statement'larını logla
log_min_duration_statement = 1000 # 1 saniyeden uzun sorguları logla
pg_hba.conf ile Erişim Kontrolü
Bu dosya PostgreSQL’in kapı bekçisi. Yanlış yapılandırılmış bir pg_hba.conf, diğer tüm güvenlik önlemlerinizi anlamsız kılabilir.
# pg_hba.conf örnek güvenli yapılandırma
cat > /etc/postgresql/14/main/pg_hba.conf << 'EOF'
# TYPE DATABASE USER ADDRESS METHOD
# Unix domain socket bağlantıları sadece local
local all postgres peer
local all all peer
# IPv4 bağlantıları - SSL zorunlu, belirli IP'lerden
hostssl proddb appuser 192.168.1.10/32 scram-sha-256
hostssl all all 127.0.0.1/32 scram-sha-256
# IPv6
hostssl all all ::1/128 scram-sha-256
# Diğer tüm bağlantıları reddet
host all all 0.0.0.0/0 reject
EOF
Kritik noktalar:
- trust metodu: Kesinlikle production’da kullanmayın. Trust metodu şifre sormadan bağlantıya izin verir
- md5 yerine scram-sha-256: MD5 artık güvensiz kabul ediliyor. PostgreSQL 10 ve sonrası için scram-sha-256 kullanın
- hostssl:
hostyerinehostsslkullanmak SSL’i zorunlu kılar - /32 prefix: Tek IP adresi için /32 kullanın, geniş ağ aralıkları vermeyin
- Sıralama önemli: pg_hba.conf satırları yukarıdan aşağıya okunur, ilk eşleşen kural uygulanır
# Değişiklik sonrası pg_hba.conf'u test edin
pg_hba_conf_check () {
postgresql -t -c "SELECT pg_reload_conf();" 2>&1
}
psql -U postgres -c "SELECT pg_reload_conf();"
Kullanıcı ve Yetki Yönetimi
En Küçük Yetki Prensibi (Principle of Least Privilege) veritabanı güvenliğinin temel taşı.
Superuser Kullanımını Minimize Edin
# postgres superuser şifresini güçlü yapın
psql -U postgres
ALTER USER postgres PASSWORD 'Guc1u_R4nd0m_$ifre_Buraya!';
# Uygulama için ayrı kullanıcı oluşturun
CREATE USER appuser WITH PASSWORD 'UygulamaIcin_Ayri_Sifre!'
NOSUPERUSER
NOCREATEDB
NOCREATEROLE
NOREPLICATION;
# Sadece ihtiyaç duyulan veritabanına yetki verin
GRANT CONNECT ON DATABASE proddb TO appuser;
GRANT USAGE ON SCHEMA public TO appuser;
-- Sadece gerekli tablolara SELECT/INSERT/UPDATE
GRANT SELECT, INSERT, UPDATE ON TABLE orders, customers TO appuser;
-- DELETE yetkisi ayrı değerlendirin
-- Sequence'lar için ayrıca yetki
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO appuser;
Read-Only Kullanıcı Oluşturun
Raporlama ve analiz için ayrı bir read-only kullanıcı tanımlamak, hem güvenliği artırır hem de production verisini yanlışlıkla değiştirme riskini ortadan kaldırır.
psql -U postgres -d proddb << 'EOF'
-- Read-only kullanıcı
CREATE USER readonly_user WITH PASSWORD 'ReadOnly_Sifre_2024!';
-- Bağlantı izni
GRANT CONNECT ON DATABASE proddb TO readonly_user;
GRANT USAGE ON SCHEMA public TO readonly_user;
-- Sadece okuma
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO readonly_user;
-- Bu kullanıcının yazma yapmasını açıkça engelle
REVOKE CREATE ON SCHEMA public FROM readonly_user;
EOF
Gereksiz Public Yetkilerini Kaldırın
PostgreSQL 14 ve öncesinde public şemasına tüm kullanıcılar varsayılan olarak tablo oluşturabiliyordu. Bu büyük bir güvenlik açığı.
psql -U postgres << 'EOF'
-- Public şemasından create yetkisini kaldır
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
-- Tüm veritabanlarında bağlantı default'ını kaldır
REVOKE ALL ON DATABASE template1 FROM PUBLIC;
-- Gereksiz public yetkilerini kontrol et
SELECT grantee, privilege_type, table_schema, table_name
FROM information_schema.table_privileges
WHERE grantee = 'PUBLIC';
EOF
Tehlikeli Fonksiyonları Devre Dışı Bırakın
PostgreSQL bazı çok güçlü ve tehlikeli fonksiyonlar içeriyor. Bunların yetkisiz kullanıcılar tarafından çağrılması felaket olabilir.
psql -U postgres << 'EOF'
-- pg_read_file, pg_write_file gibi fonksiyonları appuser'dan kaldır
REVOKE EXECUTE ON FUNCTION pg_read_file(text) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION pg_read_file(text, bigint, bigint) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION pg_ls_dir(text) FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION pg_ls_dir(text, boolean, boolean) FROM PUBLIC;
-- COPY TO/FROM PROGRAM özelliğini kısıtlayın
-- postgresql.conf'a ekleyin
-- restrict_copy_program = on (bazı versiyonlarda)
-- dblink ve postgres_fdw kullanımına dikkat edin
-- Bunlar başka sunuculara bağlantı açabilir
EOF
Connection Pooling ile Güvenlik Katmanı
PgBouncer kullanmak, hem performans hem de güvenlik açısından avantaj sağlar. Gerçek veritabanı bağlantı bilgilerini uygulama katmanından gizler.
# PgBouncer kurulumu
apt install pgbouncer
# /etc/pgbouncer/pgbouncer.ini temel güvenlik yapılandırması
cat > /etc/pgbouncer/pgbouncer.ini << 'EOF'
[databases]
proddb = host=127.0.0.1 port=5432 dbname=proddb
[pgbouncer]
listen_addr = 192.168.1.20
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 200
default_pool_size = 25
server_tls_sslmode = require
client_tls_sslmode = require
client_tls_cert_file = /etc/pgbouncer/server.crt
client_tls_key_file = /etc/pgbouncer/server.key
EOF
systemctl enable pgbouncer
systemctl start pgbouncer
Güvenlik Denetimi ve Monitoring
Güvenlik sertleştirmesi tek seferlik bir iş değil. Sürekli monitoring ve denetim şart.
Şüpheli Aktiviteleri Tespit Edin
# Başarısız login denemelerini izleyin
tail -f /var/log/postgresql/postgresql-*.log | grep "authentication failed"
# Aktif bağlantıları gerçek zamanlı izleyin
psql -U postgres -c "
SELECT pid, usename, application_name, client_addr,
state, query_start, query
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY query_start;"
# Uzun süredir çalışan sorguları tespit edin
psql -U postgres -c "
SELECT pid, now() - query_start AS duration, usename, query
FROM pg_stat_activity
WHERE state = 'active'
AND now() - query_start > interval '5 minutes';"
Yetki Denetim Scripti
#!/bin/bash
# pg_security_audit.sh
DB_HOST="localhost"
DB_USER="postgres"
echo "=== PostgreSQL Güvenlik Denetimi ==="
echo "Tarih: $(date)"
echo ""
echo "--- Superuser Listesi ---"
psql -h $DB_HOST -U $DB_USER -c "
SELECT rolname, rolsuper, rolcreatedb, rolcreaterole, rolreplication
FROM pg_roles
WHERE rolsuper = true;"
echo "--- Şifresiz Kullanıcılar ---"
psql -h $DB_HOST -U $DB_USER -c "
SELECT rolname FROM pg_authid
WHERE rolpassword IS NULL AND rolcanlogin = true;"
echo "--- Public Yetkili Tablolar ---"
psql -h $DB_HOST -U $DB_USER -c "
SELECT table_schema, table_name, privilege_type
FROM information_schema.table_privileges
WHERE grantee = 'PUBLIC';"
echo "--- SSL Durumu ---"
psql -h $DB_HOST -U $DB_USER -c "SHOW ssl;"
echo "--- Aktif Bağlantı Sayısı ---"
psql -h $DB_HOST -U $DB_USER -c "
SELECT count(*) as total,
count(*) FILTER (WHERE ssl = true) as ssl_connections
FROM pg_stat_ssl
JOIN pg_stat_activity ON pg_stat_ssl.pid = pg_stat_activity.pid;"
Fail2ban ile Brute Force Koruması
# /etc/fail2ban/filter.d/postgresql.conf
cat > /etc/fail2ban/filter.d/postgresql.conf << 'EOF'
[Definition]
failregex = ^%(__prefix_line)sFATAL: password authentication failed for user .+$
^%(__prefix_line)sFATAL: no pg_hba.conf entry for host "<HOST>"
ignoreregex =
EOF
# /etc/fail2ban/jail.local'a ekleyin
cat >> /etc/fail2ban/jail.local << 'EOF'
[postgresql]
enabled = true
port = 5432
filter = postgresql
logpath = /var/log/postgresql/postgresql-*.log
maxretry = 5
bantime = 3600
findtime = 600
EOF
systemctl restart fail2ban
Yedekleme Güvenliği
Yedekler de saldırı hedefi olabilir. Şifrelenmiş yedek almayı alışkanlık haline getirin.
# Şifrelenmiş PostgreSQL yedek alma
pg_dump -U postgres -h localhost proddb |
gzip |
openssl enc -aes-256-cbc -pbkdf2 -iter 100000
-pass pass:$BACKUP_PASSWORD
> /backup/proddb_$(date +%Y%m%d).sql.gz.enc
# Yedeği geri yüklemek için
openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000
-pass pass:$BACKUP_PASSWORD
-in /backup/proddb_20240115.sql.gz.enc |
gunzip |
psql -U postgres -h localhost proddb
PostgreSQL Güncel Tutmak
Güvenlik yamaları zamanında uygulanmayan veritabanları bilinen açıklarla savunmasız kalır.
# Mevcut versiyon kontrolü
psql -U postgres -c "SELECT version();"
# Ubuntu/Debian güncelleme
apt update
apt list --upgradable | grep postgresql
apt upgrade postgresql-14
# Güncelleme sonrası servisi kontrol edin
systemctl status postgresql
pg_lsclusters
Gerçek Dünya Senaryosu: E-Ticaret Veritabanı Sertleştirmesi
Bir e-ticaret şirketinde üç farklı uygulama PostgreSQL kullanıyor: web uygulaması, raporlama sistemi ve ETL süreci. Her biri için farklı kullanıcı ve yetki yapısı kurguladık.
psql -U postgres << 'EOF'
-- Web uygulaması: sadece orders ve products tablolarına erişim
CREATE USER webapp_user WITH PASSWORD 'Web_App_Secure_2024!!' NOSUPERUSER NOCREATEDB;
GRANT CONNECT ON DATABASE ecommerce TO webapp_user;
GRANT USAGE ON SCHEMA public TO webapp_user;
GRANT SELECT, INSERT, UPDATE ON orders, order_items, customers TO webapp_user;
GRANT SELECT ON products, categories TO webapp_user;
-- Raporlama: sadece okuma, özel rapor şeması
CREATE USER report_user WITH PASSWORD 'Report_ReadOnly_2024!!' NOSUPERUSER NOCREATEDB;
CREATE SCHEMA reports;
GRANT CONNECT ON DATABASE ecommerce TO report_user;
GRANT USAGE ON SCHEMA reports TO report_user;
GRANT SELECT ON ALL TABLES IN SCHEMA reports TO report_user;
-- ETL: sadece staging tablolarına yazma
CREATE USER etl_user WITH PASSWORD 'ETL_Pipeline_2024!!' NOSUPERUSER NOCREATEDB;
CREATE SCHEMA staging;
GRANT CONNECT ON DATABASE ecommerce TO etl_user;
GRANT USAGE ON SCHEMA staging TO etl_user;
GRANT ALL ON ALL TABLES IN SCHEMA staging TO etl_user;
-- Hassas alanlara erişimi kısıtla (kart numaraları vb.)
REVOKE SELECT ON customers_payment_info FROM report_user;
REVOKE SELECT ON customers_payment_info FROM etl_user;
EOF
Bu yapıda bir SQL injection açığından etkilenen webapp_user, saldırganın diğer şemalara veya ödeme bilgilerine erişmesini engeller.
Sonuç
PostgreSQL güvenliği katmanlı bir yaklaşım gerektirir: işletim sistemi izinlerinden başlayıp ağ yapılandırması, kimlik doğrulama, yetkilendirme ve sürekli monitoring ile devam eder. Tek bir katmanın güvenli olması yeterli değil.
Özetlemek gerekirse kritik eylem maddeleri şunlar: Hiçbir zaman trust authentication kullanmayın, scram-sha-256’ya geçin. SSL’i hem sunucu hem istemci tarafında zorunlu kılın. Her uygulama için ayrı, minimum yetkili kullanıcı oluşturun. pg_hba.conf’u mümkün olduğunca kısıtlı tutun ve 0.0.0.0/0 gibi geniş aralıklardan kaçının. Loglama kapsamlı olsun ve bu logları düzenli olarak inceleyin. Fail2ban gibi araçlarla brute force saldırılarına karşı otomatik koruma ekleyin. Yedeklerinizi şifrelenmiş olarak saklayın.
Bu önlemleri uygulamak bir günlük çalışma gerektiriyor ama karşılığı, gece 3’te “veritabanınıza yetkisiz erişim tespit ettik” alarmıyla uyanmamak. Veritabanı güvenliğine harcanan her saat, olası bir ihlale harcayacağınız günlerin, haftaların önüne geçiyor. Yatırımın mantığı bu kadar basit.