spacer.png, 0 kB
Bilgi için: bilgi at bilgiguvenligi gov tr   

 

spacer.png, 0 kB
spacer.png, 0 kB
Uygulamanızı CSRF Saldırısından Koruyun (Preventing CSRF) Yazdır E-posta
Emre SÜREN, TÜBİTAK BİLGEM   
19.12.2011

Bu yazıda Cross Site Request Forgery (CSRF) saldırısının ne olduğu, sebebi ve çözümüne ait bilgileri verdikten sonra, bir JEE uygulamasının CSRF saldırısından korunması için gerekli olan yöntemler anlatılacaktır. 

Sorun

Hiç uzatmadan teorik kısmı atlayarak, CSRF zafiyetinin olduğu bir durumu şu şekilde tanımlayabiliriz. Kurban bir link'e tıklar ve tarayıcısında bir sayfanın açılmasını bekler. Bu sırada kendisinin haberi olmaksızın farklı sitelere (Cross Site), arka planda otomatize olarak istekler yapılır. Bu link'e kurban kendi isteğiyle tıklamıştır fakat arka plandaki otomatize istekler saldırganın işlemi olduğu için istek sahtedir (Request Forgery).

Günlük yaşantımızda hepimizin sıklıkla karşılaşacağı örnekleri şu şekilde ifade edebiliriz. Google’dan mp3 veya maç yayını sayfası aratırken, sorgu sonucunda gelen sayfaları genelde hayatımızda ilk defa görürüz. Bu sayfaların da kötü niyetli insanlar tarafından yapılmış olma ihtimali pek düşünülmez, aksini düşünenler olsa bile link'e tıklayıp görmeden, içeriği bilme şansımız sıfıra yakındır. Genelde bu tarz sayfa adresleri tıklandığında, sağdan soldan reklamlar fırlar ve etraf bir anda açılır (popup) pencerelerle dolar taşar. Tıklarız bir tane, açılırı on tane. Yani burada bariz bir şekilde birden fazla istek yapıldığı (URL çağrıldığı) görülür. Bu sizin hiç bilmediğiniz sitelere (reklam sayfaları genellikle) yapılan istekler olabileceği gibi o anda başka bir sekmede (tab) açılı duran ve kullanıcı girişi yaptığınız (mesela bir bankacılık uygulaması) sayfaya da istek yapıyor olabilir. Hatta bazı durumlarda popup vs. hiçbir şey görmezsiniz, ama arkada istekler cirit atıyordur. Bu kadar paranoyadan sonra…

csrf.png 

Birçok yazılım geliştirici bu saldırının ismini bile duymamıştır. Yapılan birçok anket, tehlike seviyesi yüksek saldırı türlerinden olup kullanıcılar bir kenara geliştiriciler tarafından dahi en az bilinen açıklık olduğunu ortaya koymuştur. Ayrıca CSRF açıklığı yazılım tarafında yapılan bir hatadan kaynaklanmaz, bu zafiyet doğaldır ve fazladan bir çalışma yapılıp engellenmesi gerekmektedir. 

Bu anlatılanlara rağmen halen yok arkadaş olmaz böyle şey diyorsanız, ne kadar yıkıcı bir saldırı olduğunu buyurun aşağıdaki gerçek yaşamdan alınmış bir örnekten okuyalım.

Bizimkisi bir CSRF hikayesi;

Emre bir gün, bir bankada güvenlik müdürü olarak çalışan birisiyle tanışır. Güvenlik müdürü, İnternet bankacılığı uygulamalarının, defalarca hem kendisi hem de sektörde bu işi yapan denetimciler tarafından, farklı dönemlerde güvenlik testinden geçirildiğini ve güvenli bankacılık işlemleri için Emre’ye bankada hesap açmasını tavsiye eder. Emre’de bu teklifi görmezden gelemez ve müdürle şubeye giderek bir hesap açarlar. Bu sırada Emre, güvenlik müdürünün hesap numarasını çoktan öğrenmiştir, aynı banka ve şubede hesap açtıkları için arkadaşının beş haneli hesap numarasını tespit etmesi kendisi için zor olmamıştır. Bir süre sonra, Müdür ve Emre'nin başlarından geçecek olay aşağıdaki gibi cereyan edecektir.

  1.   Güvenlik müdürü(Kullanıcı/Kurban) İnternet bankacılığı hesabına kullanıcı girişi yapmıştır.

  2. Emre (Kullanıcı/Saldırgan) beş adımdan oluşan (wizard tabanlı) havale işlemini biraz javascript ve html kullanarak tek adıma indirgemiş ve bir link'e tıklanarak tarayıcı üzerinden çağrılabilecek duruma getirmiştir ve bu anı beklemektedir. Güvenlik müdürüne mail ile link'i gönderir.

  3. Güvenlik müdürü mailini açıp link'e tıkladıktan sonra bankacılık sayfasındaki işlemlerine geri döner ve kısa bir süre sonra hesap bakiyelerini görüntüle işlemini yaptığında, hesabındaki paranın uçtuğunu görür ve olaylar gelişir.

