GithubHelp home page GithubHelp logo

jQuery Plugin about dompurify HOT 16 CLOSED

devd avatar devd commented on July 24, 2024
jQuery Plugin

from dompurify.

Comments (16)

cure53 avatar cure53 commented on July 24, 2024

We can do this without problems, simply using the SAFE_FOR_JQUERY flag is sufficient to produce safe output. So, we could either overwrite elm.html() and friends or provide an alternative API, prefixed with safe*.

I'd however like it more if we overwrote stuff and offer the old methods prefixed with unsafe* (doing it CSP-style). Any thoughts?

So, a possible work-flow for the plugin could be:

  1. Get included
  2. Overwrite all jQuery DOMXSS sinks
  3. Offer the old methods with prefix unsafe*
  4. Done

from dompurify.

kozmic avatar kozmic commented on July 24, 2024

+1, overriding is fine.

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

There's tons of documentation of how we can do it (meaning to override jQuery core functionality). Ben Nadel has published this some years ago. Is that still the best way to do it?

http://www.bennadel.com/blog/1624-ask-ben-overriding-core-jquery-methods.htm

Should we maintain the plugin here or in a separate project? I'd personally opt for a separate project - but might be wrong. @fhemberger what thinks you?

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

Naive approach could look like this.
And we'd have to do it for all DOMXSS sinks:

(function(){
    // Store a reference to the original remove method.
    var unsafehtml = jQuery.fn.html;

    // Define overriding method.
    jQuery.fn.html = function(){
        // Log the fact that we are calling our override.
        console.log( "Use DOMPurify for both get and set" );

        // Expose the original method.
       jQuery.fn.unsafehtml = unsafehtml;
    }
})();

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

About the interface we should expose with this / methods we technically should overwrite:

jQuery.fn.purify() // same as DOMPurify but using SAFE_FOR_JQUERY flag by default

// write access 
jQuery.fn.add( xss1 ) // purify first argument, string or Node
jQuery.fn.append( xss1, xss2, xss3 ) // purify all arguments, each string or Node
jQuery.fn.after( xss1, xss2, xss3 )  // purify all arguments, each string or Node
jQuery.fn.before( xss1, xss2, xss3 ) // purify all arguments, each string or Node
jQuery.fn.html( xss1 ) // purify first argument, string, function or Node
jQuery.fn.prepend( xss1, xss2, xss3 ) // purify all arguments, each string or Node
jQuery.fn.replaceWith( xss1 ) // purify first argument, string or Node
jQuery.fn.wrap( xss1 ) // purify first argument, string or Node
jQuery.fn.wrapAll( xss1 ) // purify first argument, string or Node

Now, I am wondering. Should we also purify any HTML string that is being returned? For instance when using $(elm).html()? Should we also sanitize nodes that are being returned? Or would that be too invasive?

What worries me a bit is the flexibility of jQuery's APIs. Looking at jQuery.fn.html for example, this method accepts (at least) three types of arguments that might leads to XSS:

$('body').html(function(){return '<svg onload=alert(1)>'});

$('body').html('<svg onload=alert(2)>');

var img = document.createElement('img');
img.src=123;
img.onerror=function(){alert(3)}
$('body').html(svg)

Then again, jQuery.fn.add allows to use strings, selectors, selections, nodes and node collections and all of them can lead to XSS. This is horrible to cover and once the API changes slightly we have to change our code too. Which sucks even more.

So, ideally, we'd inject our fine selves at a far more central point to have good coverage. Any thoughts on this?

from dompurify.

fhemberger avatar fhemberger commented on July 24, 2024

I don't think that you have to overwrite too many functions, e.g. jQuery.fn.wrap() =uses=> jQuery.fn.wrapAll() =uses=> jQuery.fn.append(). I guess the interesting parts will be in manipulation.js.

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

True, many calls end up arriving in jQuery.fn.domManip.

(function(){
  var originalMethod = jQuery.fn.domManip;
  jQuery.fn.domManip = function(){
    console.dir(arguments);
    originalMethod.apply( this, arguments );
  }
})();
$('body').append('<svg onload=alert(1)>')

Sadly, not all of them. What worries me most is elm.html(fn).

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

So, I've built a very first, very naive prototype for a quick sanity check, feedback appreciated:

jpurify.js

