{"id":2370,"date":"2022-05-04T15:41:02","date_gmt":"2022-05-04T13:41:02","guid":{"rendered":"https:\/\/guven.atbakan.com\/blog\/?p=2370"},"modified":"2022-09-02T18:39:41","modified_gmt":"2022-09-02T16:39:41","slug":"web-uygulamalarinda-rate-limit","status":"publish","type":"post","link":"https:\/\/guven.atbakan.com\/blog\/tr\/web-uygulamalarinda-rate-limit\/","title":{"rendered":"Web uygulamalar\u0131nda Rate Limit"},"content":{"rendered":"<p>A\u00e7\u0131k\u00e7as\u0131 yaz\u0131ya ba\u015flarken T\u00fcrk\u00e7e&#8217;sinin ne oldu\u011funu uzun s\u00fcre d\u00fc\u015f\u00fcnd\u00fcm. Ama bulamad\u0131m. Bu sefer kendim de bir \u00e7eviri yapamad\u0131m. Biraz daha web tabanl\u0131 d\u00fc\u015f\u00fcnecek olursak &quot;yap\u0131lan istekleri\/i\u015flemleri limitleme&quot; diye \u00e7evirebiliriz. <\/p>\n<h2>Problemler ve senaryolar<\/h2>\n<p>Rate-limit asl\u0131nda \u00e7ok geni\u015f bir konsept ve bir\u00e7ok noktada kullan\u0131labiliyor. G\u00fcn\u00fcm\u00fczde web uygulamalar\u0131nda en \u00e7ok brute-force sorunlar\u0131n\u0131 \u00e7\u00f6zmek i\u00e7in kullan\u0131l\u0131yor. Ben bu yaz\u0131da ger\u00e7ek \u00f6rnekler verece\u011fim ve sonras\u0131nda neler yapabilece\u011fimizi konu\u015faca\u011f\u0131m.<\/p>\n<h3>Kullan\u0131c\u0131 taraf\u0131ndan tetiklenen e-postalar\u0131n sonsuz say\u0131da g\u00f6nderilmesi<\/h3>\n<p>Web sitelerinde suistimale a\u00e7\u0131k b\u0131rak\u0131lan noktalardan birisi genelde e-postalar oluyor. Sald\u0131rganlar buray\u0131 mutlaka bir yoklar. Buralarda bir limit mekanizmas\u0131 unutulabiliyor. \u00c7ok basit bir \u00f6rnek vermek gerekirse, &quot;parolam\u0131 unuttum&quot; e-postas\u0131 i\u00e7in \u00f6zel bir limit uygulanmad\u0131ysa, kullan\u0131c\u0131n\u0131n her talebinde yeni bir e-posta g\u00f6nderilir. \u00c7ok basit bir \u015fekilde e-posta s\u0131f\u0131rlama servisine yap\u0131lacak bir ddos ile milyonlarca e-posta g\u00f6nderilebilir. Ve bu g\u00f6nderilen e-postalar \u015firkete zarar olarak yazar. <\/p>\n<ol>\n<li>E\u011fer Mailgun, SES tarz\u0131 bir servis kullan\u0131l\u0131yorsa fatura \u00e7ok y\u00fcksek gelir. <\/li>\n<li>E\u011fer firma kendi mail sunucusunu kullan\u0131yorsa mail sunucusu kuyruktan dolay\u0131 kilitlenebilir ve \u00f6nemli e-postalar\u0131n g\u00f6nderilmesi gecikir\/engellenir. Sunucunun tekrar aya\u011fa kalkmas\u0131 i\u00e7in harcanacak personel eforu da cabas\u0131. <\/li>\n<li>E\u011fer gmail, yandex tarz\u0131 bir smtp sunucu \u00fczerinden g\u00f6nderiyorsan\u0131z da y\u00fcksek olas\u0131l\u0131kla rate-limite tak\u0131l\u0131rs\u0131n\u0131z ve bir s\u00fcre banlan\u0131rs\u0131n\u0131z (asl\u0131nda bizim yapmam\u0131z gereken \u015fey buydu!)<\/li>\n<\/ol>\n<h3>Deneme yan\u0131lma ile login bilgilerine eri\u015filmesi<\/h3>\n<p>Yani eminim herkes bu sald\u0131r\u0131lar\u0131na kar\u015f\u0131 \u00f6nlem alm\u0131\u015ft\u0131r. Ama ben yine de yazmak istedim :) \u00c7\u00fcnk\u00fc buralardan sald\u0131r\u0131 alan projelere \u00e7ok\u00e7a rastlad\u0131m. Sald\u0131rganlar\u0131n elinde genelde bir e-posta\/parola listesi oluyor ve t\u00fcm listeyi sizin \u00fczerinizde deniyorlar. Tek bir kullan\u0131c\u0131 i\u00e7in birden fazla parola denemesi de yap\u0131labilir, birden fazla kullan\u0131c\u0131 bilgisi de denenebilir.<br \/>\n&quot;X sitesinin 100.000 kullan\u0131c\u0131s\u0131n parolalar\u0131 ele ge\u00e7irildi&quot; haberlerini mutlaka duymu\u015fsunuzdur. \u0130\u015fte bu parolalar\u0131 \u00e7e\u015fitli sitelerde deniyorlar ve m\u00fc\u015fteri ayn\u0131 parolay\u0131 kulland\u0131ysa ve sald\u0131rgan login olabildiyse; kay\u0131tl\u0131 kartlar\u0131, sadakat puanlar\u0131n\u0131 ya da hesab\u0131 kullanabiliyorlar. Hesap kullan\u0131m\u0131 \u00e7ok enteresan bir konu, bir doland\u0131c\u0131l\u0131k hikayesinin akt\u00f6r\u00fc olabiliyorsunuz.<\/p>\n<ol>\n<li>M\u00fc\u015fterilerinizin hesaplar\u0131 hacklenebilir ve kullan\u0131labilir. M\u00fc\u015fteriniz zarara u\u011frayabilir. <\/li>\n<li>Sitenizi kullanarak brute-force\/rainbow table sald\u0131r\u0131lar\u0131 ile m\u00fc\u015fterilerin parolalar\u0131 ele ge\u00e7irilebilir ve o haberlere konu olabilirsiniz.<\/li>\n<\/ol>\n<p>Not: En \u00e7ok mobile \u00f6zel login endpointleri (captcha vs olmad\u0131\u011f\u0131 i\u00e7in) sald\u0131r\u0131ya a\u00e7\u0131k halde oluyorlar.<\/p>\n<h3>Sitenizdeki hassas verilerin temin edilebilmesi<\/h3>\n<p>En hassas veri san\u0131yorum ki kullan\u0131c\u0131 bilgileridir. Yine parolam\u0131 unuttum \u00fczerinden yola \u00e7\u0131karsak, bir kullan\u0131c\u0131n\u0131n sitenizde kay\u0131tl\u0131 olup olmad\u0131\u011f\u0131, d\u00f6nd\u00fc\u011f\u00fcn\u00fcz response \u00fczerinden anla\u015f\u0131l\u0131yor olabilir. Bir e-posta forma girildi\u011finde &quot;bu e-posta hesab\u0131 sistemimizde kay\u0131tl\u0131 de\u011fildir&quot; diyorsan\u0131z bir problemimiz var demektir.<br \/>\nTabi \u00f6ncelikle bu yan\u0131t\u0131 d\u00fczeltmemiz gerekiyor ve sald\u0131rgana s\u0131r vermememiz gerekiyor. Ama \u00f6ncesinde buraya uygulayaca\u011f\u0131m\u0131z bir rate-limit, sald\u0131rgan\u0131 ba\u015f\u0131m\u0131zdan uzakla\u015ft\u0131rabilir. <\/p>\n<ol>\n<li>M\u00fc\u015fterilerinizin var olup olmad\u0131\u011f\u0131 tespit edilebilir. Bu bilgiler sonraki sald\u0131r\u0131larda ya da m\u00fc\u015fterilere y\u00f6nelik yap\u0131lacak ba\u015fka sald\u0131r\u0131larda kullan\u0131labilir. Telefonla polis gibi aray\u0131p &quot;X sitesinde hesab\u0131n\u0131z tespit edildi, para verin&quot; diyebilirler :)<\/li>\n<li>Hediye kodu vb. kodlar brute force ile denenebilir ve ge\u00e7erli olanlar s\u0131zd\u0131r\u0131labilir.<\/li>\n<\/ol>\n<h3>3.parti entegrasyonlar\u0131n etkilenmesi<\/h3>\n<p>En az e-posta sunucusunu me\u015fgul etmemiz kadar \u00f6nemli bir konu buras\u0131. Art\u0131k 3.parti sistemlerle \u00e7al\u0131\u015fmayan websitesi yok. Algolia, Intercom, Segment ve daha bir s\u00fcr\u00fc site ile \u00e7al\u0131\u015f\u0131yoruz. Kendi i\u00e7imizde de cache yap\u0131yoruz, invalidation yap\u0131yoruz. Baz\u0131 i\u015flemlerin s\u00fcrekli tekrarlanmas\u0131, 3. parti sistemleri yorabilir ve bize istenmeyen faturalar \u00e7\u0131kartabilir. \u00d6rne\u011fin Algolia, yap\u0131lan istek say\u0131s\u0131na g\u00f6re fatura kesebiliyor. Belli bir rakam\u0131n \u00fcst\u00fcne \u00e7\u0131k\u0131nca fiyatlar inan\u0131lmaz art\u0131yor.<br \/>\nKullan\u0131c\u0131n\u0131z\u0131n bir aksiyonu s\u00fcrekli tekrarlad\u0131\u011f\u0131n\u0131 ve her tekrarlad\u0131\u011f\u0131nda 3. partilere request att\u0131\u011f\u0131m\u0131z\u0131 d\u00fc\u015f\u00fcnelim. Bu durumda bir ddos ile milyonlarca istek gidebilir. <\/p>\n<ol>\n<li>3.parti sistemlere \u00e7ok say\u0131da ve gereksiz istek g\u00f6nderebilir, bunun sonucunda faturalara maruz kalabiliriz. <\/li>\n<li>Baz\u0131 istatistiklerimiz etkilenebilir ve bizi yan\u0131ltabilir. <\/li>\n<li>Cache invalidation veya veritaban\u0131 i\u015flemleri sunucular\u0131m\u0131z\u0131 me\u015fgul edebilir. <\/li>\n<\/ol>\n<h2>\u00c7\u00f6z\u00fcm \u00f6nerileri<\/h2>\n<h3>Loglay\u0131n ve takip edin<\/h3>\n<p>Yap\u0131lan i\u015flemleri loglamak ve takip etmek en \u00f6nemli konular\u0131n ba\u015f\u0131nda geliyor. Elbette neyi loglayaca\u011f\u0131n\u0131z\u0131, raporlayaca\u011f\u0131n\u0131z\u0131 ve takip edece\u011finizi i\u015fin en ba\u015f\u0131nda bilemeyebilirsiniz. Alarm mekanizmalar\u0131 her zaman kurtar\u0131c\u0131n\u0131z olacakt\u0131r. <\/p>\n<p>Basit\u00e7e, istek yap\u0131lan sayfalar\u0131n\u0131z\u0131\/servislerinizi loglayabilir ve belli bir s\u00fcre sonra ortalama say\u0131lar\u0131 \u00e7\u0131kartabilirsiniz. Bu noktada bir alarm olu\u015fturup, belli bir oran\u0131n \u00fczerinde istek geldi\u011finde incelemeye alabilirsiniz. Verdi\u011fim \u00f6rneklerden yola \u00e7\u0131karsak, parola s\u0131f\u0131rlama endpointine saatte ortalama X istek geliyor ve bir anda bu say\u0131 3X olarak raporlara yans\u0131yorsa, burada bir anomali var diyebiliriz ve kontrol edebiliriz. Bir s\u00fcre sonra bu s\u00fcreci daha da otomatikle\u015ftirebilirsiniz. <\/p>\n<h3>\u0130stek say\u0131lar\u0131n\u0131 limitleyin<\/h3>\n<p>Benim s\u0131kl\u0131kla uygulad\u0131\u011f\u0131m y\u00f6ntemlerden ba\u015f\u0131nda gelir. Kullan\u0131c\u0131lara yapacaklar\u0131 i\u015flemler i\u00e7in belli limitler veririm.<br \/>\n\u00d6rne\u011fin, bir IP adresi, 1 dakika i\u00e7erisinde maximum 3 kez login olmay\u0131 deneyebilir. 5 dakika i\u00e7erisinde 6 kez deneyebilir.<br \/>\nBu kullan\u0131m\u0131 biraz daha geni\u015fletmek gerekiyor tabi. Sadece bir IP adresi baz\u0131nda bakmak yerine, bir kullan\u0131c\u0131 baz\u0131nda da bakabilirsiniz. \u00d6rne\u011fin bir e-mail adresi ile yap\u0131lan denemeleri limitleyebilirsiniz ve belli bir denemeden sonra, o hesap ile giri\u015f yap\u0131lmas\u0131n\u0131 ge\u00e7ici olarak devre d\u0131\u015f\u0131 b\u0131rakabilirsiniz.  Hesab\u0131n\u0131n kilitlenmesi elbette sizin kullan\u0131c\u0131lar\u0131n\u0131z\u0131 mutsuz edebilir. Bu noktada da IP kontrol\u00fc veya yapaca\u011f\u0131n\u0131z di\u011fer kontroller devreye girmeli.<\/p>\n<p>E\u011fer bir API servis ediyorsan\u0131z, bu noktada da bir rate-limit uygulaman\u0131z\u0131 \u015fiddetle \u00f6neririm. Belli bir s\u00fcre i\u00e7erisinde belli bir say\u0131da istek atabilirsiniz. Bu noktada sevmeyeni olmayan Stripe d\u00f6k\u00fcman\u0131ndan bir par\u00e7a b\u0131rak\u0131yorum: <a href=\"https:\/\/stripe.com\/docs\/rate-limits\">https:\/\/stripe.com\/docs\/rate-limits<\/a><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/guven.atbakan.com\/blog\/wp-content\/uploads\/2022\/03\/Screenshot-from-2022-03-24-15-21-19.png\" alt=\"\" \/><\/p>\n<p>Rate-limit belirleme konusunda sizi en \u00e7ok zorlayacak \u015fey, hangi noktalarda rate-limit uygulanaca\u011f\u0131 ve bunun ne olaca\u011f\u0131.Bunun bir form\u00fcl\u00fc yok maalesef. Log k\u0131sm\u0131nda da bahsetti\u011fim gibi, bunu \u00f6l\u00e7meniz ve kendinize uyarlaman\u0131z gerekiyor. Bir de rate limite tak\u0131lan i\u015flemleri de loglarsan\u0131z, insanlar\u0131n ne s\u0131kl\u0131kla rate-limite tak\u0131ld\u0131\u011f\u0131n\u0131 g\u00f6rebilirsiniz. <\/p>\n<p>Sitenizdeki t\u00fcm sayfalara rate-limit uygulayabilirsiniz. \u00d6rne\u011fin Laravel size \u00e7ok basit bir middleware ile rate-limit uygulayabilme imkan\u0131 sunar. <a href=\"https:\/\/laravel.com\/docs\/9.x\/routing#rate-limiting\">https:\/\/laravel.com\/docs\/9.x\/routing#rate-limiting<\/a><\/p>\n<p>Ama bunu uygularken istekleri loglaman\u0131z ve dikkat etmeniz \u00e7ok \u00f6nemli. E\u011fer burada limitleri do\u011fru belirleyemezseniz, kullan\u0131c\u0131lar\u0131n\u0131z\u0131n i\u015flem yapmas\u0131n\u0131 engelleyebilirsiniz. Bu y\u00fczden genel bir rate limit a\u00e7\u0131lmas\u0131n\u0131 pek do\u011fru bulmuyorum. Ancak bir sald\u0131r\u0131 alt\u0131nda oldu\u011funuzu bildi\u011finiz senaryolarda a\u00e7man\u0131z faydal\u0131 olabilir. Bu da bizim s\u0131kl\u0131kla uygulad\u0131\u011f\u0131m\u0131z bir y\u00f6ntem. Yani bir nevi &quot;Cloudflare Under Attack Mode&quot;  gibi.<\/p>\n<h3>3. Parti g\u00fcncellemelerini kuyru\u011fa at\u0131n<\/h3>\n<p>Bir kullan\u0131c\u0131n\u0131n herhangi bir bilgisi de\u011fi\u015fti\u011finde Algolia \u00fczerinde g\u00fcncelledi\u011finizi varsayal\u0131m. Bunu her g\u00fcncellemede yapt\u0131\u011f\u0131n\u0131zda muhtemelen \u00e7ok fazla istek g\u00f6ndereceksiniz. Bunun \u00f6n\u00fcne ge\u00e7mek i\u00e7in kendinize bir politika belirleyin. \u00d6nem derecesine g\u00f6re bir de\u011fi\u015fikli\u011fin ne kadar s\u00fcrede 3. parti uygulamada g\u00fcncellenece\u011fini belirleyin. \u00d6rne\u011fin kullan\u0131c\u0131 ad\u0131 sizin veritaban\u0131n\u0131zda g\u00fcncellendikten 10 dakika sonra Algolia \u00fczerinde g\u00fcncellenebilir. Bu 10 dakika i\u00e7erisinde olu\u015fan t\u00fcm istekleri bir kuyruk sistemine yaz\u0131p, 10. 10 dakika sonra sadece 1 istek gitmesini sa\u011flayabilirsiniz. Sonu\u00e7 olarak sadece 1 kez g\u00fcncellenmesi de yeterli olacakt\u0131r.<\/p>\n<p>Bu noktada illaki RabbitMq tarz\u0131 bir queue sistemi de kullanman\u0131za gerek yok. Kendiniz i\u00e7in basit bir veritaban\u0131 tablosu yap\u0131p bunun \u00fczerinden y\u00f6netebilirsiniz. Tabi ki bir ddos alt\u0131nda veritaban\u0131n\u0131z\u0131n da sallanaca\u011f\u0131n\u0131 unutmay\u0131n. Bu y\u00fczden siz bu i\u015fi queue sistemi \u00fczerinde kurgulamaya gayret edin :)<\/p>\n<h2>HTTP Status Code<\/h2>\n<p><strong>429<\/strong>, rate limit i\u00e7in kabul g\u00f6ren durum kodudur. Bu kod ile d\u00f6n\u00fc\u015f yapt\u0131\u011f\u0131n\u0131zda, bunu kolayca nginx\/apache loglar\u0131ndan yakalayabilirsiniz. Bu da kulland\u0131\u011f\u0131n\u0131z log toplama yaz\u0131l\u0131m\u0131 ile birlikte bir rapor\/uyar\u0131 mekanizmas\u0131 \u00fcretmenizi sa\u011flar. Tabi farkl\u0131 \u015fekillerde de bu i\u015flemleri loglayabilirsiniz ama http status code bence en pratik y\u00f6ntem.<\/p>\n<p>\u0130stek atanlara yard\u0131mc\u0131 olmas\u0131 a\u00e7\u0131s\u0131ndan rate limit ile ilgili ek bilgileri headers i\u00e7erisinde verebilirsiniz. \u00d6rne\u011fin Laravel paketinde <code>X-RateLimit-Limit<\/code>, <code>X-RateLimit-Remaining<\/code>, ve <code>Retry-After<\/code> kodlar\u0131n\u0131 g\u00f6receksiniz. <code>Retry-After<\/code> e\u011fer rate limite tak\u0131ld\u0131ysan\u0131z kar\u015f\u0131n\u0131za \u00e7\u0131kar. B\u00f6ylece client taraf\u0131nda yap\u0131lan istekleri buna g\u00f6re uyarlayabilirsiniz.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A\u00e7\u0131k\u00e7as\u0131 yaz\u0131ya ba\u015flarken T\u00fcrk\u00e7e&#8217;sinin ne oldu\u011funu uzun s\u00fcre d\u00fc\u015f\u00fcnd\u00fcm. Ama bulamad\u0131m. Bu sefer kendim de bir \u00e7eviri yapamad\u0131m. Biraz daha web tabanl\u0131 d\u00fc\u015f\u00fcnecek olursak &quot;yap\u0131lan istekleri\/i\u015flemleri limitleme&quot; diye \u00e7evirebiliriz. Problemler ve senaryolar Rate-limit asl\u0131nda \u00e7ok geni\u015f bir konsept ve bir\u00e7ok noktada kullan\u0131labiliyor. G\u00fcn\u00fcm\u00fczde web uygulamalar\u0131nda en \u00e7ok brute-force sorunlar\u0131n\u0131 \u00e7\u00f6zmek i\u00e7in kullan\u0131l\u0131yor. Ben bu yaz\u0131da [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[4],"tags":[386,385],"class_list":["post-2370","post","type-post","status-publish","format-standard","hentry","category-yazilim","tag-rate-limit","tag-rate-limiting"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":6}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_likes_enabled":true,"jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/posts\/2370","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/comments?post=2370"}],"version-history":[{"count":13,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/posts\/2370\/revisions"}],"predecessor-version":[{"id":2408,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/posts\/2370\/revisions\/2408"}],"wp:attachment":[{"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/media?parent=2370"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/categories?post=2370"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/tags?post=2370"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}