Archived: Emblem Giving is a sample application that demonstrates a serverless architecture with continuous delivery, and trouble recovery. :diamond_shape_with_a_dot_inside:
Cross-site request forgery (CSRF or XSRF) is a security vulnerability whereby one website impersonates an end-user while making a request to another website.
For example, badsite.com might submit a request to cymbalgiving.com/donate pointing to a campaign run by the attacker.
Mitigation
Token generation
The standard way to mitigate CSRF attacks is to include a randomly-generated, secure token in the page, and then ensure that any submitted requests have the proper token value.
There are a few ways to create such a token:
1) Generate tokens arbitrarily, and record them in a database
2) Generate tokens systematically, and verify that the client sends the right token based on the other request elements.
Of these, Option 1 is marginally more secure if the tokens generated are truly random. (Note: most "random" numbers on a computer are in fact pseudo-random numbers based off of a[n ostensibly] random seed value, such as the current UNIX timestamp.)
The risk of Option 2 is that if an attacker somehow managed to understand the app's inner workings, they could (in theory) predict subsequent CSRF token values - and in doing so defeat the point of the token. This is pretty unlikely in the absence of other vulnerabilities, though - and it's also easier for us to implement since it requires no state management.
Recommendation: prioritize ease-of-use (at least for now) and go with Option 2.
Possible token generation systems
In order to generate a token securely, we need to combine several properties together into a single hash. (The more properties, the harder it is to guess the token beforehand!)
A per-session property (such as an ID token) combined with a per-server secret would likely give us a passable level of protection. For additional security, we could also add a per-page value (such as the current URL) and/or a pseudorandom value known as a nonce that would be stored in the page itself. Basically, the more randomness/entropy the token contains, the better.
*Note: longer hashes are exponentially harder to break - think hash cracking difficulty ~ O(c^{input length}) - and much easier to generate (`generation time = O(c {input length})`).
The server secret can be rotated in the event of it being compromised. This would (only) require users with active sessions to log back in to the app, and would be otherwise unnoticeable to end-users.
Recommendation: use the following algorithm to generate CSRF tokens:
def compute_csrf_token(nonce):
server_secret = "some long random string from website/config.py"
// Omit destination URL unless it's easy to get via Flask
csrf_token = bcrypt(firebase_id_token + server_secret + nonce)
def route_get():
nonce = uuid4()
token = compute_csrf_token(nonce)
// Add nonce and token values to rendered HTML
return render_template("blah.html", nonce=nonce, token=token)
def route_post():
nonce = request.form["nonce"]
actual_token = request.form["csrf_token"]
expected_token = compute_csrf_token(nonce)
if expected_token != actual_token:
throw "Invalid CSRF token"
CSRF
Cross-site request forgery (CSRF or XSRF) is a security vulnerability whereby one website impersonates an end-user while making a request to another website.
For example,
badsite.com
might submit a request tocymbalgiving.com/donate
pointing to a campaign run by the attacker.Mitigation
Token generation
The standard way to mitigate CSRF attacks is to include a randomly-generated, secure token in the page, and then ensure that any submitted requests have the proper token value.
There are a few ways to create such a token: 1) Generate tokens arbitrarily, and record them in a database 2) Generate tokens systematically, and verify that the client sends the right token based on the other request elements.
Of these, Option 1 is marginally more secure if the tokens generated are truly random. (Note: most "random" numbers on a computer are in fact pseudo-random numbers based off of a[n ostensibly] random seed value, such as the current UNIX timestamp.)
The risk of Option 2 is that if an attacker somehow managed to understand the app's inner workings, they could (in theory) predict subsequent CSRF token values - and in doing so defeat the point of the token. This is pretty unlikely in the absence of other vulnerabilities, though - and it's also easier for us to implement since it requires no state management.
Recommendation: prioritize ease-of-use (at least for now) and go with Option 2.
Possible token generation systems
In order to generate a token securely, we need to combine several properties together into a single hash. (The more properties, the harder it is to guess the token beforehand!)
A per-session property (such as an ID token) combined with a per-server secret would likely give us a passable level of protection. For additional security, we could also add a per-page value (such as the current URL) and/or a pseudorandom value known as a nonce that would be stored in the page itself. Basically, the more randomness/entropy the token contains, the better.
The implementation itself might look like this:
*Note: longer hashes are exponentially harder to break - think
hash cracking difficulty ~ O(c^{input length})
- and much easier to generate (`generation time = O(c {input length})`).The server secret can be rotated in the event of it being compromised. This would (only) require users with active sessions to log back in to the app, and would be otherwise unnoticeable to end-users.
Recommendation: use the following algorithm to generate CSRF tokens: