Trusted Types की मदद से, डीओएम पर आधारित XSS हमलों से अपनी साइट को सुरक्षित रखना

वेब की सुविधाएं: भरोसेमंद टाइप

Trusted Types, सुरक्षा से जुड़ी एक सुविधा है. यह डीओएम पर आधारित क्रॉस-साइट स्क्रिप्टिंग (डीओएम XSS) को रोकने में मदद करती है. इसके लिए, "खतरनाक" ब्राउज़र एपीआई (जिन्हें सिंक कहा जाता है) में पास किए जा रहे डेटा को पहले किसी खास टाइप में बदलना ज़रूरी होता है, जैसे कि TrustedHTML.

डिफ़ॉल्ट रूप से, कई डीओएम एपीआई (जैसे, innerHTML या document.write) रॉ स्ट्रिंग स्वीकार करते हैं. अगर किसी स्ट्रिंग में किसी गैर-भरोसेमंद सोर्स से नुकसान पहुंचाने वाली स्क्रिप्ट मौजूद है, तो उसे एक्ज़ीक्यूट किया जा सकता है. ट्रस्टेड टाइप इस व्यवहार को बदल देता है: सीएसपी की मदद से चालू होने के बाद, ये सिंक सिर्फ़ उन TrustedHTML ऑब्जेक्ट को स्वीकार करेंगे जिन्हें अनुमति वाली नीतियों के तहत बनाया गया है.

लागू करने से जुड़ी अहम जानकारी

भरोसेमंद टाइप का इस्तेमाल करने के लिए, ये चार मुख्य चरण अपनाएं:

  1. सुरक्षा से जुड़ी ऐसी नीति तय करें जिससे यह पता चले कि स्ट्रिंग को कैसे सैनिटाइज़ या ट्रांसफ़ॉर्म करना है.
  2. रॉ स्ट्रिंग से भरोसेमंद टाइप ऑब्जेक्ट बनाने के लिए, उस नीति का इस्तेमाल करें.
  3. डीओएम सिंक में लिखते समय, ट्रस्टेड टाइप ऑब्जेक्ट का इस्तेमाल करें.
  4. कॉन्टेंट की सुरक्षा के लिए नीति (सीएसपी) का इस्तेमाल करके, भरोसेमंद टाइप लागू करें.

1. नीति बनाना

नीति, कॉन्टेंट को सैनिटाइज़ करने के नियमों का एक सेट होती है. इसे trustedTypes.createPolicy() का इस्तेमाल करके बनाया जाता है. आम तौर पर, इसे DOMPurify जैसी सैनिटाइज़र लाइब्रेरी या आपके ऐप्लिकेशन के एचटीएमएल एस्केपिंग नियमों को डेलिगेट किया जाता है:

import DOMPurify from 'dompurify';

const myPolicy = trustedTypes.createPolicy('sanitize-html', {
  createHTML: (input) =>
    // Return a sanitized string; createPolicy() wraps it in a TrustedHTML object.
    // Example using DOMPurify:
    DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: false }),
});

// Example using HTML escaping (for environments without third-party sanitizers):
const escapePolicy = trustedTypes.createPolicy('escape-html', {
  createHTML: (input) =>
    String(input)
      .replaceAll('&', '&')
      .replaceAll('<', '&lt;')
      .replaceAll('>', '&gt;')
      .replaceAll('"', '&quot;')
      .replaceAll("'", '&#39;'),
});

2. नीति का इस्तेमाल करना

स्ट्रिंग को सीधे सिंक में पास करने के बजाय, नीति बनाने का तरीका कॉल किया जाता है.

const untrustedInput = '<p>Hello, <strong>world</strong>!</p><img src="x" onerror="alert(1)">';

// In an enforced environment, this would throw a TypeError:
// element.innerHTML = untrustedInput;

// This returns a TrustedHTML object with unsafe elements and attributes removed:
const cleanHTML = myPolicy.createHTML(untrustedInput);
// Result: "<p>Hello, <strong>world</strong>!</p><img src=\"x\">"

3. ट्रस्टेड टाइप का इस्तेमाल करने के लिए, सिंक को ट्रांज़िशन करना

हर उस इंस्टेंस को अपडेट करें जहां सिंक में डेटा लिखा जाता है, ताकि उसे पहले भरोसेमंद टाइप ऑब्जेक्ट में बदला जा सके. कोड को कहां अपडेट करना है, यह पता लगाने के लिए, कुछ समय के लिए default नीति तय की जा सकती है. यह नीति, सिंक को TrustedType के बजाय स्ट्रिंग के साथ लिखे जाने पर लॉग करती है.

trustedTypes.createPolicy("default", {
  createHTML(value) {
    console.warn("String passed instead of Trusted Type.");
    return DOMPurify.sanitize(value, { RETURN_TRUSTED_TYPE: false });
  },
});

