Apache .htaccess ile Erişim Kontrolü ve Güvenlik

Web sunucunuzu kurup çalıştırdınız, siteniz yayında. Peki ya yetkisiz erişimler, hassas dizinler, brute force denemeleri? Apache’nin .htaccess dosyası, sunucu yapılandırmasına dokunmadan bu sorunların büyük çoğunluğunu çözmenizi sağlayan güçlü bir araç. Bugün bu dosyayı gerçek dünya senaryolarıyla birlikte derinlemesine inceliyoruz.

.htaccess Nedir ve Nasıl Çalışır?

.htaccess (hypertext access), Apache web sunucusunda dizin bazında yapılandırma yapmanızı sağlayan bir dosyadır. Ana httpd.conf veya apache2.conf dosyasını düzenleme yetkisine sahip olmadığınız durumlarda bile, bu dosya sayesinde o dizin ve alt dizinler için kapsamlı kurallar tanımlayabilirsiniz.

Dosyanın çalışması için Apache yapılandırmasında AllowOverride direktifinin aktif olması gerekir. Sunucu yöneticisiyseniz bunu kontrol edin:

# Apache ana yapılandırmasında AllowOverride kontrolü
grep -r "AllowOverride" /etc/apache2/
# veya CentOS/RHEL için
grep -r "AllowOverride" /etc/httpd/

Eğer AllowOverride None görüyorsanız, .htaccess dosyalarınız hiçbir işe yaramayacak. AllowOverride All veya en azından AllowOverride AuthConfig Limit olması gerekiyor.

# /etc/apache2/apache2.conf veya /etc/apache2/sites-available/your-site.conf içinde
<Directory /var/www/html>
    AllowOverride All
    Require all granted
</Directory>

Değişikliği yaptıktan sonra Apache’yi yeniden başlatmayı unutmayın:

sudo systemctl reload apache2
# veya
sudo systemctl reload httpd

Temel Erişim Kontrolü

IP Tabanlı Erişim Kısıtlaması

En basit ve en etkili güvenlik önlemlerinden biri, belirli IP adreslerine veya IP bloklarına erişimi kısıtlamaktır. Diyelim ki şirket içi bir yönetim paneli var ve sadece ofis IP’sinden erişilebilir olmasını istiyorsunuz:

# Apache 2.4 sözdizimi
<RequireAny>
    Require ip 192.168.1.0/24
    Require ip 203.0.113.50
</RequireAny>

# Belirli IP'yi engellemek için
<RequireAll>
    Require all granted
    Require not ip 198.51.100.0/24
</RequireAll>

Önemli not: Apache 2.2 ile 2.4 arasında sözdizimi farklıdır. Çoğu modern sistem 2.4 kullanıyor, ama eski bir sunucuyla çalışıyorsanız şunu kullanmanız gerekebilir:

# Apache 2.2 sözdizimi (eski sistemler için)
Order Deny,Allow
Deny from all
Allow from 192.168.1.0/24
Allow from 203.0.113.50

Sürümünüzü kontrol etmek için:

apache2 -v
# veya
httpd -v

Dizin Listelemeyi Kapatma

Sunucunuzda index.html veya index.php olmayan dizinler, Apache’nin varsayılan yapılandırmasında içeriğini listeleyebilir. Bu ciddi bir güvenlik açığıdır, çünkü log dosyaları, yedek dosyalar, yapılandırma dosyaları gözükebilir.

# Dizin listelemesini tamamen kapat
Options -Indexes

# Sembolik linkleri de engelle, SSI'yi de devre dışı bırak
Options -Indexes -FollowSymLinks -Includes

Bu direktifi ana .htaccess dosyasına koyduğunuzda tüm alt dizinler için geçerli olur. Belirli bir dizin için açık bırakmak istiyorsanız, o dizine ayrı bir .htaccess koyup Options +Indexes yazabilirsiniz.

Parola ile Korumalı Dizinler

.htpasswd Dosyası Oluşturma

Kritik dizinlere HTTP Basic Authentication eklemek, basit ama etkili bir güvenlik katmanı. Örneğin /var/www/html/admin dizinini koruyalım:

