Skip to content
%70 lansman · 10$/saat · Teklif al

OpenCart yönetim panelini on dakikada sıkılaştırmak

Geliştirici gerektirmeyen ve otomatik saldırı yüzeyinin büyük kısmını ortadan kaldıran altı değişiklik: paneli taşımak, depolamayı taşımak, yükleme klasörlerinde PHP çalışmasını durdurmak, giriş sayfasına kimin ulaşacağına karar vermek, kullanıcıları temizlemek ve hata sızdırmayı kesmek.

ZA
Zeynep Aydın
AppSec Lead · · 4 dk okuma

IP kısıtlı bir yönetici giriş ekranı

OpenCart mağazalarına yapılan saldırıların çoğu size özel değildir. Bir tarayıcı bot /admin adresini bulur, hazır parola listesini dener, bilinen birkaç eklenti yolunu ister ve hiçbiri tutmazsa yoluna devam eder. Aşağıdaki değişiklikler, sunucusuna zaten SSH ile bağlandığınız bir mağazada yaklaşık on dakika sürer ve otomasyonun dayandığı saldırı yüzeyini ortadan kaldırır.

Bunlar güncelleme ve yedeklemenin yerine geçmez. Önce yapılacak işlerdir, çünkü güncellemelerin aksine yerinde kalmaları hiçbir maliyet getirmez. Sırayı da bilerek bu şekilde kurduk: her adım bir öncekinin açık bıraktığı yolu kapatır ve hepsi tek bir bakım penceresinde tamamlanabilir.

1. dakika: yönetim panelini /admin adresinden çıkarın

Yönetim klasörünün adını değiştirmek, harcanan emeğe karşılık kesilen gürültü açısından en verimli adımdır. admin, panel ya da yonetim olmayan bir ad seçin, klasörü yeniden adlandırın, ardından o klasördeki config.php içinde eski adı gösteren iki satırı düzeltin.

mv /var/www/store/admin /var/www/store/kt7-panel

# /var/www/store/kt7-panel/config.php — DIR_APPLICATION satırının size uyanını bırakın
define('HTTP_SERVER', 'https://example.com/kt7-panel/');
define('DIR_APPLICATION', '/var/www/store/kt7-panel/');   // OpenCart 3.0.x
define('DIR_APPLICATION', DIR_OPENCART . 'kt7-panel/');   // OpenCart 4.x

4.x sürümünde aynı dosya, proje kökünü DIR_OPENCART, eklenti dizinini de DIR_EXTENSION olarak tanımlar; dolayısıyla yalnızca yönetim satırını değiştirirsiniz. Terminali kapatmadan önce yeni adresten bir kez giriş yapın ve ekibe yeni yer imini siz gönderin — 404 sayfasıyla karşılaşıp keşfetmelerine gerek yok.

Ad değiştirmek güvenlik değil, gizlemedir. Bilinen bir yola yapılan toplu parola denemelerini keser; URL'lerinizi zaten görebilen birini durdurmaz ve zayıf bir parolayı düzeltmez. Yine de yapın, ama aşağıdakilerin hepsini de yapın.

3. dakika: system/storage klasörünü web kökünün dışına alın

system/storage; oturumları, logları, yüklenen dosyaları, indirilebilir ürünleri ve 3.0.x'te çekirdek dosyaların üretilmiş modification kopyalarını barındırır. Bu klasör belge kökünün altındayken yanlış yazılmış tek bir kural, tüm bu içeriği herkesin indirebileceği dosyalara çevirir. Klasörü kökün dışına taşıyın ve hem config.php hem de yönetim panelinin config dosyasında DIR_STORAGE değerini güncelleyin; cache, logs, session ve upload sabitleri bu değerden türetildiği için dosya başına tek satır yeterlidir.

mv /var/www/store/system/storage /var/www/oc-storage
chown -R www-data:www-data /var/www/oc-storage

# config.php ve kt7-panel/config.php
define('DIR_STORAGE', '/var/www/oc-storage/');

OpenCart 3.0.x bunu kontrol panelindeki uyarıdan yapmayı önerir; iki dosyada da aynı mutlak yol yazdığı sürece hangi yolu seçtiğinizin önemi yoktur. İşlem sonrası vitrini ve paneli açın, test modunda bir sipariş oluşturun, sonra eski yolda sessizce yeni bir şeyin belirmediğini kontrol edin: orada yeni bir error.log görüyorsanız config dosyalarından biri atlanmış demektir.

5. dakika: dosyaların düştüğü yerde PHP çalışmasını durdurun

Bir dosya yükleme açığı bir gün işe yararsa, sunucunun o dosyayı çalıştırıp çalıştırmaması kötü bir öğleden sonra ile gerçek bir olay arasındaki farkı belirler. Görsel dizini ve depolama yolu bayt servis etmeli, kod çalıştırmamalıdır.

# nginx — regex location'lar sırayla eşleşir; bunu genel \.php$ bloğunuzdan ÖNCE koyun
location ~* ^/image/.*\.(php|phtml|phar)$ { deny all; }
location ^~ /system/  { deny all; }
location ^~ /storage/ { deny all; }   # depolama hâlâ kökün içindeyse
# Apache — image/.htaccess
<FilesMatch "\.(php|phtml|phar)$">
    Require all denied
</FilesMatch>

