33

I am trying to play an audio using Google Text-To-Speech. Therefore I need to post a request to their endpoint with the Referer and the User-Agent properly set. This call should return an MP3 that I can play.

However, I get Refused to set unsafe header errors. This is my code. How can I do this?

          $.ajax({
            url: 'http://translate.google.com/translate_tts?ie=UTF-8&q=Hello&tl=en&client=t',
            beforeSend: function(xhr) {
                 xhr.setRequestHeader("Referer", "http://translate.google.com/");
                 xhr.setRequestHeader("User-Agent", "stagefright/1.2 (Linux;Android 5.0)");
            }, success: function(data){
                el.mp3 = new Audio(data);
                el.mp3.play();
            }
          });
Serge Stroobandt
  • 28,495
  • 9
  • 107
  • 102
  • Possible duplicate of [Add Header in AJAX Request with jQuery](http://stackoverflow.com/questions/10093053/add-header-in-ajax-request-with-jquery) – Craicerjack Oct 15 '15 at 08:48
  • 1
    Doesn't matter what header you set, the Google translate endpoint doesn't support CORS – adeneo Oct 15 '15 at 08:49
  • 1
    From cURL it works... –  Oct 15 '15 at 08:51
  • 4
    @Arturo — For cURL you are making the request yourself, you aren't asking your visitor's browser to quietly do it in the background on your behalf. There are lots of extra security restrictions when you try to make other people's browsers do things. – Quentin Oct 15 '15 at 08:57

3 Answers3

52

You can't. It is impossible.

The specification requires that the browser abort the setRequestHeader method if you try to set the Referer header (it used to be that User-Agent was also forbidden but that has changed)..

If you need to set Referer manually then you'll need to make the request from your server and not your visitor's browser.

(That said, if you need to be deceptive about the user agent or referer then you are probably trying to use the service in a fashion that the owner of it does not want, so you should respect that and stop trying).

Note that while jQuery wraps XHR, the same rules apply to fetch.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • Not necessarily. There are a number of privacy-related situations where sending an *empty* referrer and origin are entirely reasonable. For example, suppose you have a government age verification site. A request from your server or from the client with a populated referrer and origin means the government knows exactly who visited specific sites. There's no legitimate reason for any government to know that information, so this *should* be sent anonymously, with no referrer. Of course, one could argue that this is "trying to use the service in a fashion that the owner of it does not want". – dgatwood Apr 28 '23 at 18:29
3

Empty Origin and Referer headers with GET XMLHttpRequest from <iframe>

Well actually, it is possible; at least for ordinary web pages. The trick consists in injecting an XMLHttpRequest function into an empty <iframe>. The origin of an empty <iframe> happens to be about://blank, which results in empty Origin and Referer HTTP headers.

HTML:

<iframe id="iframe"></iframe>

JavaScript:

const iframe    = document.getElementById('iframe');
const iframeWin = iframe.contentWindow || iframe;
const iframeDoc = iframe.contentDocument || iframeWin.document;

let script = iframeDoc.createElement('SCRIPT');

script.append(`function sendWithoutOrigin(url) {
    var request = new XMLHttpRequest();

    request.open('GET', url);

    request.onreadystatechange = function() {
        if(request.readyState === XMLHttpRequest.DONE) {
            if(request.status === 200) {
                console.log('GET succeeded.');
            }
            else {
                console.warn('GET failed.');
            }
        }
    }
    request.send();
}`);

iframeDoc.documentElement.appendChild(script);

JavaScript evocation:

var url  = 'https://api.serivce.net/';
    url += '?api_key=' + api_write_key;
    url += '&field1=' + value;

iframeWin.sendWithoutOrigin(url);

Having the possibility of sending empty Origin and Referer HTTP headers is important to safeguard privacy when using third-party API services. There are instances where the originating domain name may reveal sensitive personal information; like being suggestive of a certain medical condition for example. Think in terms of https://hypochondriasis-support.org :-D

The code was tested by inspecting the requests in a .har file, saved from the Network tab in the F12 Developer View in Vivaldi.

No attempt in setting the User-Agent header was made. Please, comment if this also works.

Serge Stroobandt
  • 28,495
  • 9
  • 107
  • 102
1

There are some header, which browser doesn't allow programmer to set its value in any of the javascript framework (like jQuery, Angular, etc.) or XMLHttpRequest ; while making AJAX request. These are called the forbidden headers: Forbidden Header