'भरोसेमंद टाइप' की मदद से, DOM-आधारित क्रॉस-साइट स्क्रिप्टिंग के जोखिमों को रोकें

Krzysztof Kotowicz
Krzysztof Kotowicz

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 83.
  • Edge: 83.
  • Firefox: यह सुविधा काम नहीं करती.
  • Safari: यह सुविधा काम नहीं करती.

सोर्स

डीओएम पर आधारित क्रॉस-साइट स्क्रिप्टिंग (डीओएम एक्सएसएस) तब होती है, जब उपयोगकर्ता के कंट्रोल वाले सोर्स (जैसे, उपयोगकर्ता नाम या यूआरएल फ़्रैगमेंट से लिया गया रीडायरेक्ट यूआरएल) का डेटा, सिंक तक पहुंचता है. यह eval() जैसा फ़ंक्शन या .innerHTML जैसा प्रॉपर्टी सेटर होता है, जो किसी भी JavaScript कोड को चला सकता है.

डीओएम एक्सएसएस, वेब की सुरक्षा से जुड़ी सबसे आम समस्याओं में से एक है. आम तौर पर, डेवलपर टीमें अपने ऐप्लिकेशन में गलती से इसे शामिल कर लेती हैं. भरोसेमंद टाइप की मदद से, आपको एप्लिकेशन लिखने, उनकी सुरक्षा की समीक्षा करने, और उन्हें डीओएम एक्सएसएस (क्लाइंट-साइड स्क्रिप्ट इंजेक्शन) से जुड़ी कमजोरियों से सुरक्षित रखने के लिए टूल मिलते हैं. ऐसा, वेब एपीआई के खतरनाक फ़ंक्शन को डिफ़ॉल्ट रूप से सुरक्षित बनाकर किया जाता है. भरोसेमंद टाइप, उन ब्राउज़र के लिए पॉलीफ़िल के तौर पर उपलब्ध हैं जो फ़िलहाल उनके लिए काम नहीं करते हैं.

बैकग्राउंड

कई सालों से, DOM XSS, वेब की सुरक्षा से जुड़ी सबसे आम और खतरनाक कमजोरियों में से एक है.

क्रॉस-साइट स्क्रिप्टिंग दो तरह की होती हैं. एक्सएसएस की कुछ कमजोरियों की वजह, सर्वर-साइड कोड होता है. यह कोड, वेबसाइट बनाने के लिए एचटीएमएल कोड को असुरक्षित तरीके से बनाता है. कुछ समस्याओं की मुख्य वजह क्लाइंट होती है. यहां JavaScript कोड, उपयोगकर्ता के कंट्रोल वाले कॉन्टेंट के साथ खतरनाक फ़ंक्शन को कॉल करता है.

सर्वर साइड एक्सएसएस को रोकने के लिए, स्ट्रिंग को जोड़कर एचटीएमएल जनरेट न करें. बग को कम करने के लिए, नॉन्स-आधारित कॉन्टेंट सुरक्षा नीति के साथ-साथ, सुरक्षित कॉन्टेक्स्ट-ऑटोएस्केपिंग टेंप्लेट लाइब्रेरी का इस्तेमाल करें.

ब्राउज़र, अब भरोसेमंद टाइप का इस्तेमाल करके, क्लाइंट-साइड DOM पर आधारित XSS को रोकने में भी मदद कर सकते हैं.

एपीआई के बारे में जानकारी

इस तरह के लिंक पर भरोसा किया गया सुविधा, इन खतरनाक सिंक फ़ंक्शन को लॉक करके काम करती है. हो सकता है कि आपने इनमें से कुछ सुविधाओं के बारे में पहले ही जान लिया हो, क्योंकि ब्राउज़र वेंडर और वेब फ़्रेमवर्क, सुरक्षा से जुड़ी वजहों से आपको इन सुविधाओं का इस्तेमाल करने से पहले ही रोक देते हैं.

भरोसेमंद टाइप के लिए ज़रूरी है कि आप डेटा को इन सिंक फ़ंक्शन में पास करने से पहले उसे प्रोसेस करें. सिर्फ़ स्ट्रिंग का इस्तेमाल करने पर, ब्राउज़र को यह पता नहीं चलता कि डेटा भरोसेमंद है या नहीं:

यह न करें
anElement.innerHTML  = location.href;
भरोसेमंद टाइप के चालू होने पर, ब्राउज़र एक TypeError दिखाता है और स्ट्रिंग के साथ DOM XSS सिंक के इस्तेमाल को रोकता है.

