XSS prevention in the Browser by the Browser

#1

Many current Webpages still have to deal with XSS and every Web Developer has to stay up to date with the research and know what the best current XSS prevention engines are.

But why can’t we move the whole XSS prevention from the Web Developer to the Web Browser?

If instead of downloading and getting used to a new library to mask XSS in the Browser, the Web Developer just uses a standard interface to the Browsers XSS prevention, they could be more secure and minimize their bandwidth use.

Such an Browser XSS prevention could save many more resources for the Web Developer.

#2

How would this relate to CSP? Would this be an additional set of protections?

#4

Yes, it would be

#5

I still think that such a protection would give the Frontend Developer more control about which parts of the Webpage should be more secure.

#6

One more thing I want to add to my proposal: A privilege level for JS Code.

This could even be a part of CSP. You would define which JS Files have a higher level, such that they can do things like:

  • Manipulate the DOM
  • Access important Variables inside these Files
  • Access cookies
  • Define Functions to call from low privileged JS

And you should not privilege the inline JS.

#7

To follow on from our previous discussion on the Firefox Security Mailing List…

I’d suggest looking at the proposed sanitize/purification function first, so the Browser will filter out the XSS issues (using it’s parser to strip JavaScript):

document.getElementById('xss_output').innerHTML = sanitize(user_input);

Then enforce it’s use with “Trusted Types”, as discussed in this issue (the repo is about how Trusted Types will hopefully work one day):

And to top that off, add a Content Security Policy to enforce the use of Trusted Types, and limit JavaScript to known sources/content.

So in summary…


Content-Security-Policy: default-src 'none'; ...; script-src https://example.com/js/; trusted-types example;

var exampleTrustedTypes = {
    'createHTML': function (s) {
      return sanitize(s);
    }
  };
if (window.TrustedTypes) {
  exampleTrustedTypes = TrustedTypes.createPolicy('example', exampleTrustedTypes);
}
document.getElementById('xss_output').innerHTML = exampleTrustedTypes.createHTML(user_input);

Note: The script-src must not contain JSONP (so disable any kind of scripting language like PHP in that folder, ref “php_admin_flag engine off”), it must not allow the Web Server process to write to those files (e.g. the www-data user, which might be running a PHP script from somewhere else on the site, like an image uploader, should not be able to write to this folder), and it should not include anything like AngularJS with it’s unsafe templating system (more info).

#8

All this is based on what I understood from the information about Trusted Types I read and looked into in the past two days.

First: TrustedTypes are a good tool that should certainly be developed further. But it shouldn’t be the whole XSS prevention by the browser, because the browser has many more opportunities to prevent XSS, that it just doesn’t use yet.

One of my objections to TrustedTypes is that it still puts the security decision of whether to allow some code to be passed into the page or not to the developer.

They are a way of centralizing the security reviews and reduce the efforts a web developer has to put into security implementation and review, but they still leave the responsibility of protecting the user of both the web site and the browser to the web developer or third party libraries.

I think that we need to put that responsibility into the hand of the browser and its developers, who also happen to have the best set of privileges, the most control, to fight XSS.

TrustedTypes are a good first protection, upon which we have to build more.

And this is what you have already done with your example.

I think there are many ways how XSS can get into the site and we shouldn’t try to prevent all of them in the browser, but rather we should try to act while XSS-Code is in the Websites JS ( here a sanitizer would be one of many options ) and after it is passed into the Browser to be displayed and executed ( here disableScripts and such other measures would be placed).

#9

My goals here

I want to work on approaches for how the browser could use its capabilities to stop XSS between a little bit before the XSS is injected and until any JS is executed. I’ll give two of my proposals here:

1. Blocking JS Execution locally

Craig and I have already discussed this previously on the dev-security mailing list by Mozilla. I gave two very concrete proposals, but they both nether made my abstract concern clear enough nor did it made my thread mode obvious. Thus I want to do this here:

If you block execution of JS inside some part of your web page, that part where you plan to insert user input, your page could gain a giant advantage against XSS attackers. Because the place where you want to insert user input, is often defined early on in the development and you can set this level of security up before writing any of the more complex code of your web page. I’d argue that this reduces the time each developer has to put into sanitizing and so forth for each user controlled output.

2. Levels of privilege for different JS Code