ट्रस्टेड टाइप के साथ काम करने वाले सामान्य सिंक में ये शामिल हैं:

  • एचटीएमएल: element.innerHTML, element.outerHTML, document.write(), element.setHTMLUnsafe(), Document.parseHTMLUnsafe()
  • स्क्रिप्ट: <script> टेक्स्ट कॉन्टेंट, eval()
  • ScriptURL: <script src>, Worker(), SharedWorker()
// Assign the TrustedHTML object.
element.innerHTML = cleanHTML;

ध्यान दें कि एचटीएमएल को "सुरक्षित" तरीके से सैनिटाइज़ करने के लिए (element.setHTML() और Document.parseHTML(), जिन्हें असुरक्षित एचटीएमएल को सैनिटाइज़ करना में शामिल किया गया है), भरोसेमंद टाइप की नीति की ज़रूरत नहीं होती. ऐसा इसलिए, क्योंकि वे संभावित एक्सएसएस हमलों को हमेशा नेटिव तौर पर सैनिटाइज़ करते हैं.

4. सीएसपी की मदद से, Trusted Types को लागू करना

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

ज़रूरी शर्तें

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

रोलआउट की रणनीति

  1. सिर्फ़ रिपोर्ट: सबसे पहले, Content-Security-Policy-Report-Only हेडर का इस्तेमाल करके रोल आउट करें. इससे, उल्लंघन करने वाले अनुरोधों को ब्लॉक किए बिना, उन्हें आपके रिपोर्टिंग एंडपॉइंट पर लॉग किया जाएगा.

    Content-Security-Policy-Report-Only: require-trusted-types-for 'script';
    
  2. नीति उल्लंघन ठीक करने का तरीका: नीतियों को इंटिग्रेट करने और उल्लंघन की रिपोर्ट शून्य होने के बाद, नीति उल्लंघन ठीक करने के तरीके को पूरी तरह से लागू करें.

    Content-Security-Policy: require-trusted-types-for 'script';
    

यह भी तय किया जा सकता है कि कौनसी नीतियां बनाई जा सकती हैं. इसके लिए, अपनी नीतियों के नाम की सूची बनाएं, जैसे कि sanitize-html या escape-html. अगर आपकी नीति DOMPurify.sanitize() को डेलिगेट करती है, तो dompurify को शामिल करें. इससे, अंदरूनी तौर पर dompurify नीति बनती है. अगर माइग्रेशन के दौरान कोई डिफ़ॉल्ट नीति रजिस्टर की जाती है, तो default को शामिल करें:

Content-Security-Policy: require-trusted-types-for 'script'; trusted-types sanitize-html escape-html dompurify;

इस सीएसपी के लागू होने पर, सिंक में कुछ भी लिखने के लिए भरोसेमंद टाइप का इस्तेमाल करना ज़रूरी है. ऐसा न करने पर, गड़बड़ी का मैसेज दिखेगा. इसके अलावा, अगर किसी ऐसे नाम से ट्रस्टेड टाइप की नीति बनाने की कोशिश की जाती है जो trusted-types में मौजूद नहीं है, तो गड़बड़ी का मैसेज दिखेगा.

इस सीएसपी को अपने दस्तावेज़ के <head> में <meta> टैग के तौर पर भी सेट किया जा सकता है. हालांकि, ऐसा करना कम सुरक्षित हो सकता है.

<!-- First child of `<head>`, as earlier tags will not enforce this CSP. -->
<meta
  http-equiv="Content-Security-Policy"
  content="require-trusted-types-for 'script'; trusted-types sanitize-html escape-html dompurify;"
/>

फ़ॉलबैक रणनीतियां

जिन ब्राउज़र में अब तक भरोसेमंद टाइप की सुविधा काम नहीं करती है उनके लिए, "tinyfill" का इस्तेमाल किया जा सकता है. इससे यह पक्का किया जा सकता है कि सैनिटाइज़ेशन की सुविधा देते समय आपका कोड काम करना बंद न करे.

if (!window.trustedTypes) {
  window.trustedTypes = {
    createPolicy: (name, rules) => rules,
  };
}

इससे आपको आज ही ट्रस्टेड टाइप पैटर्न का इस्तेमाल करके अपना कोड लिखने की सुविधा मिलती है. इस सुविधा के साथ काम करने वाले ब्राउज़र, टाइप लागू करेंगे. वहीं, पुराने ब्राउज़र, मॉक नीति के ज़रिए आपके सैनिटाइज़ेशन लॉजिक को लागू करेंगे.

अगर कोई ब्राउज़र, भरोसेमंद टाइप के साथ काम नहीं करता है, तो वह TrustedHTML ऑब्जेक्ट को स्ट्रिंग के तौर पर मानेगा (अगर tinyfill का इस्तेमाल किया जा रहा है) या सिंक लेवल पर नीति उल्लंघन ठीक करने का तरीका लागू नहीं करेगा.