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

Krzysztof Kotowicz
Krzysztof Kotowicz

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

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

सोर्स

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

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

बैकग्राउंड

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

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

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

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

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

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

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

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

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

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

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

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

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

आपके पास रिपोर्ट कलेक्टर को डिप्लॉय करने का विकल्प है. जैसे, ओपन-सोर्स 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 से शुरू होने वाली स्ट्रिंग के साथ कॉल किया गया था. इस जानकारी से आपको यह पता चल सकता है कि कोड के किन हिस्सों से डीओएम एक्सएसएस हो सकता है और किनमें बदलाव करने की ज़रूरत है.

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

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

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

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

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

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

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

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)>'

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

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

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

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

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