← All posts

आपका पासवर्ड-रीसेट फॉर्म एक मुफ्त ईमेल तोप है

Authagonal·July 9, 2026
securityrate-limitingemail

पासवर्ड-रीसेट फॉर्म शायद आपके पास मौजूद सबसे कम दिलचस्प endpoint है। यह वही अकेला endpoint भी है जिसे कोई हमलावर किसी पर भी ताक सकता है। हमारे यहाँ कुछ समय तक इस पर कोई per-email rate limit नहीं था, और यह जिस वजह से मायने रखता है वो वो वजह नहीं है जो आप सोचेंगे।

जब आप सुनते हैं "unauthenticated endpoint, no rate limit," तो पहला ख्याल brute force का आता है। लेकिन एक रीसेट रिक्वेस्ट पर brute force करने को कुछ है ही नहीं। आप कोई पासवर्ड गेस नहीं कर रहे। आप एक ईमेल एड्रेस सबमिट करते हैं और सिस्टम एक लिंक भेज देता है। इसे बार-बार ठोकने से आप किसी अकाउंट में नहीं घुस जाते। तो नुकसान किसका होता है?

शिकार एक तीसरा पक्ष है। किसी और का एड्रेस टाइप कीजिए, [email protected], सेंड दबाइए, दोहराइए। हर रिक्वेस्ट एक असली ईमेल एक असली इनबॉक्स में भेजती है जिस पर आपका कोई कंट्रोल नहीं। आपने हमारे रीसेट फॉर्म को एक मेल बम में भर्ती कर लिया है, जो किसी ऐसे शख्स पर तना है जिसने कभी कुछ साइन अप ही नहीं किया। और चूँकि मेल हमारी तरफ से आता है, नुकसान एक साथ दो जगह गिरता है। शिकार का इनबॉक्स भर जाता है। और हमारी sending reputation को चोट लगती है, क्योंकि हमारे डोमेन से आते अनचाहे मेल की बाढ़ ठीक वही चीज़ है जिस पर mailbox provider नज़र रखते हैं। इतना काफी हो जाए तो हमारा वैध मेल, वेरिफिकेशन लिंक, असली पासवर्ड रीसेट, हमारे हर असली ग्राहक के लिए स्पैम में गिरने लगता है। एक unauthenticated endpoint, बिना किसी credential और हमलावर पर बिना किसी लागत के, एक ऐसे संसाधन को घटा देता है जिसे हमारे सारे यूज़र साझा करते हैं।

तो आप इसे rate-limit करते हैं। हर ईमेल एड्रेस के हिसाब से, ताकि किसी एक टारगेट पर बाढ़ न लाई जा सके। आसान। सिवाय इसके कि जो सीधा-सादा implementation दिमाग में आता है, वो चुपके से एक अलग छेद खोल देता है।

अगर आप limit सिर्फ तभी लगाते हैं, या काम सिर्फ तभी करते हैं, जब एड्रेस के पास सचमुच एक अकाउंट हो, तो endpoint असली अकाउंट्स के लिए बनावटी अकाउंट्स से अलग बर्ताव करता है। जो हमलावर उस फर्क को देख सकता है, रिस्पॉन्स में, status code में, या बस timing में, उसके पास अब एक oracle है कि कौन-कौन से ईमेल एड्रेस आपके यहाँ रजिस्टर्ड हैं। रीसेट फॉर्म ठीक इसी वजह से एक क्लासिक अकाउंट एन्यूमरेशन लीक हैं: मेल बम का भोला-भाला फिक्स एन्यूमरेशन बग पैदा कर देता है।

असली फिक्स को दोनों काम एक साथ करने होते हैं, और दोनों हिस्से अलग-अलग हैं। पहला, normalized ईमेल एड्रेस पर rate-limit लगाइए, चाहे अकाउंट मौजूद हो या न हो। limit की key खुद एड्रेस है, lowercase और trimmed, ताकि Victim@ और victim@ एक ही बकेट साझा करें, और counter तब लगाया जाता है जब आपने अभी कुछ लुकअप किया ही नहीं होता। उस counter को एक टिकाऊ, साझा स्टोर में रहना होता है, किसी एक प्रोसेस की मेमोरी में नहीं, वरना वो restart पर उड़ जाता है और कई instances के बीच कुछ नहीं करता। दूसरा, हर हाल में एक-समान रिस्पॉन्स दीजिए: वही status, वही "अगर उस एड्रेस का अकाउंट है, तो हमने एक लिंक भेज दिया है" संदेश, वही timing का आकार, चाहे एड्रेस आपके यहाँ का हो या न हो। मेल आप फिर भी सचमुच तभी भेजते हैं जब उसके पीछे कोई अकाउंट हो। लेकिन उस राज़ के आधार पर वो कुछ भी नहीं बदलता जिसे कोई बाहरी शख्स देख सके। rate limit तीसरे पक्ष की रक्षा करता है; constant-time रिस्पॉन्स इस बात की रक्षा करता है कि किसका अकाउंट है।

आम सबक पासवर्ड रीसेट से कहीं आगे तक पहुँचता है। कोई भी unauthenticated endpoint जो असली दुनिया में साइड-इफेक्ट पैदा करता है, ईमेल भेजना, SMS भेजना, webhook कॉल करना, वो महज़ आपके attack surface का हिस्सा नहीं है। वो एक हथियार है जो उस पर तना है जो दूसरे सिरे पर है, और उसे दागने का बिल आपकी reputation पर गिरता है, हमलावर की नहीं। उस चीज़ के हिसाब से rate-limit कीजिए जिस पर असर पड़ रहा है, यानी recipient पर, caller पर नहीं। और यह इस तरह कीजिए कि किसी राज़ की मौजूदगी या गैर-मौजूदगी उसे न बदले जो कोई observer देखता है।

पासवर्ड-रीसेट फॉर्म plumbing जैसा लगता है। यह वो अकेला plumbing का टुकड़ा है जो हुक्म मिलते ही दुनिया के किसी भी शख्स पर खुशी-खुशी स्प्रे कर देगा। उसी हिसाब से इसे मीटर कीजिए।

एक unauthenticated साइड-इफेक्ट endpoint को इस तरह मीटर करना कि यह लीक न हो कि किसका अकाउंट है, देखने में जितना लगता है उससे कहीं ज़्यादा पेचीदा है। Authagonal रीसेट फ्लो को पहले से rate-limited और enumeration-safe शिप करता है, ताकि आपकी sender reputation कभी एक curl loop भर की दूरी पर तबाही से न लटकी रहे।