ModSecurity ile web güvenlik açıklarının engellenmesi hakkındaki yazı dizimizin bu bölümünde ModSecurity kullanarak Cross-Site Request Forgery (CSRF / XSRF) saldırlarının nasıl engellenebileceğinden bahsediyoruz. Web uygulamasındaki bir eksikten kaynaklanan ve istemci üzerinden yürüyen CSRF saldırısını ModSecurity ile engelleyebilmek mümkün ama her zaman için zor, uygulaması zaman alan ve çok fazla test edilmesi gereken bir yöntemdir.
Cross-Site Request Forgery (CSRF) Nedir?
Siteler arası istek sahteciliği anlamındaki CSRF, bir web uygulamasına giriş yapmış olan bir kullanıcının rızası veya haberi olmadan web uygulamasında onun yetkileriyle kritik işlemler yaptırılmasıdır. Yani aslında CSRF, önemli bir yazılı belgede kurbanın imzasının taklit edilmesine eşdeğer bir dijital sahteciliktir. Bir CSRF saldırısıyla kullanıcı istekleri değiştirilebilir ve/veya bilgileri çalınabilir.
CSRF korumasının sadece web uygulaması tarafındaki sofistike anti-CSRF mekanizmaları ile sağlanabileceği düşünülse de, çoğu durumda bunun karmaşık bir işlem olması ya da koda müdahale edilememesi nedeniyle korumanın WAF tarafında yapılması iyi bir alternatif olarak öne çıkar. Fakat WAF tarafındaki uygulamanın çok dikkatli ve uzun süre test edilmesi gerekliliği ve bunun da kolay olmaktan uzak olması nedeniyle web uygulama geliştiricilerinin daha en baştan yazılım mimarisinde bu hususa dikkat edip uygulaması en tercih edilir yöntemdir.
Yazı dizimizin bu bölümünde ModSecurity ile CSRF’in nasıl engellenebileceği üzerinde duracağız. Bu yazıda OWASP ModSecurity CRS CSRF kural setleri ve High-Tech Bridge (ağırlıklı olarak) kaynakları referans olarak alınmıştır. CSRF hakkındaki teknik detaylara ise alttaki kaynaklardan ulaşabilirsiniz:
- http://www.bilgiguvenligi.gov.tr/web-guvenligi/webdeki-buyuk-tehlike-csrf.html
- http://ab.org.tr/ab12/sunum/196-Web-Uygulama-Denetimi-1.1.pdf
- http://sanalkurs.net/csrf-xsrf-nedir-tespiti-uygulanmasi-ve-korunma-yollari-4268.html
— BÖLÜM 3: ModSecurity ile CSRF Açığını Engelleme —
ModSecurity CRS, CSRF saldırılarına karşı “modsecurity_crs_43_csrf_protection.conf” kural seti ile gelir ama bu set varsayılan olarak aktif değil pasif durumdadır. Bu kural seti, sunucu tarafından kullanıcıya dönen web sayfalarındaki bütün aktif linklere ve sayfanın formuna bir anti-CSRF token’ı ekleyen JavaScript kodu (sayfanın DOM yapısını düzenler) iliştirir. Buradaki anti-CSRF token mekanizması tamamen ModSecurity tarafından yönetilir. Eğer bu kural seti herhangi bir önlem almadan olduğu gibi uygulanırsa web uygulamasının fonksiyonlarını bozabilir. İşte bu yüzden ilk başta varsayılanda pasif olarak gelir.
AJAX tabanlı web uygulamaları veya zafiyetli script’in hiç HTTP parametresi kabul etmediği ve sadece belli bir spesifik işlemi gerçekleştirdiği gibi durumlarda bu hazır kural seti CSRF zafiyetini kesinlikle engellemeyecektir. Ama yine de bu durumda bile özel olarak anti-CSRF kural yazılamayacağı anlamına gelmez. Bu gibi özel anti-CSRF mekanizmaları için web uygulamasının tasarım ve mimarisinin çok iyi ve derinlemesine bilinmesi gerekir. Bu yüzden aslında WAF için bu kadar derinlemesine uygulama bilgisi gerekliliği, aslında CSRF iyileştirmesini de bizzat uygulamanın kendi içinde yapılmasının çok daha doğru olacağı anlamını doğrurur.
Örnek olarak alttaki CSRF zafiyetine açık olan PHP scriptini inceleyelim:
close_publick_access.php <? sql(“update config set value='closed' where name='maintenance_mode' ”); echo “Sistem su an bakim modunda!”; die(); ?>
Normalde ModSecurity CRS hazır kural seti yukarıdaki CSRF zafiyeti bulunan kodu engellemeyecektir. Çünkü kod içinde hiçbir parametre olmadan işlem yapılıyor. Fakat alttaki anti-CSRF algoritması ile bu zafiyetin istismar edilmesi engellenebilecek:
- Eğer “csrf_sessid” çerezi kayıpsa ya da yanlış bir değere sahipse (40 hex karakterden farklı), kullanıcı için yeni bir “csrf_sessid” çerezi üretilir.
- “csrf_sessid”in sha() fonksiyonu bir türevi olarak ve gizli bir string ile (genellikle ModSecurity ayarında bulunan) “csrf_sessid_sha” değeri üretilir.
- Yeni bir HTTP GET parametresi “csrf_sessid_sha” olarak bütün aktif linklere iliştirilir. Buna “close_publick_access.php”yi çağıran link de dahildir.
- “close_publick_access.php”ye erişilen her seferde “csrf_sessid_sha” değeri ile lokalde yer alan çerezin değeri (“csrf_sessid”in sha() fonksiyonu ve gizli string) karşılaştırılır ve uyumsuzluk durumunda HTTP isteği bloklanır.
Buna göre kural da alttaki gibi olur:
mod_security_custom_rules.conf SecRule &REQUEST_COOKIES:csrf_sessid "@eq 0" "phase:2, t:none, chain, pass, nolog ,id:1041" SecRule UNIQUE_ID "^(.*)$" "capture, t:none, t:sha1, t:hexEncode, setvar:TX.csrf_sessid=%{TX.1}, setenv:csrf_sessid=%{TX.1}" SecRule REQUEST_COOKIES:csrf_sessid "!^([0-9a-f]{40})$" "phase:2, t:none, t:lowercase, chain, pass, nolog ,id:1042" SecRule UNIQUE_ID "^(.*)$" "capture, t:none, t:sha1, t:hexEncode, setvar:TX.csrf_sessid=%{TX.1}, setenv:csrf_sessid=%{TX.1}" SecRule REQUEST_COOKIES:csrf_sessid "^([0-9a-f]{40})$" "phase:2, capture, t:none, t:lowercase, pass, setvar:TX.csrf_sessid=%{TX.1}, id:1043" SecRule TX:csrf_sessid "^(.*)$" "phase:2, capture, pass, t:none, pass, nolog ,setvar:TX.csrf_sessid_sha=%{TX.1}SecretStringMJ7hi732c, id:1044" SecRule TX:csrf_sessid_sha "^(.*)$" "phase:2, capture, pass, t:none, t:sha1, t:hexEncode, setvar:TX.csrf_sessid_sha=%{TX.1}, id:1045" Header set Set-Cookie "csrf_sessid=%{csrf_sessid}e; httponly" env=csrf_sessid SecContentInjection On SecRule REQUEST_FILENAME "/admin.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, pass, nolog, id:1046" SecRule &TX:csrf_sessid_sha "@eq 1" "t:none, append:'\ <script>\ var csrf_sessid_sha = \'%{TX.csrf_sessid_sha}\';\ var csrf_link=document.getElementById(\'close_publick_access\');\ if(csrf_link) csrf_link.href+=\'?csrf_sessid_sha=\'+csrf_sessid_sha;\ </script>'" SecRule REQUEST_FILENAME "/close_publick_access.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, deny, log, id:1047" SecRule &ARGS_GET:csrf_sessid_sha "!@eq 1" "t:none" SecRule REQUEST_FILENAME "/close_publick_access.php" "phase:2, t:none, t:normalisePath, t:lowercase, t:urlDecodeUni, chain, deny, log, id:1048" SecRule ARGS_GET:csrf_sessid_sha "!@streq %{TX.csrf_sessid_sha}" "t:none"
Görüldüğü üzere en karmaşık CSRF’ler bile ModSecurity ile engellenebiliyor. Ama bunun hiç kolay olmadığı, uzun testlere ihtiyaç duyduğu ve derin uygulama bilgisi gerektirdiği aşikar.
Yazı dizimizin bir sonraki bölümünde görüşmek üzere…