MySQL güvenliği söz konusu olduğunda, birçok sunucu yöneticisi yalnızca güçlü bir parola düşünür. Ancak gerçek şu ki, MySQL'in varsayılan kurulumu, ele alınmadığı takdirde sunucunuzu saldırılara açık hale getiren birkaç ciddi güvenlik açığı içerir. Anonim kullanıcı, açık uzaktan bağlantı ve ihtiyaçtan fazla yetkiye sahip kullanıcılar, birçok üretim sunucusunda görülen üç yaygın sorundur. Bu makalede, bu sorunları adım adım nasıl çözeceğinizi ve güvenli, dayanıklı bir veritabanına nasıl sahip olacağınızı öğreneceksiniz.
MySQL'in varsayılan kurulumda güvenliği neden zayıftır?
MySQL kurulduktan sonra varsayılan olarak localhost üzerinde ve root kullanıcısıyla (parolasız veya basit parolayla) çalışır. Ayrıca, kurulum betiği, herkesin kimlik doğrulaması olmadan veritabanına bağlanabilmesi için boş adlı bir anonim kullanıcı oluşturur. Bu durum geliştirme ortamında kabul edilebilir olabilir, ancak üretim sunucusunda güvenlik açısından bir felakettir.
MySQL'e yönelik birçok başarılı saldırı, yazılım hatalarından değil, yanlış yapılandırmadan kaynaklanır. Saldırgan, basit bir port taramasıyla MySQL hizmetini 3306 portunda bulur ve anonim kullanıcı etkinse veya root'un zayıf bir parolası varsa, iş tamamdır. Bu nedenle MySQL güvenliği için ilk adım, varsayılan kurulumu temizlemektir.
Sunucunun mevcut durumunu kontrol etme
Herhangi bir değişiklik yapmadan önce mevcut durumu kontrol edin. SSH ile sunucuya bağlanın ve aşağıdaki komutu çalıştırın:
mysql -u root -p
Ardından kullanıcı listesini görmek için şu sorguyu çalıştırın:
SELECT user, host, authentication_string FROM mysql.user;
Çıktı genellikle farklı host'lara (localhost, 127.0.0.1, ::1) sahip root kullanıcısını ve boş adlı (user='') bir kullanıcıyı içerir. Bu boş kullanıcı, kaldırılması gereken anonim kullanıcıdır.
Anonim kullanıcıyı kaldırma ve varsayılan veritabanlarını temizleme
Anonim kullanıcı, herhangi bir host'tan bağlanan herkesin parolasız giriş yapmasına izin verir. Bu, MySQL 3306 portunda dışarıdan erişilebilirse, herkesin girebileceği anlamına gelir. Bu kullanıcıyı kaldırmak için mysql ortamında aşağıdaki komutu çalıştırın:
DROP USER ''@'localhost';
DROP USER ''@'hostname';
Host adını tam olarak bilmiyorsanız, önceki sorguyu kullanın ve boş kullanıcıya karşılık gelen host'u bulun. Ardından DROP komutunu aynı host ile çalıştırın.
Anonim kullanıcıyı kaldırdıktan sonra, varsayılan test ve test\_% veritabanlarını da silin. Bu veritabanları varsayılan olarak tüm kullanıcılar tarafından erişilebilir ve disk doldurma veya kötüye kullanım için kullanılabilir:
DROP DATABASE IF EXISTS test;
DROP DATABASE IF EXISTS test\_%;
Son olarak, değişiklikleri uygulayın:
FLUSH PRIVILEGES;
Yaygın hata: FLUSH PRIVILEGES komutunu unutmak
mysql.user tablosunda veya GRANT/REVOKE komutlarında herhangi bir değişiklik yaptıktan sonra, MySQL'in yetki tablolarını yeniden yüklemesi için FLUSH PRIVILEGES çalıştırılmalıdır. Bunu yapmazsanız, değişiklikler hizmet yeniden başlatılana kadar uygulanmaz ve anonim kullanıcının hâlâ etkin olduğu durumda işinizin bittiğini düşünebilirsiniz.
MySQL'e uzaktan bağlantıyı sınırlama
MySQL güvenliği konusundaki en önemli kararlardan biri, hizmetin hangi adreste dinleyeceğidir. Uygulamanız aynı sunucuda çalışıyorsa (örneğin, PHP-FPM ve MySQL aynı sunucuda), uzaktan bağlantıya gerek yoktur ve MySQL'i yalnızca localhost'a bağlamalısınız.
MySQL'in ana yapılandırma dosyası genellikle /etc/mysql/mysql.conf.d/mysqld.cnf (Ubuntu'da) veya /etc/my.cnf (CentOS'ta) konumunda bulunur. bind-address satırını bulun ve aşağıdaki gibi değiştirin:
bind-address = 127.0.0.1
Bu satır yoksa, [mysqld] bölümüne ekleyin. Değişiklikten sonra hizmeti yeniden başlatın:
sudo systemctl restart mysql
Şimdi aşağıdaki komutla MySQL'in yalnızca localhost'ta dinlediğini kontrol edin:
sudo netstat -tlnp | grep 3306
Çıktı yalnızca 127.0.0.1:3306 içermelidir. 0.0.0.0 veya genel IP adresini görüyorsanız, hâlâ dışarıdan erişilebilir durumdadır.
Gerçekten uzaktan bağlantıya ihtiyacınız varsa
Bazı mimarilerde (örneğin, merkezi bir veritabanına bağlanan birden fazla uygulama sunucusu) uzaktan bağlantı gereklidir. Bu durumda, portu tamamen açmak yerine şunları yapın:
- 0.0.0.0 yerine, bind-address'e sunucunun özel IP adresini yazın.
- Güvenlik duvarında (iptables veya ufw) yalnızca uygulama sunucularının IP'lerine izin verin.
- Bağlantıyı standart olmayan bir portta çalıştırmayın; bu gerçek bir güvenlik sağlamaz ve yalnızca karmaşıklık yaratır.
- Uzaktan bağlantı için trafiğin şifrelenmesi amacıyla mutlaka SSL/TLS'yi etkinleştirin.
Unutmayın ki her uzaktan bağlantı, saldırı yüzeyini artırır. Kaçınmanın bir yolu varsa, kaçının.
Minimum erişimli kullanıcı oluşturma (Least Privilege ilkesi)
MySQL güvenliği konusundaki altın kurallardan biri, her uygulamanın veya geliştiricinin yalnızca gerçekten ihtiyaç duyduğu erişimlere sahip olmasıdır. Uygulamaların root kullanıcısıyla bağlanması büyük bir hatadır. Uygulamanız hacklenirse, saldırgan root erişimiyle tüm veritabanlarını silebilir.
Sınırlı bir kullanıcı oluşturmak için önce uygulamanızın hangi erişimlere ihtiyaç duyduğuna karar verin. Tipik bir web uygulaması yalnızca belirli bir veritabanında SELECT, INSERT, UPDATE ve DELETE işlemlerine ihtiyaç duyar. Aşağıdaki komut, bu erişim düzeyine sahip bir kullanıcı oluşturur:
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'YourStrongPassword!2024';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;
Bu komutta:
'app_user'@'localhost', bu kullanıcının yalnızca sunucunun kendisinden bağlanabileceği anlamına gelir.myapp_db.*, erişimin yalnızca myapp_db veritabanına ve tüm tablolarına olduğu anlamına gelir.- GRANT komutu yalnızca dört temel işlemi yetkilendirir.
Uygulamanız tablo oluşturma veya yapı değiştirme ihtiyacı duyuyorsa (örneğin, geliştirme aşamasında), ALTER ve CREATE erişimlerini de ekleyebilirsiniz, ancak üretim ortamında bunu yapmayın. Yapı taşıma işlemleri için DDL erişimine sahip ayrı bir kullanıcı kullanın ve işiniz bittiğinde onu silin.
Bir kullanıcının erişimlerini kontrol etme
Kullanıcının fazladan erişimi olmadığından emin olmak için aşağıdaki komutu kullanın:
SHOW GRANTS FOR 'app_user'@'localhost';
Çıktı yalnızca tanımladığınız GRANT komutunu içermelidir. GRANT ALL PRIVILEGES veya USAGE ON *.* gibi bir şey görüyorsanız, kullanıcının genel erişimi var demektir ve düzeltilmelidir.
Yaygın hata: host'ta wildcard kullanmak
Bazı geliştiriciler kolaylık olması için kullanıcıyı 'app_user'@'%' şeklinde oluşturur. Bu, kullanıcının herhangi bir adresten bağlanabileceği anlamına gelir. Uygulamanız aynı sunucudaysa, mutlaka localhost kullanın. Uzaktan bağlantı gerekiyorsa, % yerine uygulama sunucusunun tam IP adresini yazın:
CREATE USER 'app_user'@'192.168.1.50' IDENTIFIED BY 'YourStrongPassword!2024';
Bu, parola sızdırılsa bile saldırganın yalnızca belirli bir IP'den bağlanabilmesini sağlar.
Root parolasını güçlendirme ve parola politikaları
MySQL'deki root kullanıcısının güçlü ve benzersiz bir parolası olmalıdır. Hâlâ varsayılan veya zayıf bir parola kullanıyorsanız, değiştirin:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewVeryStrongPassword!2024';
FLUSH PRIVILEGES;
MySQL 8, varsayılan olarak mysql\_native\_password'dan daha iyi güvenlik sağlayan caching\_sha2\_password eklentisini etkinleştirir. Eski uygulamanız bu eklentiyle sorun yaşıyorsa, daha zayıf eklentiye geri dönmek yerine uygulama kitaplıklarını güncelleyin.
Ayrıca parola karmaşıklık politikasını etkinleştirebilirsiniz. MySQL 8'de bu, validate\_password bileşeni kurularak yapılır:
INSTALL COMPONENT 'file://component_validate_password';
SET GLOBAL validate_password.policy = STRONG;
Bu ayarla MySQL, zayıf parolaların oluşturulmasını engeller ve minimum uzunluk ile karakter kombinasyonlarını zorunlu kılar.
Özet ve son kontrol listesi
MySQL güvenliği tek seferlik bir süreç değildir; düzenli olarak kontrol edilmelidir. Yukarıdaki tüm adımları tamamladıktan sonra bu kontrol listesini gözden geçirin:
- Anonim kullanıcı kaldırıldı mı? (SELECT user FROM mysql.user WHERE user='';)
- test veritabanları silindi mi?
- bind-address yalnızca 127.0.0.1 mi (veya sınırlı özel IP)?
- Hiçbir uygulama root kullanıcısıyla MySQL'e bağlanmıyor mu?
- Her uygulamanın minimum erişimli ayrı bir kullanıcısı var mı?
- Root parolası güçlü ve benzersiz mi?
- 3306 portu güvenlik duvarıyla dışarıdan kapatılmış mı (gerçek bir ihtiyaç yoksa)?
ServerNet'ten yeni bir sanal veya özel sunucu aldıysanız ve üzerinde MySQL kuruluysa, bu adımları bugün uygulayın. Güvenli yapılandırma için birkaç dakika harcamak, bir saldırının sonuçlarıyla uğraşmaktan çok daha az maliyetlidir. Unutmayın ki veritabanı güvenliği, sunucunuzun genel güvenliğinin bir parçasıdır ve göz ardı edilmemelidir.