DBAtlas · Veritabanı operasyon atlası

Güvenlik sıkılaştırma: SQL veritabanları (Oracle, PostgreSQL, MySQL, SQL Server)

Belirti

Amaç: İlişkisel veritabanlarını CIS-tarzı sıkılaştır — varsayılan hesaplar, güçlü parola politikası, en az yetki, ağ kısıtlama, TLS, denetim (audit) ve şifreleme (TDE).

1. Varsayılan/gereksiz hesapları kaldır veya kilitle, örnek şemaları sil

Kurulumla gelen varsayılan hesaplar ve örnek şemalar bilinen saldırı yüzeyidir. Kullanılmayanları kilitle veya kaldır; üst düzey/servis hesaplarını yeniden adlandır.

Oracle

-- Kullanılmayan varsayılan hesapları kilitle ve süresini doldur:
ALTER USER SCOTT ACCOUNT LOCK PASSWORD EXPIRE;
ALTER USER HR ACCOUNT LOCK PASSWORD EXPIRE;
-- Kilitli/açık hesapları denetle:
SELECT username, account_status FROM dba_users ORDER BY account_status;
-- Örnek şemaları kaldır: $ORACLE_HOME/demo/schema/drop_sch.sql

PostgreSQL

-- Varsayılan superuser 'postgres' rolünü koru; yerine kaldır/rename ETME.
-- Rolleri denetle:
SELECT rolname, rolsuper, rolcanlogin FROM pg_roles ORDER BY rolsuper DESC;
-- Gereksiz login rollerini kaldır:
DROP ROLE IF EXISTS test_user;
-- Örnek/test veritabanlarını sil: DROP DATABASE IF EXISTS test;

MySQL

# İnteraktif sıkılaştırma sihirbazı (anonim kullanıcı, test DB, uzak root'u kaldırır):
mysql_secure_installation
-- Manuel: anonim ve test hesaplarını kaldır:
DROP USER IF EXISTS ''@'localhost';
DROP USER IF EXISTS ''@'%';
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db LIKE 'test%'; FLUSH PRIVILEGES;

SQL Server

-- 'sa' hesabını devre dışı bırak ve yeniden adlandır:
ALTER LOGIN sa DISABLE;
ALTER LOGIN sa WITH NAME = [sa_disabled_acct];
-- Guest kullanıcısını kısıtla — yalnızca KULLANICI veritabanlarında
-- (master, tempdb ve msdb'de guest açık kalmalıdır; tempdb/msdb'de kapatmak sorun çıkarır):
USE appdb;
REVOKE CONNECT FROM guest;
-- Örnek DB'leri kaldır: DROP DATABASE AdventureWorks;

2. Güçlü parola politikası ve süre sınırı uygula

Zayıf/asla değişmeyen parolalar en yaygın giriş noktasıdır. Deneme sınırı, karmaşıklık ve parola ömrü uygula; parolaları güçlü hash ile sakla.

Oracle

-- Profil ile deneme sınırı, ömür ve karmaşıklık:
CREATE PROFILE app_profile LIMIT
  FAILED_LOGIN_ATTEMPTS 5
  PASSWORD_LIFE_TIME 90
  PASSWORD_REUSE_MAX 10
  PASSWORD_VERIFY_FUNCTION ora12c_verify_function;
ALTER USER app_user PROFILE app_profile;

PostgreSQL

-- Güçlü hash algoritması (SCRAM):
SHOW password_encryption;              -- 'scram-sha-256' olmalı
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
-- Karmaşıklık için passwordcheck uzantısını yükle:
-- shared_preload_libraries = 'passwordcheck'
-- Ömür: ALTER ROLE app_user VALID UNTIL '2026-12-31';

MySQL

-- validate_password bileşenini kur ve politika ayarla:
INSTALL COMPONENT 'file://component_validate_password';
SET PERSIST validate_password.policy = 'STRONG';
SET PERSIST validate_password.length = 14;
-- Deneme sınırı ve ömür:
ALTER USER app_user PASSWORD EXPIRE INTERVAL 90 DAY
  FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 1;

SQL Server

-- Login'de Windows parola politikası ve süre dolumunu zorunlu kıl:
ALTER LOGIN app_user WITH CHECK_POLICY = ON, CHECK_EXPIRATION = ON;
-- Politika/expiration durumunu denetle:
SELECT name, is_policy_checked, is_expiration_checked
FROM sys.sql_logins;