# htpasswd aracıyla kullanıcı oluştur
sudo htpasswd -c /etc/apache2/.htpasswd admin_user

# İkinci kullanıcı eklemek için -c olmadan kullan (yoksa dosyayı sıfırlar)
sudo htpasswd /etc/apache2/.htpasswd developer

# Kullanıcıyı silmek için
sudo htpasswd -D /etc/apache2/.htpasswd eski_kullanici

# Dosyanın içeriğini kontrol et
cat /etc/apache2/.htpasswd

.htpasswd dosyasını web kökünün dışında tutmak önemli. /etc/apache2/ altında tutmak iyi bir pratik.

Şimdi korunacak dizindeki .htaccess dosyasına:

AuthType Basic
AuthName "Yetkisiz Erisim Yasaktir - Yonetim Paneli"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user

# Sadece belirli kullanıcılara izin vermek istiyorsanız
# Require user admin_user developer

Grup Tabanlı Yetkilendirme

Daha büyük ekiplerde kullanıcıları gruplara ayırmak işleri kolaylaştırır:

# .htgroup dosyası oluştur
echo "devs: developer1 developer2 developer3" > /etc/apache2/.htgroup
echo "admins: admin_user sysadmin" >> /etc/apache2/.htgroup
AuthType Basic
AuthName "Gelistirici Alani"
AuthUserFile /etc/apache2/.htpasswd
AuthGroupFile /etc/apache2/.htgroup
Require group devs admins

Hassas Dosyaları Koruma

Yapılandırma ve Yedek Dosyaları Gizleme

Web geliştirme sürecinde sıkça karşılaşılan sorun: .env, config.php.bak, database.yml gibi dosyalar yanlışlıkla web kökünde kalıyor. Bu dosyalara doğrudan erişimi engellememiz şart:

# Belirli uzantıları engelle
<FilesMatch ".(bak|backup|old|orig|save|sql|log|env|config|cfg|ini)$">
    Require all denied
</FilesMatch>

# Nokta ile başlayan gizli dosyalara erişimi engelle
<FilesMatch "^.">
    Require all denied
</FilesMatch>

# Spesifik dosyaları engelle
<Files "wp-config.php">
    Require all denied
</Files>

<Files ".env">
    Require all denied
</Files>

Gerçek dünyada bu ne kadar kritik? Bir e-ticaret projesinde .env dosyasının erişime açık kaldığını düşünün. Veritabanı şifresi, API anahtarları, ödeme sistemi kimlik bilgileri hepsi orada. Böyle bir ihmal, şirketin sonunu getirebilir.

WordPress Kurulumları İçin Özel Kurallar

WordPress kullananlar için wp-config.php ve xmlrpc.php özellikle kritik hedefler:

# wp-config.php'ye erişimi tamamen engelle
<Files wp-config.php>
    Require all denied
</Files>

# xmlrpc.php'yi engelle (brute force saldırılarının favorisi)
<Files xmlrpc.php>
    Require all denied
</Files>

# wp-admin sadece belirli IP'lerden erişilebilir olsun
<Files wp-login.php>
    <RequireAny>
        Require ip 192.168.1.0/24
        Require ip 203.0.113.50
    </RequireAny>
</Files>

URL Yönlendirme ve Yeniden Yazma

mod_rewrite ile Güvenli URL’ler

mod_rewrite, .htaccess‘in en güçlü özelliklerinden biri. Hem SEO hem güvenlik açısından kritik:

# mod_rewrite'ın aktif olduğunu kontrol et
sudo a2enmod rewrite
sudo systemctl reload apache2
RewriteEngine On

# www olmayan trafiği www'ye yönlendir
RewriteCond %{HTTP_HOST} !^www. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# HTTP'yi HTTPS'e zorla
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Zararlı URL parametrelerini engelle
RewriteCond %{QUERY_STRING} (<|>|'|%3C|%3E|%27|%00) [NC,OR]
RewriteCond %{QUERY_STRING} (union|select|insert|drop|delete|update|cast|create|char|convert|alter|declare) [NC]
RewriteRule .* - [F,L]

Son kural bloğu basit bir SQL injection ve XSS girişimlerini engellemeye yardımcı olur. Tabii bu tek başına yeterli değil; uygulama katmanında da güvenlik şart.

Hotlinking Engellemek

Başka siteler resimlerinizi kendi sitelerinde gösterip sunucu bant genişliğinizi tüketiyorsa:

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www.)?siteniz.com [NC]
RewriteRule .(jpg|jpeg|png|gif|webp|svg)$ - [F,NC,L]