Varsaymak yerine test edin. İçinde phpinfo() bulunan bir dosyayı image/ klasörüne koyun, tarayıcıdan isteyin ve sunucunuzu anlatan bir sayfa yerine 403 aldığınızı doğrulayın. Sonra dosyayı silin: unutulmuş bir test dosyası kendi başına bir açıktır.

6. dakika: giriş sayfasına kimin ulaşacağına karar verin

OpenCart başarısız müşteri girişlerini sınırlar — config_login_attempts ayarı ile oc_customer_login tablosu bunun içindir — ama bu sınır ekibinizin yönetici hesaplarını kapsamaz. Sürümünüz uygulama katmanında ne yaparsa yapsın, yönetim paneli için en ucuz ve en güvenilir sınır PHP'nin önünde, web sunucusunda durur.

location ^~ /kt7-panel/ {
    allow 203.0.113.10;      # ofis
    allow 198.51.100.0/24;   # VPN
    deny all;

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    }
}

İç içe bir location, kendi allow/deny kurallarını tanımlamadığı sürece dıştakileri devralır; böylece içerideki PHP işleyicisi de korunmuş olur. Sürekli seyahat eden bir ekip için adres listesi yerine auth_basic ve htpasswd ile HTTP kimlik doğrulaması kullanın ya da paneli VPN arkasına alın. Giriş formunu bir bot için erişilemez kılan her çözüm işinizi görür.

Sabit bir IP listesi tutmak mümkün değilse en azından tekrarlanan denemeleri pahalı hâle getirin. Web sunucusunun erişim logunda yeniden adlandırdığınız panel yoluna giden POST isteklerini izleyen ve bir dakika içinde beş başarısız denemeden sonra adresi engelleyen bir fail2ban kuralı, işletme maliyeti sıfıra yakın bir çözümdür; toplu parola denemesini bir avuç isteğe indirir.

8. dakika: kullanıcılar, gruplar ve API anahtarları

SELECT user_id, username, user_group_id, status, date_added FROM oc_user ORDER BY date_added DESC;
SELECT api_id, username, status FROM oc_api;
SELECT * FROM oc_api_ip;
  • Kişi başına tek hesap; asla ortak bir giriş kullanmayın, çünkü kime ait olduğunu bilmediğiniz bir işlemi soruşturamazsınız.
  • İşten ayrılanların hesaplarını kaldırın. Pasifleştirmek açık bir olay sürerken anlamlıdır; olay kapandığında hesap silinir.
  • user_group_id değeri 1 olan yetkiyi işin gerektirdiği en az sayıda kişiye verin, geri kalan herkes için daha dar bir grup tanımlayın.
  • oc_api tablosundaki her API kullanıcısının oc_api_ip tablosunda karşılığı olmalı. API'yi kullanmıyorsanız status değerini 0 yapın.
  • Kurulumdan kalan install dizinini silin ve dizin listelemenin kapalı olduğunu doğrulayın.

Parolalar da kendi cümlesini hak ediyor. OpenCart ne yazarsanız onu kabul eder; yani politikayı sizin koymanız gerekir: uzun, kişiye özel, bir parola yöneticisinde saklanan ve bir ajans ya da serbest çalışan mağazadan ayrıldığı gün herkes için yenilenen parolalar. Aynı gün o kişinin yönetici hesabını, varsa API anahtarını ve sunucu erişimini de kapatın.

10. dakika: sızdırmayı kesin, sinyali açın

İki ayar ve dört başlık. Ayarlar bölümünün Sunucu sekmesinde, üretimde Hataları Göster kapalı, Hataları Logla açık olmalıdır: /var/www yollarını ve veritabanı adını ekrana basan bir hata sayfası, kurulumunuzun bedava haritasıdır. Ardından hiçbir maliyeti olmayan yanıt başlıklarını ekleyin.

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Zaten vhost dosyasındayken HTTPS_SERVER ve HTTPS_CATALOG değerlerinin iki config dosyasında da tanımlı olduğunu ve düz HTTP'nin tek seferde, kalıcı olarak asıl alan adına yönlendirildiğini doğrulayın. HTTP ile HTTPS tanımlarının karışması, başka türlü sorunsuz görünen bir yönetici oturumunun her iki tıklamada bir düşmesinin en sık nedenidir.

On dakikanın satın almadığı şey

Buradaki hiçbir adım güncelliğini yitirmiş bir eklentiyi yamalamaz ve hiçbiri bir mağazayı geri getirmez. Sıkılaştırma kaç kişinin deneme şansı bulacağını belirler; güncellemeler, eklenti envanteri ve test edilmiş bir yedek ise denemelerden biri tuttuğunda ne olacağını belirler. Son üç ayda bir yedeği geri yüklemediyseniz henüz yedeğiniz yok, yalnızca bir dosyanız var.

Ne zaman bize yazın

Bu altı adımın canlı mağazada uygulanmasını ve doğrulanmasını istiyorsanız — vhost değişiklikleri dahil, her kuralın gerçekten engellediğini gösteren testleriyle birlikte — OpenCart sürümünüzü ve hosting sağlayıcınızı yazın. Lansman kampanyası boyunca işler saatlik 10 $ + KDV ile faturalanır ve tahmin, iş başlamadan önce elinize geçer. İlk yanıt 2 saat içinde, Pzt–Cmt 09:00–22:00 (GMT+3) arasında verilir.

ZA
Zeynep Aydın
AppSec Lead

OAuth, JWT ve OWASP odaklı güvenlik mimarisi; tehdit modelleme.