3. En az yetki: PUBLIC/geniş yetkileri geri al, rol tabanlı yetki ver

Herkese (PUBLIC) verilmiş geniş yetkiler yatay hareketi kolaylaştırır. Yetkileri geri al, roller oluştur ve yalnızca gerekeni ver.

Oracle

-- Tehlikeli PUBLIC yetkilerini geri al:
REVOKE EXECUTE ON UTL_HTTP FROM PUBLIC;
REVOKE EXECUTE ON UTL_FILE FROM PUBLIC;
REVOKE EXECUTE ON DBMS_SCHEDULER FROM PUBLIC;
-- Rol tabanlı yetki:
CREATE ROLE app_read;
GRANT SELECT ON app.orders TO app_read;
GRANT app_read TO app_user;

PostgreSQL

-- Şemadaki varsayılan PUBLIC yetkilerini geri al:
REVOKE ALL ON DATABASE appdb FROM PUBLIC;
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
-- Rol tabanlı, salt-okunur erişim:
CREATE ROLE app_read NOLOGIN;
GRANT USAGE ON SCHEMA app TO app_read;
GRANT SELECT ON ALL TABLES IN SCHEMA app TO app_read;
GRANT app_read TO app_user;

MySQL

-- Global geniş yetkileri denetle ve geri al:
SHOW GRANTS FOR app_user;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM app_user;
-- Rol tabanlı, nesne düzeyinde yetki (MySQL 8+):
CREATE ROLE app_read;
GRANT SELECT ON appdb.* TO app_read;
GRANT app_read TO app_user;
SET DEFAULT ROLE app_read TO app_user;

SQL Server

-- public rolüne verilmiş fazla yetkiyi geri al:
REVOKE SELECT ON SCHEMA::dbo FROM public;
-- Rol tabanlı yetki:
CREATE ROLE app_read;
GRANT SELECT ON SCHEMA::app TO app_read;
ALTER ROLE app_read ADD MEMBER app_user;
-- Sunucu düzeyinde: sabit sunucu rollerini (sysadmin) sınırla.

4. Ağ/erişim kısıtla — yalnızca bilinen istemciler bağlansın

Veritabanını dünyaya açık dinlemekten kaçın. Dinleme adresini kısıtla, host/IP bazlı erişim kuralları uygula ve güvenlik duvarıyla portu sınırla.

Oracle

# listener.ora / sqlnet.ora — geçerli düğüm kontrolü:
TCP.VALIDNODE_CHECKING = YES
TCP.INVITED_NODES = (10.0.0.5, 10.0.0.6)
TCP.EXCLUDED_NODES = (0.0.0.0/0)
# Değişiklikten sonra: lsnrctl reload

PostgreSQL

# postgresql.conf — sadece belirli arayüzü dinle:
listen_addresses = '10.0.0.10,localhost'
# pg_hba.conf — host/IP + güçlü kimlik doğrulama:
hostssl appdb app_user 10.0.0.0/24 scram-sha-256
host    all      all       0.0.0.0/0      reject
# Yeniden yükle: SELECT pg_reload_conf();

MySQL

# my.cnf — yalnızca belirli arayüze bağlan:
[mysqld]
bind-address = 10.0.0.10
-- Host bazlı kullanıcı (yalnız uygulama sunucusundan):
CREATE USER 'app_user'@'10.0.0.5'
  IDENTIFIED BY '****' REQUIRE SSL;
-- Uzak root'a asla '%' host verme.

SQL Server