# Veya hotlink yapanları başka bir resme yönlendir
RewriteRule .(jpg|jpeg|png|gif)$ /images/hotlink-engellendi.jpg [R,NC,L]

Brute Force ve DDoS Koruması

Rate Limiting ile İstek Sınırlama

mod_evasive veya mod_ratelimit yoksa .htaccess ile temel bir koruma sağlayabilirsiniz:

# Çok fazla istek atan IP'leri geçici olarak engelle
# mod_evasive kurulu olmalı
<IfModule mod_evasive24.c>
    DOSHashTableSize    3097
    DOSPageCount        5
    DOSSiteCount        50
    DOSPageInterval     1
    DOSSiteInterval     1
    DOSBlockingPeriod   600
</IfModule>

Yalnızca .htaccess seviyesinde basit bir önlem olarak belirli user-agent’ları engelleyebilirsiniz:

# Kötü botları engelle
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (masscan|nikto|sqlmap|nmap|libwww-perl|harvest|casper|fetch|wget) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} (emailcollector|trackback|spam|scraper|curl) [NC]
RewriteRule .* - [F,L]
</IfModule>

# Boş user-agent'lara izin verme
RewriteCond %{HTTP_USER_AGENT} ^-?$
RewriteRule .* - [F,L]

Dikkat: wget ve curl engellemek genel kullanım için uygun olmayabilir. Kendi otomasyon scriptleriniz varsa bu araçları kullanıyor olabilirsiniz.

HTTP Güvenlik Başlıkları

Modern web güvenliğinin vazgeçilmez parçası olan güvenlik başlıklarını .htaccess üzerinden ekleyebilirsiniz:

<IfModule mod_headers.c>
    # Clickjacking koruması
    Header always set X-Frame-Options "SAMEORIGIN"
    
    # XSS koruması (eski tarayıcılar için)
    Header always set X-XSS-Protection "1; mode=block"
    
    # MIME sniffing engellemek
    Header always set X-Content-Type-Options "nosniff"
    
    # HSTS - HTTPS zorunlu kıl (1 yıl)
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    
    # Referrer bilgisini sınırla
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    
    # Permissions Policy
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
    
    # Sunucu bilgisini gizle
    Header unset Server
    Header always unset X-Powered-By
</IfModule>

mod_headers aktif değilse:

sudo a2enmod headers
sudo systemctl reload apache2

Content Security Policy (CSP)

CSP başlığı biraz daha karmaşık ama XSS saldırılarına karşı çok güçlü bir koruma:

<IfModule mod_headers.c>
    # Sıkı bir CSP politikası
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}' https://trusted-cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self'; frame-ancestors 'none'"
</IfModule>

CSP’yi önce Content-Security-Policy-Report-Only modunda test edin, üretim ortamına geçmeden önce ne engellediğini görün.

Önbellekleme ve Performans

Güvenliğin yanı sıra .htaccess performans ayarları için de kullanılır. Statik dosyalar için tarayıcı önbelleğini ayarlamak hem güvenlik hem performans açısından önemli:

<IfModule mod_expires.c>
    ExpiresActive On
    
    # Resimler için uzun süre
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    
    # CSS ve JavaScript
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    
    # HTML sayfaları daha kısa süre
    ExpiresByType text/html "access plus 1 hour"
    
    # Hassas içerik önbellekleme yapma
    <FilesMatch ".(php|cgi|pl|py)$">
        ExpiresDefault "access plus 0 seconds"
        Header set Cache-Control "no-store, no-cache, must-revalidate"
    </FilesMatch>
</IfModule>

Gerçek Dünya Senaryosu: E-ticaret Sitesi

Bir e-ticaret projesinde kullanabileceğiniz kapsamlı bir .htaccess örneği:

