Breaking out of Same-Domain Constraints - Something useful


What I had decided earlier was that breaking out of Same-site constraints wasn't that useful. But I thought of an interesting way of using it to break request tokens.

I'm not positive if there's a better name, but one of the biggest recommendations for dealing with XSRF is to use request tokens. You make a really big random number, put it in the user's session, and also put it in a hidden form element on the form. When the user comes back, they carry the token from the form, and the server compares the form token to the session token. If they don't match, fail the request. Theoretically, a user took an XSRF link from another site wouldn't be carrying this token.

But what if there's an XSS vulnerability anywhere on the target XSRF site? Here's the workflow:

  1. Attacker gives the victim script to carry to the injection point on the target site.
  2. This script collects the token value from the hidden form element.
  3. The script generates a request back to the attacker's site. The request back will include the request token.
  4. The attacker site generates javascript to request the ultimate target URL with the token included.
Note that the ultimate page we want to call (order widgets) doesn't have to be the page with the XSS vulnerability. If Change Profile has a scripting vulnerability, we can use that page just to gather the token and carry out the remainder of the attack.

This will work in many cases because the token doesn't include any other information about the requesting site. In order to combat this, the first (obvious) step is to not have any XSS vulnerabilities on pages that hand out tokens. Better yet, don't have any XSS. But if there are any, you also have to somehow tie the token to the page that genned it. So maybe your token generation looks something like:
  • k1 = [large random number]
  • k2 = [key signifying the proper target]
  • token = f(k1 + k2)
  • Store k1 in session
Then the check becomes:
  • k1 = [k1 from session]
  • k2 = [the key for this action]
  • token = f(k1 + k2)
  • compare token to request(token)
This ties a request token to the action that uses the token.

Under normal circumstances, if the user carries a random number that matches what's in the session, it goes through. That number only gets re-generated when they request a new form. And if there's no tying the number the user carries to the action, then any form can post to any action.

kuza55, Anurag Agarwal and all those other cats who like to break out of same-site checks sure are making life difficult. Fortunately, with this, your best bet is to get rid of all your output filtering flaws.