(function(){
    /**
     * Define a safe elm.html() method for jQuery
     * 
     * + Replaces elm.html()
     * + Exposes original method as elm.unsafeHtml()
     */
    jQuery.fn.unsafeHtml = jQuery.fn.html;
    jQuery.fn.html = function(){
        if(arguments && arguments[0]){
            if(typeof arguments[0] === 'string' || arguments[0].nodeName){
                arguments[0] = DOMPurify.sanitize(arguments[0]);
            }
        }
        jQuery.fn.unsafeHtml.apply(this, arguments);
    };

    /**
     * Define a safe elm.domManip() method for jQuery
     * 
     * + Replaces elm.domManip()
     * + Protects elm.append()
     *            elm.prepend()
     *            elm.before()
     *            elm.after()
     *  + Exposes original method as elm.unsafeDomManip()
     */
    jQuery.fn.unsafeDomManip = jQuery.fn.domManip;
    jQuery.fn.domManip = function(){
        if(arguments && arguments[0]){
            for(var i in arguments[0]){
                arguments[0][i] = DOMPurify.sanitize(arguments[0][i]);
            }
        }
        jQuery.fn.unsafeDomManip.apply(this, arguments);
    };

    /**
     * Define a safe el.wrapAll method for jQuery
     * 
     * + Replaces elm.wrapAll()
     * + Protects elm.wrapAll()
     *            elm.wrap()
     *            elm.wrapInner()
     * + Exposes original method as elm.unsafeWrapAll()
     */
    jQuery.fn.unsafeWrapAll = jQuery.fn.wrapAll;
    jQuery.fn.wrapAll = function(){
        if(arguments && arguments[0]){
            if(typeof arguments[0] === 'string' || arguments[0].nodeName){
                arguments[0] = DOMPurify.sanitize(arguments[0]);
            }
        }
        jQuery.fn.unsafeWrapAll.apply(this, arguments);
    }; 
})();

test.html

<html>
    <head>
        <script src="jquery.js"></script>
        <script src="purify.js"></script>
        <script src="jpurify.js"></script>
    </head>
    <body>
        <div id="html"></div>
        <div id="append"></div>
        <div id="wrap"></div>
        <script>
            $('#html').html('<h1>XSS<svg/onload=alert(1.0)>');

            // no protection yet $('<svg/onload=alert(1.1)>')
            // no protection yet $('#html').html(function(){return '<h1>XSS<svg/onload=alert(1.2)>'});

            $('#append').append('<svg/onload=alert(2.1)>', '<svg/onload=alert(2.2)>');
            $('#append').prepend('<svg/onload=alert(2.3)>', '<svg/onload=alert(2.4)>');
            $('#append').before('<svg/onload=alert(2.4)>', '<svg/onload=alert(2.5)>');
            $('#append').after('<svg/onload=alert(2.6)>', '<svg/onload=alert(2.7)>');

            $('#append').wrap('<svg/onload=alert(4.1)>');
            $('#append').wrapInner('<svg/onload=alert(4.2)>');
            $('#append').wrapAll('<svg/onload=alert(4.3)></svg>');
        </script>
    </body>
</html>

from dompurify.

devd avatar devd commented on July 24, 2024

This is fantastic! Pretty excited about this.

One concern with the console.log for unsafe use was that the safe function uses it too. Just something to keep in mind since we don't want to spam the console :( But, warning on console on unsafe use would be really useful too. Not sure what the right thing to do is. On the other hand, a method called unsafe is obviously a red flag and easily caught with a grep.

from dompurify.

devd avatar devd commented on July 24, 2024

Also, another quick comment: a few developers I talked to said they were bigger fans of creating a new function called safe* instead of monkey patching current use to use the safe version directly and creating new unsafe*.

This is a style issue though. I also think your approach is better; but just wanted to put it in your radar and see what you thought.

(sorry, I had looked into this a while back and paging all of it back is taking a bit of time :)

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

@devd Thanks for the comments :)

We might add a flag to solve the safe/unsafe question. I'd love to follow the strictness of CSP and dictate safety and unsafe to opt out. Rather than the other way round - security imho needs to be opt-out. But with a flag we can mitigate any conflicts I guess ;)

from dompurify.

devd avatar devd commented on July 24, 2024

Couple more questions:

many of the functions take DOM elements, array of DOM elements, (array of) jQuery objects and strings. I think you are correctly handling the string and DOM element case, but not the array cases or the jQuery objects case.

One additional concern: it is safe to manually create a tree of elements manually and then use append or prepend to insert it into the page. We probably shouldn't sanitize a safely created tree (the inline event handlers might intentionally be there). A trick I have seen done in similar functions is to use the fact that a tree was created manually as a proxy for it being safe. So, the code would essentially do "if string, will sanitize; if tree, don't sanitize". This is another setting that could be behind a configuration flag.

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

The code above is just a sanity check, nothing even close to alpha. And yes, later version will of course contain more checks and type handlers. Although we cannot really handle callbacks imho.

As for the tree. I think we should have as few assumptions as possible and sanitize what we can. What if the tree comes from a CORS XHR with response type document? Then your assumption of it being safe would crumble and we had an XSS :)

from dompurify.

devd avatar devd commented on July 24, 2024

thanks! I wasn't sure if you already knew about the array of elements and jquery objects case. I know it definitely surprised me the first time :)

re the tree: definitely agree that default should be safe! I was wondering though if it could be a useful flag to have.

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

@devd Yeah, I read the API docs a while ago and was amazed by the amount of types you can throw into these methods. The callback sucks most as we cannot analyze and secure it. Unless we come up with ba smart wrapper function that passes through all arguments and then sanitizes the return value.

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

@devd @kozmic @fhemberger I created a private project alongside a working prototype and some first, simple tests: https://github.com/cure53/jPurify

Please let me know if you are interested in having a look. I think we should move the discussion there?

from dompurify.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.