Sunucu Güvenliği
cPanel'de PHP güvenlik ayarları: her sürümde expose_php, display_errors ve fazlası
Çoklu ea-php ve alt-php sürümü olan cPanel sunucusunda expose_php, display_errors, allow_url_include ve disable_functions ayarlarının etkin değerini nasıl doğrularsınız, hangilerini güvenle kapatırsınız?
Güncellendi:
Bir cPanel sunucusunda tek bir PHP yoktur. EasyApache 4 ile gelen ea-php sürümleri, CloudLinux kullanıyorsanız alt-php sürümleri, her hesabın MultiPHP Manager'da seçtiği farklı sürüm ve bunların her birinin kendi php.ini dosyası, kendi php.d klasörü vardır. Bir sürümde kapattığınız ayar başka bir sürümde açık kalabilir; 8.2 için yaptığınız düzeltme, hâlâ 7.4 veya 8.1 üzerinde çalışan eski sitelere hiç ulaşmaz.
Bu yazıda PHP'nin güvenlikle ilgili altı ayarını, bunların her sürümde gerçekte hangi değerle çalıştığını nasıl doğrulayacağınızı ve hangilerini gönül rahatlığıyla değiştirebileceğinizi, hangilerinde önce siteleri kontrol etmeniz gerektiğini anlatıyoruz. Komutlar AlmaLinux, Rocky Linux ve CloudLinux üzerinde cPanel/WHM için yazıldı; root olarak çalıştırmanız gerekir.
Altı ayar ve ne işe yaradıkları
| Ayar | Önerilen | Açık kalırsa ne olur |
|---|---|---|
| expose_php | Off | Her yanıta X-Powered-By: PHP/8.1.x başlığı eklenir. Saldırgan sürümü tek istekle öğrenir ve o sürüme özgü açıkları dener. |
| display_errors | Off | Hata mesajları ziyaretçiye gösterilir: dosya yolları, veritabanı sorgu parçaları, bazen kullanıcı adları sayfaya düşer. |
| allow_url_include | Off | include ve require ile uzak bir URL'den kod yüklenebilir. Uzaktan dosya dahil etme (RFI) açıklarını doğrudan kod çalıştırmaya çevirir. |
| allow_url_fopen | Off (dikkatli) | file_get_contents gibi fonksiyonlar uzak URL açabilir. Birçok eklenti, güncelleme ve yedekleme aracı buna ihtiyaç duyar. |
| disable_functions | exec, passthru, shell_exec, system, proc_open, popen, pcntl_exec | Boşsa, sisteme yüklenmiş bir web kabuğu (web shell) işletim sistemi komutlarını doğrudan çalıştırabilir. |
| session.upload_progress.enabled | Off (geçici önlem) | CVE-2026-109618 için bilinen istismar yolu bu özellik üzerinden geçiyor. Yama gelene kadar kapatmak riski azaltır. |
İlk üçü, sitelerin çok büyük çoğunluğunda hiçbir işlevi bozmadan kapatılabilir. allow_url_fopen ve disable_functions ise daha güçlü kısıtlamalardır ama sitelerin çalışmasını etkileyebilir. Son satır ise kalıcı bir sertleştirme değil, belirli bir açığa karşı geçici önlemdir. Bu ayrımı yazının sonunda Sentinel'in davranışını anlatırken tekrar ele alacağız.
1. Adım: Sunucuda hangi PHP sürümleri var?
Önce envanter. cPanel'in kendi aracıyla kurulu ea-php sürümlerini, dosya sisteminden de çalıştırılabilir PHP ikililerini listeleyin:
bash
# cPanel'in gördüğü kurulu sürümler
whmapi1 php_get_installed_versions
# ea-php ikilileri
ls -d /opt/cpanel/ea-php*/root/usr/bin/php
# CloudLinux kullanıyorsanız alt-php ikilileri
ls -d /opt/alt/php*/usr/bin/php 2>/dev/null
# Hangi pakette hangi sürüm var (sürüm numarasıyla birlikte)
rpm -qa --qf '%{NAME} %{VERSION}\n' | grep -E '^(ea-php[0-9]+-php-cli|alt-php[0-9]+-cli) ' | sortHangi hesabın hangi sürümü kullandığını görmek için WHM'de MultiPHP Manager sayfasına bakabilir ya da komut satırında /usr/local/cpanel/bin/rebuild_phpconf --current çıktısındaki varsayılan sürümü kontrol edebilirsiniz. Kullanılmayan eski bir sürüm de kuruluysa, bir hesap ona geçirildiği anda devreye girer; bu yüzden denetime kurulu her sürümü dahil edin.
2. Adım: Etkin değeri okuyun, php.ini metnini değil
En sık yapılan hata, php.ini dosyasını açıp oradaki satıra bakmaktır. PHP, php.ini'yi okuduktan sonra php.d klasöründeki ek .ini dosyalarını alfabetik sırayla okur ve aynı anahtarı tekrar tanımlayan dosya öncekini ezer. php.ini'de display_errors = Off yazsa bile php.d içindeki bir dosya onu On yapabilir. Doğru yöntem, PHP'nin kendisine sormaktır:
bash
V=ea-php81
BIN=/opt/cpanel/$V/root/usr/bin/php
# Hangi ini dosyaları yükleniyor?
$BIN --ini
# Altı ayarın etkin değeri
$BIN -i | grep -E '^(expose_php|display_errors|allow_url_fopen|allow_url_include|disable_functions|session.upload_progress.enabled) 'php -i çıktısında her satır ayar adı, yerel değer ve ana değer biçimindedir; örneğin expose_php => On => On. Tüm sürümleri tek seferde görmek için kısa bir döngü yeterlidir:
bash
for BIN in /opt/cpanel/ea-php*/root/usr/bin/php; do
echo "== $BIN"
"$BIN" -r 'foreach (["expose_php","display_errors","allow_url_fopen","allow_url_include","disable_functions","session.upload_progress.enabled"] as $k) { echo $k, "=", var_export(ini_get($k), true), PHP_EOL; }'
doneini_get kapalı bir ayar için boş metin ya da 0 döndürür; açık olan için 1 veya On. disable_functions boş metin dönüyorsa hiçbir fonksiyon kapatılmamış demektir.
Hangi php.d dosyasının bir ayarı ezdiğini bulmak için:
bash
grep -nE '^[[:space:]]*(expose_php|display_errors|allow_url_include|allow_url_fopen)[[:space:]]*=' \
/opt/cpanel/ea-php81/root/etc/php.d/*.iniKomut satırı ile web tarafı aynı olmayabilir
php -i komut satırı (CLI) çalışma zamanını gösterir. ea-php sürümlerinde CLI ve web tarafı aynı php.ini ve php.d dosyalarını paylaşır, ama PHP-FPM kullanılıyorsa havuz yapılandırmasındaki php_admin_value ve php_admin_flag satırları web tarafında bu değerleri ezebilir. Şüpheli bir hesap için FPM havuz dosyalarına bakın:
bash
grep -rnE 'php_(admin_)?(value|flag)\[(display_errors|allow_url_fopen|allow_url_include|disable_functions)\]' \
/opt/cpanel/ea-php*/root/etc/php-fpm.d/ 2>/dev/nullWeb tarafındaki gerçek değeri görmenin en kesin yolu, ilgili hesabın belge kökünde rastgele adlı geçici bir dosyayla ini_get çıktısını almak ve kontrolden hemen sonra dosyayı silmektir. phpinfo sayfasını kalıcı olarak bırakmayın; bıraktığınız sayfa, kapatmaya çalıştığınız bilgi sızıntısının ta kendisidir.
3. Adım: Hesap düzeyindeki ezmeler: .user.ini, .htaccess ve CageFS
Sunucu düzeyinde her şeyi kapatsanız bile hesap sahipleri bazı ayarları kendi dizinlerinden değiştirebilir. Hangi ayarın nereden değiştirilebileceği PHP'nin ayar kategorisine bağlıdır: display_errors her yerden (.user.ini, .htaccess, kod içinde ini_set) değiştirilebilir; expose_php, allow_url_fopen, allow_url_include ve disable_functions ise yalnızca sistem düzeyinde (php.ini, php.d, FPM havuzu) ayarlanabilir.
Bu yüzden display_errors için hesap dosyalarını taramak anlamlıdır. cPanel'deki kullanıcı düzeyindeki MultiPHP INI Editor de hesap dizinine .user.ini veya php.ini yazar:
bash
# .user.ini içinde display_errors açan hesaplar
find /home/*/public_html -maxdepth 4 -name '.user.ini' \
-exec grep -HiE '^[[:space:]]*display_errors[[:space:]]*=[[:space:]]*(on|1)' {} + 2>/dev/null
# .htaccess ile açanlar (mod_php / LSAPI)
find /home/*/public_html -maxdepth 4 -name '.htaccess' \
-exec grep -HiE 'php_(flag|value)[[:space:]]+display_errors[[:space:]]+(on|1)' {} + 2>/dev/nullCloudLinux ve CageFS kullanan sunucularda tablo biraz farklıdır. PHP Selector, her kullanıcıya kendi alt-php sürümünü ve kendi php.ini dosyasını verir; bu dosyalar /var/cagefs altında kullanıcı başına tutulur. Kullanıcı PHP Selector'dan allow_url_fopen'ı açabilir. Sunucu düzeyindeki ayarınız bu kullanıcılar için geçerli olmaz:
bash
find /var/cagefs/*/*/etc/cl.selector/php.ini -type f 2>/dev/null \
| xargs grep -lE '^[[:space:]]*allow_url_(fopen|include)[[:space:]]*=[[:space:]]*(On|1)' 2>/dev/null \
| head -50Bu listede çıkan bir hesap her zaman sorun değildir; meşru bir ihtiyaç için açılmış olabilir. Ama bilmeniz gereken bir istisnadır ve kullanıcıyla konuşulmadan geri alınmamalıdır.
4. Adım: Güvenli üçlüyü düzeltin
expose_php, display_errors ve allow_url_include ayarlarını kapatmak, sitelerin işlevini neredeyse hiç etkilemez. Yine de her değişiklikten önce yedek alın. Önerilen yol WHM'de Software altındaki MultiPHP INI Editor'dür: sürümü seçin, Basic Mode'da üç ayarı Disabled yapın ve kaydedin. Komut satırını tercih ediyorsanız:
bash
V=ea-php81
INI=/opt/cpanel/$V/root/etc/php.ini
TS=$(date -u +%Y%m%d_%H%M%S)
# 1) Yedek ve değişiklik öncesi hash
cp -p "$INI" "$INI.yedek-$TS"
sha256sum "$INI"
# 2) Değerleri yazın (satır yoksa ekleyin)
for KV in 'expose_php = Off' 'display_errors = Off' 'allow_url_include = Off'; do
K=${KV%% *}
if grep -qE "^[[:space:]]*$K[[:space:]]*=" "$INI"; then
sed -i -E "s/^[[:space:]]*$K[[:space:]]*=.*/$KV/" "$INI"
else
echo "$KV" >> "$INI"
fi
done
# 3) Değişiklik sonrası hash ve fark
sha256sum "$INI"
diff "$INI.yedek-$TS" "$INI"
# 4) PHP-FPM ve web sunucusunu yeniden başlatın
/scripts/restartsrv_apache_php_fpm
/scripts/restartsrv_httpdArdından 2. adımdaki döngüyü tekrar çalıştırın. Değer hâlâ On görünüyorsa php.d içinde bir dosya onu ezmeye devam ediyordur; o dosyadaki satırı silmek yerine başına noktalı virgül koyarak yorum satırına çevirin ki neyi değiştirdiğiniz geri izlenebilsin. Aynı işlemi kurulu her sürüm için tekrarlayın.
display_errors kapandığında hatalar kaybolmaz; log_errors açıksa hata günlüğüne yazılmaya devam eder. Geliştirme yapan bir müşteriniz hata görmek istiyorsa doğru yer canlı sayfa değil, günlük dosyasıdır.
5. Adım: allow_url_fopen ve disable_functions için önce sitelere bakın
Bu iki ayar güçlüdür ama paylaşımlı bir sunucuda körlemesine uygulanırsa bir şeyleri bozar. allow_url_fopen kapandığında file_get_contents ile uzak adres okuyan kod çalışmaz; bazı WordPress eklentileri, kur ve kargo entegrasyonları, görsel optimizasyon ve yedekleme araçları bundan etkilenir. disable_functions listesindeki exec veya proc_open kapatıldığında Composer, WP-CLI, görsel işleme kütüphaneleri ve bazı yedekleme eklentileri hata verir.
Uygulamadan önce şunları yapın:
- Hesap dosyalarında bu fonksiyonların ne kadar kullanıldığına bakın (aşağıdaki komut). Sonuç kabaca bir fikir verir; eklenti kodunda geçmesi, fonksiyonun her istekte çağrıldığı anlamına gelmez.
- Kritik müşteri sitelerinin ödeme, form ve yedekleme akışlarını değişiklikten sonra elle deneyin.
- Değişikliği önce az sayıda hesabın kullandığı bir PHP sürümünde deneyin; sorun çıkmazsa diğer sürümlere yayın.
- Bir hesabın gerçekten ihtiyacı varsa, sunucu genelini gevşetmek yerine o hesap için ayrı bir sürüm veya FPM havuzu ayarı düşünün.
bash
# exec ailesini kullanan PHP dosyası sayısı, hesap bazında (salt okuma)
for U in /home/*/public_html; do
N=$(grep -rlE '\b(shell_exec|proc_open|passthru|popen|pcntl_exec)[[:space:]]*\(' "$U" --include='*.php' 2>/dev/null | wc -l)
[ "$N" -gt 0 ] && echo "$N $U"
done | sort -rn | head -20CVE-2026-109618 ve session.upload_progress
21 Ekim 2026'da yayımlanan CVE-2026-109618 (ve eşlik eden CVE-2026-109619), PHP çekirdeğinde kimlik doğrulaması gerektirmeyen uzaktan kod çalıştırma açığıdır. mod_php, PHP-FPM, CGI ve LiteSpeed lsphp dahil tüm web çalışma şekillerini etkiler. Resmî yamalı sürümler 8.2.35, 8.3.36, 8.4.27 ve 8.5.12'dir. 8.1 ve daha eski dallar için resmî yama yoktur; bunlarda ancak dağıtıcının (cPanel veya CloudLinux) paketine eklediği backport koruma sağlar.
Asıl çözüm paket güncellemesidir. Yama gelene kadar bilinen istismar yolunu kapatmak için session.upload_progress.enabled ayarı Off yapılabilir. Bu özelliği kullanan yükleme ilerleme çubukları nadirdir; kapatmanın yan etkisi genellikle fark edilmez.
bash
# Paket changelog'unda CVE backport'u var mı?
rpm -q --changelog ea-php81-php-cli | grep -cE 'CVE-2026-10961[89]'
# Geçici önlem: sürümün php.d klasörüne ayrı bir dosya
V=ea-php81
printf '%s\n' '; CVE-2026-109618 gecici onlem (yama sonrasi kaldirilabilir)' \
'session.upload_progress.enabled = Off' \
> /opt/cpanel/$V/root/etc/php.d/zzzz-php2shell-onlem.ini
/scripts/restartsrv_apache_php_fpm
/scripts/restartsrv_httpd
# Doğrulama
/opt/cpanel/$V/root/usr/bin/php -r 'var_dump(ini_get("session.upload_progress.enabled"));'Dosya adının zzzz ile başlaması, php.d içinde en son okunmasını ve başka bir dosyanın bu ayarı tekrar açmamasını sağlar. CloudLinux alt-php sürümlerinde aynı dosya /opt/alt/phpXX/etc/php.d klasörüne yazılır. Paket güncellemesi yapıldıktan ve sürüm yamalı hâle geldikten sonra bu dosyayı kaldırabilirsiniz.
Sentinel bunu nasıl yapar
Sentinel'in php-security modülü kurulu her ea-php sürümünü ayrı ayrı ele alır ve değerleri php.ini metninden değil, o sürümün kendi ikilisine ini_get ile sorarak okur; böylece php.d ezmeleri de görünür. CageFS etkin sunucularda kullanıcıların PHP Selector dosyalarında allow_url_fopen veya allow_url_include açılmış mı diye ayrıca bakar ve bunu düzeltmeden, yalnızca bulgu olarak raporlar.
Panelde onayladığınızda Sentinel yalnızca üç ayarı değiştirir: expose_php, display_errors ve allow_url_include. Değiştirmeden önce her php.ini için dosya.harden-bak-zaman damgası adıyla yedek alır, SHA-256 değerini kaydeder, bu anahtarları ezen php.d satırlarını yorum satırına çevirir, PHP-FPM ve web sunucusunu yeniden başlatır ve modülü yeniden denetler. allow_url_fopen ve disable_functions bilerek otomatik uygulanmaz; siteleri bozabilecekleri için ayrı, düşük önemli bir öneri olarak raporlanır ve kararı size bırakılır.
Panelde göreceğiniz bulgular şuna benzer (sürüm adları örnektir):
| Kontrol | Önem / Durum | Mesaj |
|---|---|---|
| PHP ea-php81 | Orta / Uyarı | 2 ayar yanlış: expose_php=On, display_errors=On |
| PHP ea-php81 Önerilen Kısıtlamalar | Düşük / Uyarı | Önerilen, siteleri kırabilir (otomatik uygulanmaz): allow_url_fopen=On, disable_functions boş |
| CageFS PHP Override Riski | Orta / Uyarı | 3 kullanıcı allow_url_fopen/include=On override etmiş |
CVE-2026-109618 ayrı bir modülde, her ea-php ve alt-php sürümü için kontrol edilir: sürüm resmî olarak yamalı mı, paket changelog'unda backport var mı, yoksa session.upload_progress kapalı mı. Düzeltme onaylanırsa açık dalların paketleri güncellenir, her birine geçici önlem dosyası yazılır ve PHP yeniden başlatılır. Sentinel sunucuya ajan kurmaz; SSH ile bağlanır, kontrolleri çalıştırır ve çıkar.
TEKNOWEB ÇÖZÜMLERİ
Bu rehberle ilgili çözümler
Rehberdeki konuyu gerçek ürün ve hizmet seçenekleriyle birlikte değerlendirin.
Yorumlar ve sorular
Deneyimini paylaş, birlikte çözelim.
Yorumlar yükleniyor…
Okumaya devam edin
Tüm rehberlerSunucu Güvenliği
Sentinel güvenlik raporu nasıl okunur: puan, önem derecesi ve öncelik sırası
Sentinel'de ilk sunucunuzu ekledikten sonra panel ve PDF raporda gördüğünüz puanın nasıl hesaplandığı, önem ile durum farkı, bulgulara hangi sırayla bakacağınız ve onaylı düzeltmenin nasıl çalıştığı.
Sunucu Güvenliği
cPanel sunucusunda açık port denetimi: MySQL, Redis ve Docker dışarıya açık mı?
ss ile dinleyen servisleri çıkarın, MySQL, Redis, MongoDB ve Docker'ı yerel arayüze bağlayın, CSF kurallarını gözden geçirin ve güvenlik duvarı değişikliğini geri alma zamanlayıcısıyla güvenle yapın.
Sunucu Güvenliği
cPanel'de Süresi Dolmuş SSL Sertifikaları: AutoSSL Neden Yenilemez, Nasıl Kontrol Edilir?
AutoSSL açık olsa bile sertifikalar neden süresini doldurur? DNS, CAA, Cloudflare ve sağlayıcı limitleri; tüm site ve servis sertifikalarını openssl ile bitiş tarihine göre listelemenin yolları.