यह बताने के लिए कि डेटा को सुरक्षित तरीके से प्रोसेस किया गया है, एक खास ऑब्जेक्ट बनाएं - भरोसेमंद टाइप.

यह करें
anElement.innerHTML = aTrustedHTML;
  
भरोसेमंद टाइप चालू होने पर, ब्राउज़र उन सिंक के लिए TrustedHTML ऑब्जेक्ट स्वीकार करता है जिनमें एचटीएमएल स्निपेट की उम्मीद होती है. संवेदनशील जानकारी को सिंक करने के लिए, TrustedScript और TrustedScriptURL ऑब्जेक्ट भी होते हैं.

ट्रस्टेड टाइप, आपके ऐप्लिकेशन के DOM XSS अटैक सरफ़ेस को काफ़ी कम कर देते हैं. इससे सुरक्षा की समीक्षा करना आसान हो जाता है. साथ ही, ब्राउज़र में रनटाइम के दौरान, कोड को कंपाइल, लिंट या बंडल करते समय, टाइप के आधार पर की जाने वाली सुरक्षा जांच को लागू करने में मदद मिलती है.

भरोसेमंद टाइप इस्तेमाल करने का तरीका

कॉन्टेंट की सुरक्षा से जुड़ी नीति के उल्लंघन की रिपोर्ट के लिए तैयारी करना

आपके पास रिपोर्ट कलेक्टर को डिप्लॉय करने का विकल्प है. जैसे, ओपन-सोर्स reporting-api-processor या go-csp-collector. इसके अलावा, आपके पास किसी कमर्शियल रिपोर्ट कलेक्टर का इस्तेमाल करने का विकल्प भी है. ReportingObserver का इस्तेमाल करके, ब्राउज़र में कस्टम लॉगिंग और उल्लंघनों को डीबग भी किया जा सकता है:

const observer = new ReportingObserver((reports, observer) => {
    for (const report of reports) {
        if (report.type !== 'csp-violation' ||
            report.body.effectiveDirective !== 'require-trusted-types-for') {
            continue;
        }

        const violation = report.body;
        console.log('Trusted Types Violation:', violation);

        // ... (rest of your logging and reporting logic)
    }
}, { buffered: true });

observer.observe();

या इवेंट लिसनर जोड़कर:

document.addEventListener('securitypolicyviolation',
    console.error.bind(console));

सिर्फ़ रिपोर्ट वाला सीएसपी हेडर जोड़ें

उन दस्तावेज़ों में यह एचटीटीपी रिस्पॉन्स हेडर जोड़ें जिन्हें आपको भरोसेमंद टाइप में माइग्रेट करना है:

Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example

अब सभी उल्लंघनों की शिकायत //my-csp-endpoint.example से की गई है, लेकिन वेबसाइट काम करती रहेगी. अगले सेक्शन में बताया गया है कि //my-csp-endpoint.example कैसे काम करता है.

Trusted Type के उल्लंघनों की पहचान करना

अब से, जब भी भरोसेमंद टाइप किसी उल्लंघन का पता लगाते हैं, तो ब्राउज़र कॉन्फ़िगर किए गए report-uri को एक रिपोर्ट भेजता है. उदाहरण के लिए, जब आपका ऐप्लिकेशन innerHTML को कोई स्ट्रिंग भेजता है, तो ब्राउज़र यह रिपोर्ट भेजता है:

{
"csp-report": {
    "document-uri": "https://my.url.example",
    "violated-directive": "require-trusted-types-for",
    "disposition": "report",
    "blocked-uri": "trusted-types-sink",
    "line-number": 39,
    "column-number": 12,
    "source-file": "https://my.url.example/script.js",
    "status-code": 0,
    "script-sample": "Element innerHTML <img src=x"
}
}

इससे पता चलता है कि https://my.url.example/script.js की लाइन 39 पर, innerHTML को <img src=x से शुरू होने वाली स्ट्रिंग के साथ कॉल किया गया था. इस जानकारी से आपको यह तय करने में मदद मिलती है कि कोड के कौनसे हिस्से, DOM XSS की शुरुआत कर सकते हैं और उन्हें बदलने की ज़रूरत है.

उल्लंघन ठीक करें

भरोसेमंद लिंक से जुड़े उल्लंघन को ठीक करने के लिए, आपके पास कुछ विकल्प हैं. इसके लिए, आपत्तिजनक कोड को हटाया जा सकता है, लाइब्रेरी का इस्तेमाल किया जा सकता है, भरोसेमंद टाइप से जुड़ी नीति बनाई जा सकती है या आखिरी सुझाव के तौर पर, डिफ़ॉल्ट नीति बनाई जा सकती है.

