JS Security Notes

Posted on Sat 12 May 2018 in js-security, notes


Context

The post would just gather some of the knowledge i gained over the while working with JS security, most of them are known, this is just a bookmark or reminder or refresher. Do correct me if im wrong or send me a mail if we could add anything.

Browser Knowledge 101

I wont be going over how your typical browser works.For javascript to execute for a common user you need a browser.

Key words to keep in mind.

  • Same Origin Policy:

Long story short, Browsers restricts resources from one origin/domain to be accessed over a different origin/domain in the browser.The policy is set by the browser. For SOP to function it operates on a set of rules, which can be found here https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy - Protocol Changes - SOP Violation - Port Changes - SOP Violation - Subdomain - SOP Violation

You could just run chromium-browser --disable-web-security to see that now the browser doesnt give a fuck about the same origin policies.

A few relative things to SOP:

If you just understood SOP and noticed the word "restricts", then this might make sense:

- Even with SOP, browser allows you to make requests to different domain, just that you cannot read the response.
- Having SOP doesn't protect you from CSRF, reason you dont need to read the response and you just need to initiate the attack or do the damage.You need to use csrf tokens or same-site cookies.
- SOP can be bypassed through DNS rebinding for local servers, since the whole point of the attack is you nw talk to the localhost through a lesser ttl and you can now read the data.DNS rebinding can be mitigated through the host-header.
(https://medium.com/@rhodey/walking-past-same-origin-policy-nat-and-firewall-for-ethereum-wallet-control-30c29b73a057, https://github.com/mpgn/ByP-SOP)
- SOP policies can be circumvented through a series of genuine methods, which will be discussed later.
  • Understanding Window, Parent and child

Majority of the things in JS and its implementation in real case scenarios depends on window, so window is the thing you see on the screen.

The reference to window.parent is a reference to the current window or subframe. So if a an i-frame is being loaded then the iframe is child and the window.parent is the parent to the iframe-child.(This can be for iframes, object or frames)

the window.parent can be accessed by the child i-frame only if its on the same-domain, the SOP applies here as well.

  • Bypassing the SOP

There are a set of genuine methods that can be used to circumvent SOP.Lets see the avaiable methods and exceptions

- SOP applies partially for script and img tags

SOP does not apply to script with src tags and img tags, thats the reason you are able to see the scripts being loaded.Now the next question is if the site is able to load the JS, we could just query an endpoint to read the content of that site right great!!,

No you wont, if you actually load an endpoint lets say <script src="https://money.com/getbalance"></script>,The browser wouldn't allow you to access the content of the script, you can verify this for yourself here by opening up an console and querying for document.scripts[0].textContent , you would see the null here.(document.scripts allows you to see all the scripts being loaded within the site).

There are other factors such as even lets say the getbalance has some js, the endpoint "/getbalance" is being served with MIME text/html and X-content-type-options: nosniff eventhough if the content-type options header is missing most modern browsers dont allow you to sniff the content-type.(MIME is the multimedia type you want to serve as)

Inshort the script through src just loads and executes.

- POST Message circumvention

Post message is used as a circumvention for SOP. SOP allows parent windows/frames of cross origins to communicated among each other e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it. (Source Moziila)

The POST message implementation has a recieving end as well as sending end. The recieving end has a event listener which listens for any messages from the postMessage call made to the origin.

Usuall pitfalls has the listener implemented to listen on calls from any source which allows other sources loaded to interact with the recieving window.

An example can be seen here:

var message = document.getElementById('message');

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event)
{

    message.innerHTML = event.data; // If this done, origin is not verified here and an attacked could load malicious content here.

    if (event.origin !== "http://example.org:8080") // If the origin is verified
        return;
}

// Source developer.mozilla.org
- Cross Origin Resource Sharing (CORS)

CORS is yet another legitamate method for bypassing same origin policy.CORS allows cross-domain resources to be shared across.The CORS is specified in the header by the site which you wish to access by the Allow-Access-Origin-Header.CORS allows only origin-list-or-null (which is an origin or the string null) within the header.Before a CORS request is done a pre-flight request is done to check whether the site supports CORS or not, this is usually done in the case of a POST request and not in the case of a GET request.By defualt CORS only allows for GET and POST requests.

Any other requests to be specified has to use Access-Control-Allow-Methods header and specify the method.

eg: Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE

There are most commonly two ways Allow-Access-Origin-Header are implemented - One with Allow-Access-Origin-Header: * , which allows all sites to access it. - The other being Allow-Access-Origin-Header: specific-domain.com as we had discussed above (origin-list-or-null) (You cannot allow all sub-domains, ie: https://*.google.com)

CORS by defualt does not allow credentials or cookies to be shared across. For this another header Access-Control-Allow-Credentials should be set to true.

The Access-Control-Allow-Credentials: true and Allow-Access-Origin-Header: * could lead to serious problems, as now any domain could read the resource apis and perform malicious actions on behalf of the user.

Avoid returning Access-Control-Allow-Origin: "null" as it causes a bunch of security issues. (Check out for the resources mentioned below.)

One of the most common mistake seen is accepting the origin header dynamically from the the request and using it within the Allow-Access-Origin-Header,This again is similar to the first method mentioned.

One of the best resources for CORS specification and best practices are: https://w3c.github.io/webappsec-cors-for-developers/#avoid-returning-access-control-allow-origin-null

CORS exploitation resources and reference: https://portswigger.net/kb/papers/exploitingcorsmisconfigurations.pdf

Excercises

Here's a list of files, you could actually open and check and see whats going through.

Update

The article keeps on updating as i get time.