javascriptgreasemonkeycorsuserscriptsgm-xmlhttprequest

What HTTP origin does GM_xmlhttpRequest send?


I want my app with a REST API to be accessible in different flavors:

I want to limit the list of sites for my app to be accessible from by a whitelist.

I know how to do it with CORS but I'm not sure if it works with GM_xmlhttpRequest the same way since GM_xmlhttpRequest does not require the Origin header to be sent back from a server.

I don't care for a client but I still need to check on a server from which site the request was sent and answer with something like {response:"site not supported"} if it isn't in a whitelist.

So, when I run a userscript on some webpage and make a GM_xmlhttpRequest, can the server detect the origin?


Solution

  • You cannot use the Origin header to reliably restrict access by userscripts to your API.

    By default, GM_xmlhttpRequest()Doc does not send the Origin header at all. Nor does GM_xmlhttpRequest block cross-site requests; that is the main reason that GM_xmlhttpRequest exists.

    Also, for Greasemonkey (Firefox) and Tampermonkey (Chrome), GM_xmlhttpRequest does not send the referer header, by default.

    However, both headers can be overridden to be whatever the script-writer wants.

    Here is a demo script that spoofs both headers (use a packet sniffer to see for yourself):

    // ==UserScript==
    // @name        _Test Fake Referrer
    // @include     http://stackoverflow.com/questions/18178934/*
    // @grant       GM_xmlhttpRequest
    // ==/UserScript==
    
    GM_xmlhttpRequest ( {
        method:     "GET",
        url:        "http://www.google.com",
        headers:    {
            referer:  "http://microsoft.com",
            origin:   "http://microsoft.com"
        }
    } );
    



    A plain Chrome userscript is not so kind to the script developer. Native Chrome userscripts never send the Origin header and always send the current page as the referer.

    If you try to spoof either of these headers, the console will show errors like:

    Refused to set unsafe header "referer"
    Refused to set unsafe header "origin"

    This is one more reason to use Tampermonkey for your Chrome userscripts.