# TCP portunu güvenlik duvarıyla sınırla (yalnız uygulama subnet'i):
New-NetFirewallRule -DisplayName 'SQL-1433' -Direction Inbound `
  -Protocol TCP -LocalPort 1433 -RemoteAddress 10.0.0.0/24 -Action Allow
-- Dinlenen adresleri denetle:
SELECT * FROM sys.dm_tcp_listener_states;
-- Kullanılmıyorsa SQL Browser servisini kapat.

5. TLS/şifreli bağlantı zorunlu kıl

Ağdaki trafik pasif dinlemeye açıktır. Sunucu sertifikası tanımla ve istemcilerin şifreli bağlanmasını zorunlu kıl.

Oracle

# sqlnet.ora — TCPS/TLS (sunucu sertifikası wallet'ta):
WALLET_LOCATION = (SOURCE=(METHOD=FILE)(METHOD_DATA=(DIRECTORY=/etc/oracle/wallet)))
SSL_CLIENT_AUTHENTICATION = FALSE
SSL_VERSION = 1.2
# listener.ora'da yalnız TCPS (port 2484) dinle. Not: SQLNET.ENCRYPTION_SERVER TLS değil, Native Network Encryption'dır.

PostgreSQL

# postgresql.conf:
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file  = 'server.key'
ssl_min_protocol_version = 'TLSv1.2'
# pg_hba.conf'te 'hostssl' satırı kullan; düz 'host' ile şifresiz bağlantıyı reddet.

MySQL

# my.cnf:
[mysqld]
require_secure_transport = ON
ssl_cert = /etc/mysql/server-cert.pem
ssl_key  = /etc/mysql/server-key.pem
ssl_ca   = /etc/mysql/ca.pem
-- Kullanıcı düzeyinde: ALTER USER app_user REQUIRE SSL;

SQL Server

-- Bağlantı şifrelemesini zorunlu kıl (SQL Server Configuration Manager):
-- Protocols for MSSQLSERVER > Properties > Force Encryption = Yes
-- Sertifika ata; sonra servisi yeniden başlat.
-- Durumu denetle:
SELECT session_id, encrypt_option FROM sys.dm_exec_connections;

6. Denetim (audit) aç — kim ne yaptı görülebilsin

Yetkili erişim ve şüpheli işlemleri izlemek için denetim kaydı şart. Oturum açma, yetki değişikliği ve hassas nesne erişimini logla.

Oracle

-- Unified Auditing ile politika oluştur ve etkinleştir:
CREATE AUDIT POLICY sec_pol
  ACTIONS LOGON, LOGOFF, ALTER USER, GRANT, CREATE USER, DROP USER;
AUDIT POLICY sec_pol;
-- Kayıtları gör:
SELECT * FROM unified_audit_trail ORDER BY event_timestamp DESC;

PostgreSQL

# pgaudit uzantısı ile:
# postgresql.conf:
shared_preload_libraries = 'pgaudit'
pgaudit.log = 'ddl, role, write'
-- Uzantıyı oluştur:
CREATE EXTENSION pgaudit;
-- log_connections = on, log_disconnections = on da açılmalı.

MySQL

-- Enterprise/Percona audit_log eklentisini yükle:
INSTALL PLUGIN audit_log SONAME 'audit_log.so';
SET PERSIST audit_log_policy = 'ALL';
-- MariaDB: server_audit eklentisi
-- INSTALL SONAME 'server_audit'; SET GLOBAL server_audit_logging=ON;

SQL Server

-- Server Audit oluştur ve başlat:
CREATE SERVER AUDIT sec_audit
  TO FILE (FILEPATH = 'C:\SQLAudit\');
ALTER SERVER AUDIT sec_audit WITH (STATE = ON);
CREATE SERVER AUDIT SPECIFICATION sec_spec
  FOR SERVER AUDIT sec_audit
  ADD (FAILED_LOGIN_GROUP), ADD (DATABASE_ROLE_MEMBER_CHANGE_GROUP)
  WITH (STATE = ON);

7. Veri şifreleme (at-rest / TDE) uygula

Disk, yedek veya dosya çalınırsa veri okunamamalı. Sütun/tablespace/veritabanı düzeyinde durağan veri şifrelemesi (TDE) etkinleştir.

Oracle

-- Transparent Data Encryption (keystore + tablespace):
ADMINISTER KEY MANAGEMENT CREATE KEYSTORE '/etc/oracle/wallet'
  IDENTIFIED BY "WalletPwd1";
ADMINISTER KEY MANAGEMENT SET KEY IDENTIFIED BY "WalletPwd1" WITH BACKUP;
CREATE TABLESPACE sec_ts DATAFILE '/u01/sec01.dbf' SIZE 100M
  ENCRYPTION USING 'AES256' DEFAULT STORAGE(ENCRYPT);

PostgreSQL

-- Yerleşik blok TDE yoktur; iki yaygın yaklaşım:
-- 1) Sütun düzeyinde pgcrypto:
CREATE EXTENSION pgcrypto;
INSERT INTO t(ssn) VALUES (pgp_sym_encrypt('123-45', 'anahtar'));
SELECT pgp_sym_decrypt(ssn, 'anahtar') FROM t;
-- 2) Dosya sistemi/blok şifreleme (LUKS) veya EDB/Cybertec TDE derlemesi.

MySQL

# InnoDB tablespace şifreleme — keyring BİLEŞENİ (8.0.24+; 8.4'te keyring_file eklentisi kaldırıldı)
# 1) mysqld ikilisinin dizininde global manifest: mysqld.my
{ "components": "file://component_keyring_file" }
# 2) plugin_dir içinde: component_keyring_file.cnf
{ "path": "/var/lib/mysql-keyring/component_keyring_file", "read_only": false }
# 3) Sunucuyu yeniden başlat; doğrula:
-- SELECT * FROM performance_schema.keyring_component_status;
-- Tabloyu şifrele:
ALTER TABLE app.orders ENCRYPTION = 'Y';
-- Yeni tablolar için: SET PERSIST default_table_encryption = ON;
# 8.0.24 öncesi (yalnızca 8.0): early-plugin-load = keyring_file.so + keyring_file_data
# UYARI: keyring dosyasını veri dizininden AYRI ve güvenli biçimde yedekleyin;
# keyring kaybolursa şifreli tablolar ve yedekleri kalıcı olarak okunamaz.

SQL Server

-- Transparent Data Encryption (DEK + sertifika) — anahtar ve sertifika master'da olmalı:
USE master;
CREATE MASTER KEY ENCRYPTION BY PASSWORD = '<GucluParola1>';
CREATE CERTIFICATE tde_cert WITH SUBJECT = 'TDE Cert';
-- ZORUNLU: sertifikayı özel anahtarıyla hemen yedekle ve sunucu dışında sakla.
-- Bu yedek olmadan sunucu kaybında şifreli DB ve yedekleri geri YÜKLENEMEZ.
BACKUP CERTIFICATE tde_cert TO FILE = 'D:\guvenli\tde_cert.cer'
  WITH PRIVATE KEY (FILE = 'D:\guvenli\tde_cert.pvk',
    ENCRYPTION BY PASSWORD = '<CertYedekParola1>');
USE appdb;
CREATE DATABASE ENCRYPTION KEY
  WITH ALGORITHM = AES_256 ENCRYPTION BY SERVER CERTIFICATE tde_cert;
ALTER DATABASE appdb SET ENCRYPTION ON;
-- İlerleme: SELECT DB_NAME(database_id), encryption_state, percent_complete FROM sys.dm_database_encryption_keys;

8. Yamaları güncel tut ve gereksiz özellikleri kapat

Bilinen açıklar en çok sömürülen risktir. Düzenli güvenlik yaması uygula; kullanılmayan protokol, eklenti ve özellikleri devre dışı bırak (saldırı yüzeyini küçült).

Oracle

-- Yüklü sürüm ve yamaları denetle:
SELECT version_full FROM v$instance;
-- Quarterly Critical Patch Update (CPU) uygula: OPatch/opatchauto
-- Kullanılmayan bileşenleri kaldır (ör. XML DB, APEX) ve
-- external procedure (extproc) listener'ını kapat.

PostgreSQL

# Sürümü ve minor yamayı denetle:
SELECT version();
# Paket yöneticisiyle güncel minor sürüme yükselt (ör. 16.x en son).
# Kullanılmayan uzantıları kaldır: DROP EXTENSION IF EXISTS ...;
# postgresql.conf: kullanılmayan dil/PL uzantılarını yükleme.

MySQL

-- Sürümü denetle: SELECT VERSION();
-- LTS/güvenlik güncellemesine yükselt (8.0.x/8.4 LTS).
-- Yerel dosya okumayı kapat:
SET PERSIST local_infile = OFF;
-- Kullanılmayan eklentileri kaldır: UNINSTALL PLUGIN ...;

SQL Server

-- Ürün sürümü/patch seviyesini denetle:
SELECT SERVERPROPERTY('ProductVersion'), SERVERPROPERTY('ProductLevel');
-- En güncel Cumulative Update (CU) uygula.
-- Kullanılmayan özellikleri kapat (sp_configure ile):
EXEC sp_configure 'xp_cmdshell', 0; RECONFIGURE;
EXEC sp_configure 'Ole Automation Procedures', 0; RECONFIGURE;
DBAtlas'ta aç →