javascripthtmljqueryxssredactor

Jquery replacement for .html() function that won't try to rewrite the html on Redactor imperavi - Xss vulnerability


This is treated as a XSS vulnerability issue. I'm using the redactor component from Imperavi, and it seems like it can't generate the right output value when the Html is not valid.

The problem is when we insert strings like this:

<<SCRIPT a=2>qssQ5GkdwWU=7;//<</SCRIPT>

The redactor removes the script tags and generates this string. This is expected because of XSS attacks.

<qssQ5GkdwWU=7;//<

The problem happens then the redactor tries to set the previous value to the redactor element using html.(html). It will think that there is an element and will output this:

<qssq5gkdwwu=7;> </qssq5gkdwwu=7;>

How can I set the value to the element but preventing this behavior?


Solution

  • You can override JQuery's htmlPrefilterfunction:

    htmlPrefilter: function( html ) {
      return html;
    },
    
    

    If special character are the issue then try escaping them like this:

    // trying to set following string as innerHTML
    let c = '<qssQ5GkdwWU=7;//<';
    
    // with default jquery
    $('.one').html(c);
    
    
    // modify filter function, and do your own character escaping 
    jQuery.htmlPrefilter = function(html) {
      let clean = html.replace(/[&<"']/g, function(m) {
        switch (m) {
          case '&':
            return '&amp;';
          case '<':
            return '&lt;';
          case '"':
            return '&quot;';
          default:
            return '&#039;';
        }
      });
    
      return clean;
    }
    
    // now try on second div
    $('.two').html(c);
    <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
    One:<span class="one"></span><br> 
    Two:<span class="two"></span><br>

    Execute above script preferably before you load Redactor.


    If you decide to do your own sanitization then you could use DOMPurify or similar library.

    let content = 'Malicius content <img src="https://dummyimage.com/30" onload="this.style.border=`2px solid red`;alert(`attacked! :p`);" >';
    // default jquery
    $('.one').html(content);
    
    
    // modify filter function, do your own sanitization
    jQuery.htmlPrefilter = function(html) {
      html = DOMPurify.sanitize(html);
      console.log('sanitized: ', html)
      return html;
    }
    
    // trying on second div
    $('.two').html(content);
    <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.4/purify.min.js" integrity="sha512-jGh38w63cHRzfBHtyKgEMMkJswUFXDA3YXrDjaE8ptzxV5DDkLDUDjtGUy5tmDkOXHWsItKfFjocaEtj1WuVnQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    
    One:<span class="one"></span><br> Two:
    <span class="two"></span><br>

    First image gets red border. And because of the sanitization second doesn't.