समस्या वाले कोड को फिर से लिखना

ऐसा हो सकता है कि अब नॉन-कंफ़ॉर्मिंग कोड की ज़रूरत न रही हो या उसे उल्लंघन करने वाले फ़ंक्शन के बिना दोबारा लिखा जा सकता हो:

यह करें
el.textContent = '';
const img = document.createElement('img');
img.src = 'xyz.jpg';
el.appendChild(img);
यह न करें
el.innerHTML = '<img src=xyz.jpg>';

लाइब्रेरी का इस्तेमाल करना

कुछ लाइब्रेरी पहले से ही भरोसेमंद टाइप जनरेट करती हैं, जिन्हें सिंक फ़ंक्शन में पास किया जा सकता है. उदाहरण के लिए, XSS पेलोड को हटाकर, एचटीएमएल स्निपेट को सैनिटाइज़ करने के लिए DOMPurify का इस्तेमाल किया जा सकता है.

import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});

DOMPurify, भरोसेमंद टाइप के साथ काम करता है और TrustedHTML ऑब्जेक्ट में रैप किए गए, सुरक्षित एचटीएमएल को दिखाता है, ताकि ब्राउज़र कोई उल्लंघन न जनरेट करे.

भरोसेमंद लिंक के टाइप की नीति बनाना

कभी-कभी, नीतियों का उल्लंघन करने वाले कोड को हटाया नहीं जा सकता. साथ ही, वैल्यू को साफ़ करने और आपके लिए भरोसेमंद टाइप बनाने के लिए कोई लाइब्रेरी उपलब्ध नहीं होती. ऐसे मामलों में, खुद ही भरोसेमंद टाइप का ऑब्जेक्ट बनाया जा सकता है.

सबसे पहले, नीति बनाएं. नीतियां, भरोसेमंद टाइप के लिए फ़ैक्ट्री होती हैं. ये अपने इनपुट पर सुरक्षा से जुड़े कुछ नियम लागू करती हैं:

if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
  const escapeHTMLPolicy = trustedTypes.createPolicy('myEscapePolicy', {
    createHTML: string => string.replace(/\</g, '&lt;')
  });
}

यह कोड, myEscapePolicy नाम की नीति बनाता है. यह अपने createHTML() फ़ंक्शन का इस्तेमाल करके, TrustedHTML ऑब्जेक्ट बना सकता है. तय किए गए नियम, एचटीएमएल एलिमेंट बनाने से रोकने के लिए, < वर्ण को एचटीएमएल-एस्केप करते हैं.

इस नीति का इस्तेमाल इस तरह करें:

const escaped = escapeHTMLPolicy.createHTML('<img src=x onerror=alert(1)>');
console.log(escaped instanceof TrustedHTML);  // true
el.innerHTML = escaped;  // '&lt;img src=x onerror=alert(1)>'

डिफ़ॉल्ट नीति का इस्तेमाल करना

कभी-कभी नुकसान पहुंचाने वाला कोड नहीं बदला जा सकता. उदाहरण के लिए, जब किसी सीडीएन से तीसरे पक्ष की लाइब्रेरी लोड की जा रही हो. ऐसे में, डिफ़ॉल्ट नीति का इस्तेमाल करें:

if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
  trustedTypes.createPolicy('default', {
    createHTML: (string, sink) => DOMPurify.sanitize(string, {RETURN_TRUSTED_TYPE: true})
  });
}

default नाम की नीति का इस्तेमाल तब किया जाता है, जब किसी सिंक में स्ट्रिंग का इस्तेमाल किया जाता है, जो सिर्फ़ ट्रस्टेड टाइप को स्वीकार करता है.

कॉन्टेंट की सुरक्षा के लिए बनी नीति को लागू करने पर स्विच करना

जब आपका ऐप्लिकेशन उल्लंघन नहीं करता है, तो 'भरोसेमंद टाइप' लागू करना शुरू किया जा सकता है:

Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example

अब, आपका वेब ऐप्लिकेशन कितना भी जटिल क्यों न हो, डीओएम एक्सएसएस से जुड़ी जोखिम की संभावना सिर्फ़ आपकी किसी नीति में मौजूद कोड से हो सकती है. नीति बनाने की संख्या को सीमित करके, इस जोखिम को और भी कम किया जा सकता है.

इसके बारे में और पढ़ें