Skip to main content
added 1561 characters in body
Source Link

Other prevention approaches: JWT

JSON Web Token is quite a popular alternative to cookies + synchronizer token pattern circa 2020.

What this method does is:

  • store a signed token in window.localStorage
  • whenever you want to make an authenticated request to the server, send a header Authentication: <token>. Note that this can only be done from JavaScript.

This method works because unlike cookies, localStorage is only available when you make requests from the website itself (through JavaScript), thus dispensing the synchronizer token.

Then, when users first visit the website, they are initially logged off, and a dummy loading page shows.

Then the browser runs the JavaScript is just received from the server, reads localStorage (now that we are on the correct domain already) and sends an authenticated GET request to an API path to get only the data without HTML, usually as JSON.

Finally the JavaScript renders that data on the browser.

This approach has become particularly popular due to the popularity of Single Page Applications, where the simplest implementation approach is this two-step get dummy page then populate it with the API data.

So this basically carries the tradeoffs:

  • advantages:
    • simpler to implement since no synchronizer on every form
    • the usual SPA advantages: you get only data after the initial request, not HTML tags
  • disadvantages:
    • the usual SPA disadvantages:
      • during first load the user might see annoying loading dummy page elements
      • the website is not visible without JavaScript

See also

See also

Other prevention approaches: JWT

JSON Web Token is quite a popular alternative to cookies + synchronizer token pattern circa 2020.

What this method does is:

  • store a signed token in window.localStorage
  • whenever you want to make an authenticated request to the server, send a header Authentication: <token>. Note that this can only be done from JavaScript.

This method works because unlike cookies, localStorage is only available when you make requests from the website itself (through JavaScript), thus dispensing the synchronizer token.

Then, when users first visit the website, they are initially logged off, and a dummy loading page shows.

Then the browser runs the JavaScript is just received from the server, reads localStorage (now that we are on the correct domain already) and sends an authenticated GET request to an API path to get only the data without HTML, usually as JSON.

Finally the JavaScript renders that data on the browser.

This approach has become particularly popular due to the popularity of Single Page Applications, where the simplest implementation approach is this two-step get dummy page then populate it with the API data.

So this basically carries the tradeoffs:

  • advantages:
    • simpler to implement since no synchronizer on every form
    • the usual SPA advantages: you get only data after the initial request, not HTML tags
  • disadvantages:
    • the usual SPA disadvantages:
      • during first load the user might see annoying loading dummy page elements
      • the website is not visible without JavaScript

See also

added 135 characters in body
Source Link

This is where the SOP comes into play. Although the GET and POST do actually send the authenticated request just like the HTML formGET and POST do actually send the authenticated request just like the HTML form, the sender's browser prevents the JavaScript code from reading the HTML reply back, because the request was sent to a separate domain!

This is where the SOP comes into play. Although the GET and POST do actually send the authenticated request just like the HTML form, the sender's browser prevents the JavaScript code from reading the HTML reply back, because the request was sent to a separate domain!

This is where the SOP comes into play. Although the GET and POST do actually send the authenticated request just like the HTML form, the sender's browser prevents the JavaScript code from reading the HTML reply back, because the request was sent to a separate domain!

withCredentials
Source Link

Without further security measures, this would:

  • the request does get sent. The SOP does not forbid this request from being sent.
  • it includes authentication cookies from bank.com which log you in. As mentioned at "Are all cross-origin requests forbidden?" below, sending cookies across domains allows you for example to click a <a link to bank.com and go to that website already logged-in, which is what users generally want.

So if evil.com makes a post single request, hethey would never guess that token, and the server would reject the transaction!

$.getajax({
  url: 'http://bank.com/transfer',
  type: "GET",
  xhrFields: {withCredentials: true},
});
// Parse HTML reply and extract token.
$.postajax({
  url: 'http://bank.com/transfer',
  type: "POST",
  data: {
    to: 'ciro',
    ammount: '100000000',
    authenticity_token: extracted_token
  },
  xhrFields: {withCredentials: true},
});

Here the attacker used withCredentials: true because XHR does not send cross request cookies without it, see also: Why are cookies sent with HTML page's cross domain requests but not with JS's XHR?

This is where the SOP comes into play. Although the $.getGET and $.postPOST do actually send the authenticated request just like the HTML form, the sender's browser prevents the JavaScript code from reading the HTML reply back, because the request was sent to a separate domain!

Without further security measures, this would:

  • the request does get sent. The SOP does not forbid this request from being sent.
  • it includes authentication cookies from bank.com which log you in

So if evil.com makes a post single request, he would never guess that token, and the server would reject the transaction!

$.get('http://bank.com/transfer')
// Parse HTML reply and extract token.
$.post('http://bank.com/transfer', {
  to: 'ciro',
  ammount: '100000000',
  authenticity_token: extracted_token
})

This is where the SOP comes into play. Although the $.get and $.post do actually send the authenticated request just like the HTML form, the sender's browser prevents the JavaScript code from reading the HTML reply back, because the request was sent to a separate domain!

Without further security measures:

  • the request does get sent. The SOP does not forbid this request from being sent.
  • it includes authentication cookies from bank.com which log you in. As mentioned at "Are all cross-origin requests forbidden?" below, sending cookies across domains allows you for example to click a <a link to bank.com and go to that website already logged-in, which is what users generally want.

So if evil.com makes a post single request, they would never guess that token, and the server would reject the transaction!

$.ajax({
  url: 'http://bank.com/transfer',
  type: "GET",
  xhrFields: {withCredentials: true},
});
// Parse HTML reply and extract token.
$.ajax({
  url: 'http://bank.com/transfer',
  type: "POST",
  data: {
    to: 'ciro',
    ammount: '100000000',
    authenticity_token: extracted_token
  },
  xhrFields: {withCredentials: true},
});

Here the attacker used withCredentials: true because XHR does not send cross request cookies without it, see also: Why are cookies sent with HTML page's cross domain requests but not with JS's XHR?

This is where the SOP comes into play. Although the GET and POST do actually send the authenticated request just like the HTML form, the sender's browser prevents the JavaScript code from reading the HTML reply back, because the request was sent to a separate domain!

added 207 characters in body
Source Link
Loading
deleted 204 characters in body
Source Link
Loading
Updated OWASP cheatsheet link (they have changed their website structure)
Source Link
Loading
added 124 characters in body
Source Link
Loading
added 552 characters in body
Source Link
Loading
added 15 characters in body
Source Link
Loading
replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link
Loading
replaced http://security.stackexchange.com/ with https://security.stackexchange.com/
Source Link
Loading
added 182 characters in body
Source Link
Loading
added 102 characters in body
Source Link
Loading
added 268 characters in body
Source Link
Loading
added 626 characters in body
Source Link
Loading
Clarified again thanks to comments
Source Link
Loading
Loading
added 278 characters in body
Source Link
Loading
deleted 1 character in body
Source Link
Loading
added 1660 characters in body
Source Link
Loading
Source Link
Loading