CORS and Other Web Attacks
CORS to loosen SOP, login XSRF
CORS
Cross-Origin Resource Sharing
- The SOP is sometimes too restrictive
- You host a public API that other sites call from their front ends
- Your front end is at
cse312.comand your API is atapi.cse312.com(Different origins!)
- Cross-Origin Resource Sharing (CORS) lets a server relax the SOP for its own responses
- The server approves preflights, and marks which origins may read its responses
- Uses
Access-Control-Allow-*headers
- CORS never makes anything more strict. It only allows things that the SOP would usually block
Preflight - Request
OPTIONS /api/posts/42 HTTP/1.1
Host: api.cse312.com
Origin: https://cse312.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: content-type
Origin- The origin of the page that wants to send the requestAccess-Control-Request-Method- The method of the real requestAccess-Control-Request-Headers- The non-safelisted headers the real request will includeContent-Typeis listed here sinceapplication/jsonis not one of the 3 simple types
Preflight - Response
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://cse312.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 600
Access-Control-Allow-Originmust match the requesting origin (or*to allow all origins)- The requested method and headers must be in the allowed lists
Access-Control-Max-Age- The browser can cache this approval for 600 seconds- The real response must also include
Access-Control-Allow-Origin- Otherwise, the real request is sent, but JavaScript still can't read its response
Access-Control-Allow-Origin
Access-Control-Allow-Origin: https://cse312.com- JavaScript on
https://cse312.commay read this response - Must be a full origin: protocol + host + port
Access-Control-Allow-Origin: cse312.comdoes not work- Only one origin is allowed in this header
- JavaScript on
Access-Control-Allow-Origin: *- JavaScript on any origin may read this response
- Fine for truly public data (A public API, fonts, a CDN)
- Do not use this as a hammer to get rid of your CORS errors!
Other Attacks
Login XSRF
- Normal XSRF: Act as the victim on the victim's account
- Login XSRF: Log the victim into the attacker's account
- The attack page submits your login form with the attacker's username and password
- The victim doesn't notice they're logged into someone else's account
- Everything the victim does is saved to the attacker's account
- Search history, uploaded files, a saved credit card number
- The attacker logs in later and reads it all
- Your login form needs XSRF protection too, even though the user has no authenticated session yet
- Foreshadow: You'll see this again with OAuth and the
stateparameter
- Foreshadow: You'll see this again with OAuth and the
Forging JSON With a Form
<form action="https://bank.com/api/transfer" method="post" enctype="text/plain">
<input type="hidden" name='{"to": "attacker", "amount": 10000, "x": "' value='"}'>
</form>- A
text/plainform sendsname=valuewith no encoding - The body of this request:
{"to": "attacker", "amount": 10000, "x": "="}- Valid JSON! And it's a simple request, so there's no preflight
- If your server parses the body as JSON without checking for
Content-Type: application/json- The attack works, even though your front end only sends JSON with
fetch
- The attack works, even though your front end only sends JSON with
- Although this attack will not contain lax cookies, so it's not too threatening
XSS Defeats XSRF Defenses
- Recall HTML injection (XSS): The attacker's JavaScript runs on your origin
- JavaScript running on your origin can:
- Read your pages, including the XSRF token
- Send same-origin requests that include your cookies
- Every XSRF defense assumes the attacker's code runs on a different origin
- Always escape HTML in user-submitted content
Other Protections
Re-Authentication
- For the most sensitive actions, require the user's current password:
- Changing their password or email address
- Disabling two-factor authentication
- The attacker doesn't know the password, so they can't forge the request
- A confirmation step or CAPTCHA for high-value actions (eg. large transfers)
- These hurt usability. Save them for the actions that matter most