SunucuKontrol — Sunucu Yönetim Paneli
Güvenlik

Aynı sunucuda birden fazla site güvenle nasıl barındırılır?

Yayın:

Kısaca
Sorun ne?
Bütün siteler aynı kullanıcıyla çalışırsa, birindeki açık saldırgana hepsinin dosyalarını açar.
Çözüm ne?
Her siteye ayrı bir sistem kullanıcısı ve ayrı bir PHP havuzu vermek. Böylece bir site diğerlerinin dosyalarını okuyamaz.
Zor mu?
Elle her site için birkaç dosya demek. Kontrol paneli bunu site eklerken kendiliğinden yapabilir.

Tek bir sunucuda on site barındırmak ucuz ve pratiktir. Ama siteler birbirinden yalıtılmamışsa, en zayıf sitenin açığı on sitenin hepsinin açığı olur. Bu yazı, aynı sunucudaki siteleri birbirinden ayırmanın yollarını anlatıyor.

Sorun: herkes aynı kullanıcıyla çalışıyor

Varsayılan kurulumlarda bütün siteler web sunucusunun tek kullanıcısıyla (www-data) çalışır. Bir sitede güncellenmemiş bir eklentiden içeri giren saldırgan, o kullanıcının okuyabildiği her şeyi okur: diğer sitelerin dosyaları, wp-config.php gibi veritabanı parolası içeren ayar dosyaları dahil.

1. Her siteye ayrı bir sistem kullanıcısı

sudo useradd --system --home /var/www/ornek.com --shell /usr/sbin/nologin ornekcom
sudo mkdir -p /var/www/ornek.com/public_html /var/www/ornek.com/tmp
sudo chown -R ornekcom:ornekcom /var/www/ornek.com
sudo chmod 750 /var/www/ornek.com
sudo chmod 700 /var/www/ornek.com/tmp

750 izniyle dizine yalnız sahibi ve grubu girebilir; diğer sitelerin kullanıcıları giremez. Web sunucusunun statik dosyaları okuyabilmesi için web sunucusu kullanıcısını sitenin grubuna eklemeniz gerekir; ama bunu yalnız 3. adımdaki sembolik bağ korumasıyla birlikte yapın. Web sunucusu bütün sitelerin grubunda olduğunda, bir site kendi dizinine komşu sitenin wp-config.php dosyasını gösteren bir sembolik bağ koyup onu web sunucusuna okutabilir. Sitenin kendi tmp dizini PHP'nin geçici dosyaları ve oturumları içindir (2. adım).

2. Her siteye ayrı bir PHP-FPM havuzu

PHP kodu sitenin kendi kullanıcısıyla çalışmalı. Bunun için her site kendi PHP-FPM havuzunu alır:

# /etc/php/8.4/fpm/pool.d/ornek.com.conf
[ornek.com]
user = ornekcom
group = ornekcom
listen = /run/php/ornek.com.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 5
php_admin_value[open_basedir] = /var/www/ornek.com:/usr/share/php
php_admin_value[upload_tmp_dir] = /var/www/ornek.com/tmp
php_admin_value[sys_temp_dir] = /var/www/ornek.com/tmp
php_admin_value[session.save_path] = /var/www/ornek.com/tmp

pm = ondemand az ziyaret alan sitelerin boşta bellek tüketmesini önler; open_basedir PHP'nin site dizini dışındaki dosyalara erişmesini sınırlar. Ortak /tmp'yi listeye eklemeyin: orada başka sitelerin yüklenen dosyaları, oturumları ve root'un geçici dosyaları durur; site oraya sembolik bağ da kurabilir. Yükleme, geçici dosya ve oturum yolları bu yüzden sitenin kendi tmp dizinine alınır.

3. Web sunucusunda sembolik bağ koruması

Site, web sunucusu ayarında kendi PHP soketine yönlendirilir. Aynı yerde, başka bir kullanıcıya ait dosyayı gösteren sembolik bağları reddedin (nginx):

# /etc/nginx/sites-available/ornek.com
server {
    server_name ornek.com www.ornek.com;
    root /var/www/ornek.com/public_html;
    # Bağ ile hedefi aynı kullanıcıya ait değilse 403
    disable_symlinks if_not_owner from=/var/www/ornek.com;

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/ornek.com.sock;
    }
}

if_not_owner, sitenin kendi dosyalarını gösteren bağlara (ör. sürüm dizinine bağlanan public_html) izin verir; komşu sitenin dosyasını gösteren bağı reddeder.

4. Her siteye ayrı veritabanı kullanıcısı

Bütün sitelerin aynı veritabanı kullanıcısını, hele root'u kullanması, bir sitenin parolasıyla bütün veritabanlarının açılması demektir. Her siteye yalnız kendi veritabanında yetkili bir kullanıcı verin:

CREATE USER 'ornekcom'@'localhost' IDENTIFIED BY '<güçlü-parola>';
GRANT ALL PRIVILEGES ON ornekcom_db.* TO 'ornekcom'@'localhost';

5. Yönetim araçlarını herkese açmayın

phpMyAdmin gibi araçlar her sitenin adresinden (ornek.com/phpmyadmin) açık olursa saldırganlar için hazır bir giriş kapısı olur. Bu araçlara yalnız panel üzerinden ve yetkili kişilerin erişmesini sağlayın.

6. Yedekleri de site site alın

Bir site ele geçirildiğinde yalnız o siteyi temiz bir yedekten dönebilmek, bütün sunucuyu geri almaktan çok daha hızlıdır. Yedekleri site bazında ve sunucu dışına kopyalayarak alın.

Yalıtımı kontrol edin

# PHP işçileri hangi kullanıcılarla çalışıyor? Hepsi www-data ise yalıtım yok.
ps -eo user,cmd | grep 'php-fpm: pool' | sort | uniq -c
# Havuzlarda ortak /tmp açık mı? Çıktı boş olmalı.
grep -H 'open_basedir.*:/tmp' /etc/php/*/fpm/pool.d/*.conf
# nginx sembolik bağ koruması her sitede var mı?
grep -L 'disable_symlinks' /etc/nginx/sites-enabled/*

SunucuKontrol'de

Bunların hepsini her site için elle yapmak zaman alır ve unutulmaya açıktır. SunucuKontrol'de siteler ortak bir kullanıcıyı paylaşmaz: panel her alan adını eklerken ona kendi sistem kullanıcısını, kendi PHP-FPM soketini ve kendi tmp dizinini (yükleme, geçici dosya ve oturumlar için) verir; nginx ayarına disable_symlinks if_not_owner kendiliğinden yazılır. phpMyAdmin müşteri alan adlarında hiç yayınlanmaz, yalnız panelden açılır. Ayrıntılar için panel seçerken dikkat edilmesi gerekenler yazısına bakabilirsiniz.

İlgili yazılar