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 -ten 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.