The main problem CSP tries to solve is XSS by inline JS or execution from an unintended source. But how CSP goes about doing so is really inappropriate, and many current projects are unable to adapt to what CSP is sometimes enforcing. I think that an approach that leaves more control to the web developer is the better choice here, where it actually affects how they go about designing their web pages. Thus what if certain code, your main.js file for example, would have the privilege to access the DOM, cookies, etc., while other files, inline JS or third-party libraries have to call the functions inside your main.js File to access those things. You could more tightly control what happens to security relevant features and data if that can only happen in one or a few places, not on the whole web page. But with this approach you could still write a little inline JS to execute an Event Listener, or set some variables, many projects would still have to adapt, but they wouldn’t have to rebuild the architecture, just move some of the DOM manipulation and cookie handling into a central place and only let it be accessed by secure function calls.

These are my two current proposals, I tried to make them not too concrete as to allow you to first judge the idea and then work on the implementation.

#10

I can’t see how different privilege levels for JS code could work in practice. The main problem is the call stack could have scripts from different privileges. What do you do then?

For example suppose you have main.js (app logic), util.js (a library), and evil.js (some attacker script). Suppose you set up the privileges so only util.js has privilege to edit the DOM (e.g. elem.appendChild()), which it uses for a library method MyLib.AddElement(). main.js then calls MyLib.AddElement() to make DOM manipulations.

Suppose for extra security you remove main.js’s privilege to edit the DOM directly and rely only on util.js. Now you have a case where an unprivileged script (main.js) can make DOM alterations simply by calling library methods in the privileged util.js. That means evil.js also has the same capabilies as main.js, resulting in no meaningful protection.

Alternatively you can give main.js prvilege to edit the DOM directly, and require that the entire call stack has the privelege. Now main.js has no extra protections to the situation before privileges were added, so it is still vulnerable to injection attacks, etc - resulting in no meaningful protection.

I can’t see a good solution to this that results in better security in practice. I think the best approach is to use existing protections like CSP, and if you have untrusted script you want to isolate, you can use a sandboxed iframe or web worker to run it in, where it has no direct access to the DOM. Then you can impose restrictions on the postMessage() bridge.

#11

The advantage of privileges for different JS sources is that you can centralize all your manipulation of sensible data or security relevant features. Think about the privileged code as an interface for unprivileged code to access security relevant data or features, but only those the privileged code allows them to access and only in such a way that the privileged code has control about what happens.

Imagine for example that a web page has an error reporting system.

If unprivileged code would reach an error that the user should know about, like invalid input, the unprivileged code, that couldn’t access the DOM, call alert() or in anyway directly communicate with the user, would call a function inside the privileged code called something like error_wrong_input(error_code). And now instead of directly manipulating the DOM, the unprivileged code, that could be XSS, has alerted the user, but not actually manipulated the DOM in a custom way, deferring to an error code to display a predetermined message without any risk of XSS.

This couldn’t just be used for error messaging of course, interaction with a server or the use of some confidential data should also be tightly controlled and more importantly shouldn’t be accessed directly by inline JS, that could be XSS.

And, as I think of them, privileges shall prevent XSS injected in the page from accessing confidential data or interacting with the user, not a lot else.

These problems many people agree to be important factors for why XSS is still so important, although we know about it for more than a decade. XSS is:

  • difficult to spot
  • difficult to prevent
  • devastating, even if only one XSS exists in the whole page

I think to disable JS locally may address the second point, while privilege levels for JS address the last one. It could reduce the harm a single unmasked line of user input inserted into the page at an unprivileged point could do.

And I think that inline JS, if privileges are enabled, should be unprivileged by default, always referring to a privileged sources that can’t be manipulated by the user, for handling any of the security related data or features.

And CSP is thus far not enough, in that it has not enough options and thus usage for large projects, because it doesn’t give them the options privileges could.

#12

You haven’t addressed the point I made. You just described the idea some more. How would you actually solve the problem of having differently privileged scripts in the call stack?

#13

I think that goes very deep into the implementation before discussing merits and faults of privileged JS. Thus don’t think of the idea bad only because my approach at implementing it isn’t the best But I’ll try to give you an idea of how this maybe implemented.

The Stacks behavior shouldn’t change dramatically

I’ll only make a small addition to the stack frames of JS functions. But first I need to outline the rules for my implementation of privileged JS: In my implementation there would be three different levels of privilege for the JS engine:

Unprivileged Default
Privileged Can call functions that require privilege and can be called by unprivileged functions
Require privilege Require at least privilege to be executed