# Temel güvenlik
Options -Indexes -Includes -ExecCGI

# HTTPS zorunlu
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Hassas dosyaları engelle
<FilesMatch ".(env|bak|backup|sql|log|config|cfg)$">
    Require all denied
</FilesMatch>

<FilesMatch "^.">
    Require all denied
</FilesMatch>

# Admin panelini IP ile kısıtla
<Files "admin.php">
    <RequireAny>
        Require ip 192.168.1.0/24
        Require ip 203.0.113.50
    </RequireAny>
</Files>

# Güvenlik başlıkları
<IfModule mod_headers.c>
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header unset Server
    Header always unset X-Powered-By
</IfModule>

# Zararlı sorgu parametrelerini engelle
RewriteCond %{QUERY_STRING} (union.*select|select.*from|insert.*into|drop.*table) [NC]
RewriteRule .* - [F,L]

# Hotlink engelle
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www.)?e-ticaret-siteniz.com [NC]
RewriteRule .(jpg|jpeg|png|gif|webp)$ - [F,NC,L]

# Önbellek
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpeg "access plus 6 months"
    ExpiresByType image/png "access plus 6 months"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
</IfModule>

.htaccess Sorunlarını Gidermek

Bir şeyler ters gidince ne yapmalı?

# Apache hata loglarını takip et
sudo tail -f /var/log/apache2/error.log

# Sözdizimi hatalarını kontrol et
sudo apache2ctl -t
# veya
sudo apachectl configtest

# .htaccess'in okunup okunmadığını test et
# Geçici olarak hatalı bir satır ekleyip 500 alıyor musun diye bak

# mod_rewrite debug modu
# .htaccess'e geçici olarak ekle:
# RewriteLog "/tmp/rewrite.log"
# RewriteLogLevel 5
# (Apache 2.4'te bu farklı çalışır, LogLevel kullanılır)

500 Internal Server Error alıyorsanız büyük ihtimalle sözdizimi hatası var. apache2ctl -t komutu bunu hemen gösterir.

403 Forbidden alıyorsanız erişim kurallarınız çok kısıtlayıcı olabilir ya da dosya izinleri yanlış:

# .htaccess dosyası için doğru izinler
chmod 644 /var/www/html/.htaccess
chown www-data:www-data /var/www/html/.htaccess

Performans Notu: .htaccess’in Bedeli

.htaccess çok güçlü ama bir bedeli var: Her istek için Apache, istenen dosyaya kadar olan tüm dizinlerde .htaccess dosyası arar. Bu, özellikle çok sayıda alt dizini olan sitelerde performans kaybına yol açar.

Eğer sunucu yapılandırmasına erişiminiz varsa, .htaccess kurallarınızı VirtualHost veya Directory bloklarına taşıyın ve AllowOverride None yapın. Bu yaklaşım hem daha hızlı hem daha güvenli.

Ama paylaşımlı hosting kullanıyorsanız veya geliştiriciler kendi kurallarını yönetmesi gerekiyorsa, .htaccess hala en pratik çözüm.

Sonuç

.htaccess doğru kullanıldığında güçlü bir araç, yanlış kullanıldığında ise baş ağrısı kaynağı. Bugün ele aldığımız konuları özetleyecek olursak:

  • IP tabanlı erişim kontrolü, yönetim panelleri için ilk savunma hattı olmalı
  • Dizin listelemedisable her zaman açık olmalı, istisna yoksa
  • Hassas dosyaları web köküne koymayın, koydunuz mu mutlaka engelleyin
  • HTTP güvenlik başlıkları, mod_headers ile birkaç satırda eklenebilir
  • mod_rewrite, hem güvenlik hem yönlendirme için vazgeçilmez
  • Sorun giderirken Apache log dosyaları ve apache2ctl -t en iyi dostunuz

Her .htaccess değişikliğinden sonra mutlaka test edin. Canlı ortamda test yapmak yerine staging ortamı kurmak uzun vadede sizi çok dertten kurtarır. Ve son olarak: .htaccess güvenliği destekler ama tek başına yeterli değildir. Uygulama güvenliği, güncel yazılımlar ve düzenli denetimler bu işin bütününü oluşturur.

Yorum yapın