बाहरी साइट को सुरक्षित रूप से प्रीव्यू करना — प्रॉक्सी + सैनिटाइज़ेशन + iframe sandbox का इम्प्लीमेंटेशन
- engineering
- security
- nextjs
- iframe
इस लेख का सार
- बाहरी साइट को अपने ओरिजिन के iframe में लोड करने पर, बाहरी JS हमारे सेशन को छू सकता है — यह एक जोखिम है
- समाधान है "SSRF-गार्ड युक्त प्रॉक्सी + बाहरी JS को हटाना + प्रतिबंधित CSP + iframe sandbox" वाली बहु-स्तरीय सुरक्षा
- sandbox अगर ज़रूरत से ज़्यादा सख्त हो, तो वह अपनी ही स्क्रिप्ट को भी रोक देता है।
allow-scriptsजोड़ना भूल जाने से फीचर काम करना बंद हो सकता है
HeatMapX के A/Bटेस्ट में एक फीचर है, जो "बदलाव (Variant B) के बाद पेज कैसा दिखेगा" उसे टारगेट पेज पर लागू करके प्रीव्यू करता है। तकनीकी रूप से देखें तो यह "यूज़र की बाहरी साइट को हमारे खुद के डोमेन के iframe के अंदर सुरक्षित रूप से दिखाना" है, जो सोचने से ज़्यादा नाज़ुक प्रोसेस है। इस लेख में हम डिज़ाइन और असल में सामने आई एक समस्या को साझा कर रहे हैं।
एक सीधा-सादा इम्प्लीमेंटेशन खतरनाक क्यों है
अगर बाहरी साइट का HTML जैसा है वैसा ही लेकर हमारे ओरिजिन (उदाहरण के लिए heatmapx.com) से परोसा जाए, तो उस HTML में मौजूद <script> या onclick= जैसे टैग हमारे ही ओरिजिन के अधिकार के साथ चल जाते हैं। इससे Cookie या लॉगिन सेशन के पढ़े जाने का खतरा रहता है। इसे हर हाल में रोकना ज़रूरी है।
बहु-स्तरीय सुरक्षा की संरचना
इसीलिए हमने निम्नलिखित परतों को एक के ऊपर एक जोड़ा है।
1. SSRF-गार्ड युक्त प्रॉक्सी
टारगेट URL को वैलिडेट करके http/https के अलावा सब कुछ अस्वीकार किया जाता है। इसके अलावा localhost, प्राइवेट IP, और क्लाउड के मेटाडेटा एंडपॉइंट (जैसे 169.254.169.254) को भी ब्लॉक किया जाता है। रीडायरेक्ट को भी अपने-आप फॉलो नहीं किया जाता — redirect: 'manual' के ज़रिए हर स्टेप पर फिर से वैलिडेट किया जाता है, ताकि इंटरनल नेटवर्क की ओर न भेजा जा सके।
2. बाहरी JS को हटाना (सैनिटाइज़ेशन)
प्राप्त HTML से <script> टैग, on*= इनलाइन हैंडलर, और javascript: स्कीम को हटा दिया जाता है। प्रीव्यू में क्लाइंट की साइट की JS को चलाने की कोई ज़रूरत नहीं है (यह जानते हुए भी कि SPA को पूरी तरह से रीक्रिएट नहीं किया जा सकता, यह एक जानबूझकर लिया गया समझौता है)।
3. प्रतिबंधित CSP और base href
<head> के ठीक बाद <base href> डालकर रिलेटिव पाथ वाली इमेज और CSS को रिज़ॉल्व किया जाता है, साथ ही रिस्पॉन्स में एक प्रतिबंधित CSP लगाई जाती है जो "बाहरी JS को नहीं चलने देती"। इमेज और CSS को दिखाने के लिए अनुमति दी गई है।
4. iframe sandbox
आखिर में, डिस्प्ले वाले iframe पर sandbox लगाकर उसे आइसोलेट किया जाता है।
सामने आई कमी: sandbox ज़रूरत से ज़्यादा सख्त था
प्रीव्यू में, प्राप्त HTML में "बदलाव (changeSet) लागू करने वाली एक छोटी सी अपनी स्क्रिप्ट" इंजेक्ट की जाती है, जो iframe के अंदर चलकर लुक बदलती है। लेकिन प्रीव्यू वाले iframe के sandbox में सिर्फ़ allow-same-origin था, allow-scripts जोड़ा ही नहीं गया था।
नतीजा यह हुआ कि अपनी स्क्रिप्ट भी नहीं चली और बदलाव लागू हुए बिना ही मूल पेज दिखने लगा। एडिटिंग वाले एडिटर साइड के iframe में allow-scripts allow-same-origin सही तरीके से सेट था और वह ठीक काम कर रहा था, इसलिए वजह यह सेटिंग की असंगति थी।
फिक्स सीधा-सादा था — प्रीव्यू साइड को भी allow-scripts allow-same-origin के बराबर कर देना। साथ ही, iframe के sandbox एट्रिब्यूट को वैलिडेट करने वाला एक रिग्रेशन टेस्ट भी जोड़ा गया।
sandbox="allow-same-origin" → sandbox="allow-scripts allow-same-origin"
सीख
- बाहरी कंटेंट को एम्बेड करते समय "बहु-स्तरीय सुरक्षा" के नज़रिए से सोचें। किसी एक उपाय पर निर्भर न रहें।
sandboxको "लगा दिया तो सुरक्षित" मान लेना गलत है — असल में ज़रूरी बात यह है कि सिर्फ़ ज़रूरी अनुमतियाँ ही सटीक रूप से दी जाएँ। अगर यह ज़रूरत से ज़्यादा सख्त हो, तो अपना ही फीचर रुक जाता है।- "एक ही काम करने वाले दो रास्ते" (एडिटर और प्रीव्यू) की सिक्योरिटी सेटिंग्स एक जैसी हैं या नहीं, यह हमेशा जाँचें। सिर्फ़ एक को ठीक करने पर दूसरा टूट सकता है।
निष्कर्ष
बाहरी साइट का सुरक्षित प्रीव्यू, SSRF-गार्ड, बाहरी JS को हटाना, प्रतिबंधित CSP, और iframe sandbox की बहु-स्तरीय सुरक्षा से हासिल किया जा सकता है। और sandbox की अनुमतियाँ कम हों या ज़्यादा, दोनों ही स्थितियाँ समस्या बन सकती हैं। इस बार allow-scripts जोड़ना भूल जाना, इसी का एक क्लासिक उदाहरण था।