By default all functions that are neither part of a standard about security relevant features nor privileged by the web developer are unprivileged. They thus can only call privileged functions that in turn can call functions that require privilege to be executed. The privileged functions are those I talked about above and those functions that require privilege are those that are security relevant features (DOM,etc.).

How to call functions and return from them

To implement these rules the JS engine would assign each function a privilege level, if none is defined by the standards or by the web developer (in a way not yet clearly defined) the engine defaults to unprivileged and adds this info to the function after interpreting the function definition. On each function call, the engine would then check if the two privilege levels, the one of the caller and the called, match and throw an error if not. If the check passes the Stack frame of the called function is pushed, together with a small info about the functions privilege level.

Returning

After the function returns the old privilege level from the function on the stack below that one is adapted.

Conclusion

I don’t think that, if none of the JS functions can interfere with the part of the Stack frame regarding the privilege level, this implementation should be save. And I’m also not thinking that a function should be able to change its privilege level, ever!

I hope that this proposal helps you understand how I would manage a Stack with functions with multiple privilege levels, but I am sure that it can be ensured that functions can live on the same stack, while having different privileges. After all JVM and the Stack of C and C++ programs did that for a long time and there are thus many developers with experience enough to build such a stack for browsers.

#14

Once again, you haven’t addressed the point I made. You just described how privileges might work. My point was that they fundamentally do not offer any meaningful protection.

#15

Why don’t they? They let XSS injected in a web page by accident not access such things as DOM or cookies? What is security, if not this?

#16

I believe that this does not offer any meaningful protection, as I explained in my earlier post. If you only respond by explaining in more detail how the feature would work, you are not addressing my point that I do not believe it offers any meaningful protection.

#17

I admit, I don’t quit understand why you believe that privileges offer no meaningful protection against inline XSS. Could you please explain that further?

#19

Imagine the following: A project has these two files:

  • main.js
  • index.php Inside index.php there is a small bug that allows user input to be directly inserted into the page.

What would happen if an attacker would try to insert XSS and there wouldn’t be privileges enabled?

He could do everything current XSS attacks do, steal cookies, bank account data, manipulate the appearance of the page, etc.

What would happen if privileges were enabled?

Assume the web developer assigned the main.js to be privileged, while index.php and thus all inline JS and XSS inserted there to be unprivileged. What could an attacker then do with his XSS vulnerability? If he tried to access any of the security relevant features, the browser would throw an error and report to the web developer about the incident. He thus has only one option, to analyze the functions in main.js and look for a way to directly access one of the security relevant features, that he is blocked from using directly in index.php. Thus the capabilities of the attacker were greatly diminished, he can’t anymore access everything freely, but is constrained by functions that the web developer himself designed. I think that with the right design, these functions could leave ever less space for the attacker to exploit an XSS.

To answer another question of yours: This is better then CSP, because it still allows for inline JS, and just diminishes the risk of such inline JS introducing dangerous XSS.

If this still didn’t address your point, I urge you to explain it further, because I evidently didn’t understand it.

#20

CSP already controls whether or not you can run scripts. It also already provides tools to safely use inline scripts (e.g. nonce/hashes), so I’m not sure you fully understand what CSP can do.

My point is assuming you can bypass the restrictions of a well-configured CSP, you have two possible situations:

  • if unprivileged scripts can still perform privileged tasks by calling priviliged scripts, there is effectively no extra protection. In practice there are likely to be library scripts, which would necessarily have to be privileged, so the attacker just needs to call that instead.

  • if privileged tasks require the entire call stack to be privileged, then in practice you are likely to have to mark every script allowed by CSP as privileged for the code to continue to work. This adds no extra protection beyond CSP.

In short, I believe CSP already provides all the necessary controls to adequately control XSS. I suggest looking up all the capabilities it provides, there are lots of tools to configure which scripts are allowed to run, and it seems like you haven’t fully appreciated that.

#21

If you weight the complexity of a secure privilege system against the possible advantage for the security of a site, it seems to me that privileges shouldn’t be implemented as I explained them. But I’m still convinced that disabling the execution of JS for user input that is inserted into a page gives you both a low level of complexity and a high level of security to prevent XSS.

#22

But I’m still convinced that disabling the execution of JS for user input that is inserted into a page gives you both a low level of complexity and a high level of security to prevent XSS.

Yep, and that is exactly what CSP does.