लगभग दो साल पहले, मैं
StackExchange साइट
नेटवर्क में काफी महत्वपूर्ण भेद्यता के साथ आया था। मैं कहता हूं कि "लड़खड़ा गया" क्योंकि मैंने साइट को हैक करने की कोशिश नहीं की। परिस्थितियों ने मेरे लिए दरवाजा खोल दिया। भेद्यता अपने आप में काफी दिलचस्प है, और इसमें उन सभी के लिए एक सबक शामिल है जो साइट या सर्वर इन्फ्रास्ट्रक्चर का निर्माण और रखरखाव करते हैं। तो, यहाँ कैसे मैं
StackOverflow हैक की कहानी है ...
स्रोत डेटा
उस समय मैंने एक छोटी सी कंपनी में काम किया, जहाँ पूरी तरह से ड्रैकियन प्रतिबंधों के साथ एक फ़ायरवॉल था। उन्होंने HTTP / 1.1 विनिर्देशन को पूरा नहीं करने वाले सभी अनुरोधों और प्रतिक्रिया शीर्षकों को काट दिया (और मान्य HTTP / 1.1 हेडर को भी काट दिया)। इसने उन साइटों पर एक चाल खेली जो
X-Requested-With
जैसी चीजों पर भरोसा करती हैं। इसलिए, मेरे "बाहरी रोमांच" के लिए, मैंने एक प्रॉक्सी स्थापित की।
मेरे पास उस समय कई सर्वर थे, इसलिए मैंने उनमें से एक पर स्क्विड स्थापित किया। चूंकि मैं कुछ सोच रहा था, मैंने केवल
127.0.0.1
साथ प्रॉक्सी कनेक्शन की अनुमति दी। मैंने सर्वर के लिए SSH सुरंग को उठाया और ब्राउज़र के लिए प्रॉक्सी के रूप में स्थानीयहोस्ट को इंगित किया। ब्राउज़र सुरंग से जुड़ा है, जो सर्वर पर स्क्विड से जुड़ा है। सब कुछ सही था। इस तथ्य के अलावा कि मेरे सभी ट्रैफ़िक को एन्क्रिप्ट किया गया था, मुझे साइटों को सामान्य रूप से उपयोग करने का अवसर मिला।
आप में से जो मुझे बताना चाहते हैं कि मैंने गलत किया है, मैं आपका ध्यान इस तथ्य की ओर आकर्षित करना चाहता हूं कि मुझे ऐसा करने का अवसर मिला। और सिर्फ एक अवसर नहीं, मुझे खुले तौर पर परदे के पीछे का उपयोग करने के लिए कहा गया था, क्योंकि हमें कुछ साइटों के साथ काम करना था जो इस फ़ायरवॉल के माध्यम से काम नहीं करते थे। इसलिए मैंने कुछ भी "गलत" नहीं किया।
आक्रमण
उस समय, मैं अक्सर स्टैकऑवरफ्लो चैट में था। तब वह बस दिखाई दिया था, और इसमें कुछ कीड़े थे। ठीक एक दिन, साइट ने मुझे कॉल स्टैक दिखाना शुरू कर दिया। मुझे इससे कोई महत्व नहीं था, क्योंकि मैं अक्सर इंटरनेट पर इस बारे में मिला करता था। वास्तव में, लगभग हर बार मुझे ASP.NET में लिखी गई साइट पर एक त्रुटि संदेश मिला, मैंने कॉल स्टैक देखा।
और फिर मैंने चैट में एक नया मेनू आइटम देखा। इस नए मेनू आइटम को "व्यवस्थापक" कहा जाता था। जिज्ञासा से बाहर, मैंने इस लिंक पर क्लिक किया, यह विश्वास करते हुए कि मुझे पहुंच से वंचित किया जाएगा। आगे जो हुआ उसने मुझे चौंका दिया। मुझे हर चीज की पूरी सुविधा मिली। मेरे पास एक डेवलपर कंसोल था जहां मैं देख सकता था कि कौन क्या कर रहा है। मेरे पास एक डेटाबेस के साथ काम करने के लिए एक इंटरफ़ेस था, जहां मैं किसी भी डेटाबेस से सीधे कुछ भी पूछ सकता था। मुझे पूर्ण अधिकार प्राप्त हैं।
आगे क्या हुआ
अगली बात जो मैंने की वह तुरंत मॉडरेटर को बता दी। कुछ मिनटों के बाद मैं एक मध्यस्थ के साथ एक निजी चैट में था, साथ ही दो डेवलपर्स भी थे। कारण लगभग 10 मिनट के भीतर पाया गया था। एक और 10 मिनट के बाद, समस्या को सतही रूप से हल किया गया था। एक पूर्ण सुधार में कुछ घंटे लगे। उन्होंने बहुत अच्छा काम किया। मेरे पास अभी भी उस चैट का लॉग है, और मैं कहना चाहता हूं कि ये डेवलपर्स सभी प्रशंसा के पात्र हैं। उन्होंने जल्दी और पेशेवर जवाब दिया। और उन्होंने समस्या को जल्द से जल्द हल किया।
भेद्यता
यदि आप चतुर हैं, तो आप शायद अनुमान लगा चुके हैं कि क्या हुआ था। जब से मैं एक प्रॉक्सी के माध्यम से बाहर निकला, मेरे अनुरोध में
X-Forwarded-For
हेडर जोड़ा गया। इस हेडर का मूल्य आईपी था जिसमें से प्रॉक्सी का अनुरोध किया गया था। लेकिन, चूंकि मैं एसएसएच सुरंग के माध्यम से प्रॉक्सी से जुड़ा था, आईपी स्थानीय था। तो स्क्विड ने
X-Forwarded-For: 127.0.0.1
जोड़ा ...
लेकिन सबसे दिलचस्प वह था जो एएसपी ने लॉग में दिखाया था। जब उन्होंने मेरे प्रश्नों के
REMOTE_ADDR: 127.0.0.1
को देखा, तो एक
REMOTE_ADDR: 127.0.0.1
रिकॉर्ड था
REMOTE_ADDR: 127.0.0.1
! उनके आवेदन में, सभी हेडर चेक सही ढंग से लागू किए गए थे। लेकिन IIS को सही तरीके से कॉन्फ़िगर नहीं किया गया था और यह
REMOTE_ADDR
X-Forwarded-For
REMOTE_ADDR
X-Forwarded-For
मान के
REMOTE_ADDR
अधिलेखित कर देता है, अगर कोई मौजूद था। और ऐसी कॉन्फ़िगरेशन त्रुटि के लिए धन्यवाद, मैं अपने प्रॉक्सी सर्वर का उपयोग करके व्यवस्थापक पैनल तक पहुंचने में सक्षम था।
निष्कर्ष
कभी भी
X-Forwarded-For
पर भरोसा न करें, जैसा कि हम देखते हैं - यह सुरक्षित नहीं है। हमेशा
REMOTE_ADDR
उपयोग करें। यह विचार करने योग्य है कि क्या आपको आईपी-आधारित सुरक्षा की आवश्यकता है। या, कम से कम, आपको इस पर पूरी तरह से भरोसा नहीं करना चाहिए, लेकिन इसे केवल एक अतिरिक्त उपाय के रूप में उपयोग करें।
यह ध्यान रखना दिलचस्प है कि डेवलपर्स ने वास्तव में उचित हेडर चेकिंग का उपयोग किया था। लब्बोलुआब यह है कि आपको कभी भी अपने बुनियादी ढांचे पर आँख बंद करके भरोसा नहीं करना चाहिए। सर्वर और एप्लिकेशन के बीच कॉन्फ़िगरेशन अंतर के कारण यह छेद दिखाई दिया। इस तरह की छोटी चीजें हर दिन होती हैं। अनुप्रयोग एक चीज़ और सर्वर को मानता है - दूसरा। समस्या यह है कि इस तरह का भरोसा पूरी तरह से सुरक्षा को कमजोर कर सकता है। इस मामले में, डेवलपर्स ने
REMOTE_ADDR
(काफी न्यायसंगत) के मूल्य पर भरोसा किया, लेकिन सर्वर सही तरीके से कॉन्फ़िगर नहीं किया गया था। बेशक, ऐसी स्थितियां हैं जब आपको सर्वर या अन्य घटकों पर भरोसा करना पड़ता है, लेकिन याद रखें कि अंधा भरोसा अच्छी बात नहीं है। इसके बारे में सोचो, और ऐसे मामलों के खिलाफ अपने आप को बीमा करने की कोशिश करो।
StackOverflow टीम ने इस मुद्दे को पूरी तरह से हल किया। तेज, उत्तरदायी और उचित। उन्होंने मुझसे मदद मांगी (जो मैंने खुशी से प्रदान की) और पेशेवर और सम्मानजनक व्यवहार किया। उन्होंने शानदार काम किया। हम सभी को सबक सीखने की जरूरत है। भेद्यता रिपोर्ट को गंभीरता से प्रतिक्रिया दें। पेशेवर और जल्दी से मुद्दे को हल करें।
PHP के बारे में
यहां सबसे दिलचस्प बात यह है कि PHP में लिखे गए एप्लिकेशन में समान भेद्यता हो सकती है।
Symfony2 अनुरोध वर्ग पर एक नज़र डालें। यह बहुत अच्छा लग रहा है। जब तक आप ध्यान दें कि यह निर्धारित करने के लिए एक स्थिर चर का उपयोग करता है कि क्या प्रॉक्सी पर भरोसा किया जाना चाहिए। इसका मतलब यह है कि यदि आपके एप्लिकेशन का कोई भी हिस्सा प्रॉक्सी से हेडर प्राप्त करना चाहता है (उदाहरण के लिए, लॉग को लिखने के लिए), तो आपका पूरा एप्लिकेशन तब प्रॉक्सी से हेडर प्राप्त करेगा। यह देखने के लिए कि क्या आपका कोड इस भेद्यता के लिए असुरक्षित है, कॉल
$request->trustProxy()
। यह भी ध्यान दें कि कोई उल्टा तंत्र नहीं है। आप प्रॉक्सी पर "विश्वास करना बंद" नहीं कर सकते। मुझे लगता है कि यह एक बड़ा वास्तुशिल्प है ...
Zend फ्रेमवर्क 2 ही करता है। इसमें एक
वर्ग है जो समान तरीके से व्यवहार करता है (आईपी प्राप्त करने के संदर्भ में)। दिलचस्प है, Zend फ्रेमवर्क 1 में,
आईपी एड्रेस प्राप्त करने का
तरीका पर्याप्त था। कॉलिंग कोड को स्पष्ट रूप से इंगित करना चाहिए कि वह क्या प्राप्त करना चाहता है, और डिफ़ॉल्ट रूप से एक सुरक्षित विकल्प होना चाहिए।
निष्कर्ष
यह समस्या दो मामूली गलतफहमियों के संयोजन का परिणाम थी। अलग-अलग, वे अनदेखी करना बहुत आसान हैं। लेकिन अगर वे एक निश्चित तरीके से अभिसरण करते हैं, तो आपको बहुत गंभीर सुरक्षा जोखिम प्राप्त होगा। और सबसे बड़ा सबक यह है कि आप वास्तव में अपने आवेदन के बाहर किसी भी चीज पर भरोसा नहीं कर सकते। यदि आप इसके आसपास प्राप्त कर सकते हैं (उदाहरण के लिए, हेडर और वैरिएबल जैसे
REMOTE_ADDR
पर भरोसा नहीं करके), तो आप अपने एप्लिकेशन को अधिक सुरक्षित बना सकते हैं। लेकिन सबसे पहले, आपके द्वारा लिखे गए कोड और आपके द्वारा बनाए गए सिस्टम के बारे में सोचें। और उनका साथ दें।