Bu arada, olayı yaşayan ve tanıklık eden toplam beş kişi halen hayattadır.

Nereden geldik buraya? CSRF’den korun.

CSRF saldırısıyla neler yapılabileceğini anladığımıza göre bu açıklıktan nasıl kurtuluruz sorusunun cevabını artık arayabiliriz. Sayfa talebini gerçekten kullanıcının yaptığına emin olabilecek bir yol bulabilirsek çözümü bulmuş olacağız. Bunu oturup düşünmek yerine, üstesinden gelenlerin uyguladığı sisteme bakarsak, bir jeton (token) yapısıyla çözdüklerini görebiliriz. Aslında burada bahsedilen bir tasarım deseni olan “synchronizer token pattern” uygulamasıdır (implementation). Token şablonu, birçok MVC framework tarafından desteklenmektedir. Bunlara SpringMVC gibi popüler ve Struts gibi çok kullanılmış çatılar da dahildir. Ayrıca OWASP grubunun da bu iş için geliştirdiği CSRF Guard isimli bir projesi bulunmaktadır. Biz burada basitlik açısından, ESAPI kütüphanesi ışığında çözümü kendimiz yapacağız.

Bu noktada, CSRF zafiyetinin önlemi gayet basittir. Sorunun ne olduğunu biliyoruz, çözüm yolunu da biliyoruz o zaman işe başlayabiliriz. Aşağıdaki basamaklar uygulamayı CSRF saldırısından korumak için tam olarak ne yapmamız gerektiğini açıklamaktadır.

  1. Kullanıcı giriş yaptığında, yeni bir CSRF token oluştur ve ilgili oturum nesnesi içerisinde bu değeri tut.

  2. Korunmasını istediğiniz form veya URL için bu token değerini parametre olarak gönder (hidden field).

  3. Korunacak bu işlemler için kullanıcı isteğinde gelen token ve oturum nesnesi içerisinde saklanan token değerlerini sunucu tarafında karşılaştır.

  4. Kullanıcı çıkışı veya zamanaşımı sonunda token bilgisini geçersiz yap.

Koda dökersek;

1. Adım: Aşağıdaki kod parçası kullanıcı girişi yapan kod kısmını göstermektedir. Kullanıcı nesnesinde oluşturulacak yeni bir alanda (instance variable), CSRF token değeri saklanır ve daha önce de olduğu gibi http oturumu içerisinde bu kullanıcı nesnesi taşınır. Bu işlem sadece başarılı kullanıcı girişindeki ilk istekte bir kez yapılır.

     /**
     * CSRF Token üreteceğimiz metod.
     * @return Rastgele eşsiz bir değer, UUID (Universally Unique Identifier)
     */
    public String CSRFTokenProvider() {

        UUID csrfToken = UUID.randomUUID();

        return csrfToken.toString();
    }

2. Adım: CSRF koruması istenen form veya URL için, parametre olarak CSRF token eklenir. Literatürde korunması istenen form veya URL  için token eklenmesi tavsiye edilse de, başarılı kullanıcı girişi sonrasında yollanan ilk sayfadan itibaren bu değerin her cevapta gönderilmesini şiddetle tavsiye ediyorum.

     private AuthenticationService auth;

     /**

     * @param request kullanıcının yaptığı istek

     * @return istenen sayfanın form'una csrf token parametre olarak eklenir

     */

    public HttpServletRequest addCSRFTokenToForm(HttpServletRequest request) {

        User user = auth.getCurrentUser(); 

        request.setAttribute("CSRF_TOKEN", user.getCSRFToken());

        return request;

   }

3. Adım: Kullanıcının her isteği içerisinde otomatik olarak (hidden field) gelecek olan token ve oturum nesnesi içerisinde saklanan token değerleri karşılaştırılır. Aynı değillerse, bu sahte bir istektir. Sunucu tarafında isteklerin karşılandığı yerde bu metod çağrılmalıdır. Unutmadan sahte istekler kayıt altına (log) alınmalıdır. Uygulama genelinde log tutma nerede ve nasıl yapılmalıdır konusunu başka bir makalede detaylı olarak inceleyeceğiz.

    private AuthenticationService auth;

    /**
     * csrf token değerlerini karşılaştıracak metod
     * @param request kullanıcının yaptığı istek
     * @throws IntrusionException Sahte istek kayıt altına alınır
     */
    public void verifyCSRFToken(HttpServletRequest request) throws IntrusionException {

        User user = auth.getCurrentUser();

        String token = request.getParameter("CSRF_TOKEN");

        if ( !user.getCSRFToken().equals(token) ) {

            throw new IntrusionException("Saldırı", "Beklenmeyen CSRF token geldi, muhtemelen sahte bir istek.");

        }
    } 

