2

I am trying existing backend code using JavaScript:

fetch(someURL)
  .then(res => res.json())
  .then(data => console.log(data));

However, I noticed that the response header is saying

content-type: application/x-javascript

so it is not JSON and the .json() call would fail, and the data returned seems to be text and contains:

for(;;);{"_some_var":1,"payload":{  ...   // many properties and values here

What is happening and what is a proper way to get the values returned?

Phil
  • 157,677
  • 23
  • 242
  • 245
Stefanie Gauss
  • 425
  • 3
  • 9
  • 1
    This seems like something that the provider of the API you're calling would be able to explain. – Pointy Dec 07 '22 at 18:00
  • but it seems it is some kind of standard... you know how it is at work, the backend people might have left the company or you really don't know who is currently responsible for the API – Stefanie Gauss Dec 07 '22 at 18:01
  • See: [Preventing the Execution of Unauthorized Script in JSON](https://opensource.adobe.com/Spry/samples/data_region/JSONParserSample.html). While implemented differently in your case, the same principles apply. – Ouroborus Dec 07 '22 at 19:26
  • 1
    @Ouroborus first of all, I have no idea why if I fetch data in JSON format, you will have to inject `for(;;);` or `while(1)` into the response body. Second, if it is not JSON format, what is that hybrid thing for that has code and object at the same time. Third, replacing `while(1)` is so low level grease monkey kind of thing. What if the server returns `for(;;);` then all the front end fail to work? – Stefanie Gauss Dec 08 '22 at 02:35

1 Answers1

3

Seems to be a security measure to prevent JSON hijacking via

<script src="https://example.com/resource.json"></script>

The security hole in the case where this was relevant (pre ES5 / 2011) was that the request would be sent with any existing cookies for the remote domain and the response could contain sensitive data. The loop makes the response unusable in the above context.

The general consensus is for safe clients to remove the token before parsing

fetch(someUrl)
  .then((res) => (res.ok ? res.text() : Promise.reject(res)))
  .then((almostJson) =>
    JSON.parse(almostJSON.replace(/^(while|for)\(.*?\);/, ""))
  )
  .then(console.log);

There's some decent related discussion in this post.

Phil
  • 157,677
  • 23
  • 242
  • 245
  • 3
    Also likely a very outdated "security" measure, since CSRF tokens are common now, and `x-javascript` hasn't been common in at least 15 years or so. – Zac Anger Dec 08 '22 at 03:12
  • 2
    @ZacAnger seems it was made impossible in browsers in 2011 with ES5 – Phil Dec 08 '22 at 03:56