4. Adım: Kullanıcı çıkışında (logout) ekstra bir önlem almaya gerek yoktur. Zaten başarılı bir oturum sonlandırma işleminde, oturum geçersiz (invalidate) oluyordur, token oturum içerisindeki bir nesnede tutulduğu için doğal olarak o da yok olacaktır.

    /**

     * standart bir logout metodu 

     * @param request kullanıcının yaptığı istek

     */ 

    public void killSession(HttpServletRequest request) {

        HttpSession session = request.getSession(false);

        if (session != null) {

            session.invalidate();

        }  

        session = request.getSession(true);

    }

Görüldüğü gibi alınan önlem basit ve sağlam bir yöntemidir. Şimdi, neler yaptığımızı hızlı bir şekilde gözden geçirirsek; CSRF nedir, niçin sorundur, ne kadar tehlikelidir ve dört adımda nasıl çözülür (token oluştur, token değerini form veya URL ile taşı, token değerini sunucu tarafında kontrol et, token'i öldür) şeklindedir.

Final

2011 yılında gerçekleştirdiğim, kamu kurumlarından özel sektöre kadar her alanda, birçok web uygulama güvenliği denetiminde bu açıklıkla karşılaştım. Birçok kurumda, paylaştığım bilgiler doğrultusunda, yazılım geliştirme ekibiyle birlikte bir çalışma yürüterek bu açıklıkları kapattık. Fakat her ne kadar çözüm basit olsa da gerçek ortamdaki uygulamalarda çeşitli sıkıntılarla karşılaşılabiliyor. Bir bankanın mobil bankacılık uygulaması için bu çözüm biraz masraflı geldi. İstemci tarafındaki kodlara baktığımızda birçok sayfada form kullanılmadığını gördük bunun için url tabanlı ama biraz farklı bir yöntem (in-house) geliştirmek zorunda kaldık. Başka bir makalede bu uygulamayı (implementation) paylaşacağım.

Sorularınızı, eleştirilerinizi ve sizin uygulamalarınızda nasıl önlemler aldığınızı yorum olarak veya bana ulaşarak paylaşmaktan çekinmeyin.

Kaynaklar

[1] http://www.owasp.org/index.php/Top_10_2007-Cross_Site_Request_Forgery

[2] http://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

[3] http://www.owasp.org/index.php/Category:OWASP_CSRFGuard_Project

[4] https://www.owasp.org/index.php/ESAPI_Swingset  

 


Favori olarak ekle (1) | Görüntüleme sayısı: 804

Yorumlar (2)
1. 10-01-2012 15:21
 
Hayır ne yazıkki önlemez. 
Yazıdaki örnek CSRF vakasındaki işlem EFT/Havale olmayabilirdi. SMS onayı koyamayacağınız finansal bir başka işlem de olabilirdi. (Bankacılık işlemleri EFT/Havaleden ibaret değil biliyorsunuz ve diğer çoğu işlemde sms onayı istenmiyor.) 
 
İnternet bankacılığınızda EFT/Havale işlemleri için OTP kullanımı zorunluysa bu şekilde bir saldırı "yapamazsınız", SMS/Token kontrolüne takılırsınız ama CSRF açıklığı önlemiş değildir. 
 
Yukarıda anlatılan olayda SMS onayı opsiyoneldi ve kullanılmıyordu, para transferinin başarılı yapılmasında etkisi var tabiki.
 
Emre SÜREN
2. 10-01-2012 11:18
 
Bankaların internet bankacılığı uygulamalrında (yukarıdaki örnekteki eft/havale gönderimi adımı için) SMS veya token cihazı ile oluşturulan kodların girilmesi bu açığı önlemeye yeterlidir değil mi?
 
Görkem Durğüt

Sadece kayıtlı kullanıcılar yorum yazabilir.
Lütfen sisteme giriş yapın veya kayıt olun.

 
spacer.png, 0 kB
spacer.png, 0 kB
Copyright 2012 TÜBİTAK-BİLGEM. Sitenin teknik altyapısında Joomla kullanılmıştır. Yazar ve site referans gösterilmeden alıntı yapılamaz. Görüşleriniz
spacer.png, 0 kB