Cross-Site-Request-Forgery, short CSRF, is a type of vulnerabilities that gets more and more attention. The concept can be translated as “tricking the browser into automatically performing some action using the user’s privileges”. Let’s see what phpBB does about it.
The secret behind this is that web applications use cookies to identify the user. Also, cookies get automatically added to every request sent to the cookie’s domain – regardless of the cause of the request. So, if a webpage tells your browser: send a request to that domain, with the parameters X, it will do it — and add your cookie, telling the target domain who you are. Hence, the request gets treated as if you had issued it willingly, using your privileges.
What can be done about it?
Sadly, there is no silver bullet to get rid of CSRF once and for all. But on the other hand, we offer a whole toolkit of measures in phpBB 3.0. So, let’s give you a short tour of our measures:
Referrer Validation
phpBB offers you the option to validate the HTTP Referrer header of incoming POST requests. This is a transparent way of offering a weak CSRF protection. Naturally this does not work at all for requests triggered from the same domain, nor will it work if users use browsers that send no referrer. Moreover, it is easy to suppress the referrer for GET requests, which is why only POST requests get any protection at all.
Usage: N/A
Protects: POST requests only
Security: Rather weak
Pro: Completely transparent.
Contra: POST only, not very secure, users might not send a referrer.
Link Hash
For the protection of GET requests, for instance the bookmark function, we have added link hashes in 3.0.3. While links, i.e. actions via GET, should not alter the application state, it can’t be helped for some lightweight operations. For such operations we have link hashes. The idea is that by adding some secret to every valid (state changing) link, we make it impossible (within the limits of cryptography) for attackers to create valid requests. An attacker would have to know the secret, otherwise the software can tell valid from malicious actions.
Usage:
To use a link hash, you first have to generate it by using the generate_link_hash function. This function takes a single argument – the action that is to be hashed. The rules for the argument are as follows:
- It should not be completely constant, as that does reduce security.
- All invocations of this function on the same page should use the same or few different values. Generating a new hash is expensive, so re-use.
- The php file handling the request needs to “know” the value that was used; i.e. they have to match
This argument is then added to the protected link as “hash”, i.e.
- Code: Select all
...&hash=" . generate_link_hash("{$mode}_$match_id"))
To later check the link hash, the function check_link_hash is used, with the submitted hash and the value that was used to generate the link as arguments. I.e.
- Code: Select all
$token = request_var('hash', '');
check_link_hash($token, "{$mode}_$match_id")
If that returns true, all is well. Otherwise: something fishy might be going on.
Protects: Intended for GET
Security: Reasonable
Pro: Works for links, rather secure, quick for user
Contra: Links have to be altered to include hash.
Form Tokens
The bread-and-butter CSRF protection are form tokens. These form tokens are conceptually the same as link hashes, but are passed via a hidden form field instead of using a GET parameter. Form tokens expire after a time, which can be set in the ACP and are only valid for the given user.
Usage: They are used very similarly to link hashes: First a Token has to be generated (and added to the template variables) by calling the function add_form_key. It takes a single argument, a string describing your form – it is important to use different values for different forms.
- Code: Select all
add_form_key('posting');
Then the {S_FORM_TOKEN} template variable has to be added to the form’s template. The variable contains – after the invocation of add_form_key – a set of hidden fields with all the information required.
To validate a request, check_form_key is used with the same argument that was used to generate the form token.
- Code: Select all
check_form_key('posting')
Like with hashes, true means that all is well.
Protects: POST requests only, intended for reversible actions
Security: Reasonable
Pro: Transparent for user, rather secure
Contra: POST only, needs template changes
Confirm Boxes
The heavy-duty protection are confirm boxes. These boxes are meant to protect irreversible actions and also prompt the user to confirm that s/he really wants to perform the action in question. As a means to improve security, only one confirm box can be used at once. Users with several browser windows sometimes find this irritating.
Usage: The confirm box adds another step in the form submission and thus requires rather extensive changes to the script that uses it. The basic concept of the usage is a if statement, where the THEN part is for performing the action and the ELSE part is for assembling all the data that is needed to reach the same state in the script. The guard is the function confirm_box with the argument true, the ELSE part uses the same function, but with different arguments. These are: false (to show that we are setting up a new confirm box), a language string describing the action and the HTML for hidden fields. The requirement here is that the script reaches the exact same state with the hidden fields as it had when it first hit the confirm_box.
- Code: Select all
if (confirm_box(true))
{
// Perform actual action
}
else
{
$s_hidden_fields = array(
'foo' => $bar,
);
confirm_box(false, $user->lang['Explanation'], build_hidden_fields($s_hidden_fields));
}
The confirm_box function:
Protects: Irreversible actions
Security: Strong
Pro: Secure, Gives feedback
Contra: Just one at a time; User interaction required
Posted by typefreak on January 14th, 2009 at 5:20 pm:
About the “Confirm Boxes”:
Actually, the way you currently describe them ads a very weak sense of security, as it is quite easy to forge two post request with, say, two seconds between them.
If the code generating the $s_hidden_fields array is known, and being open-source, it is, the resulting hidden fields can be easily calculated, completely surpassing the ‘added’ defence.
In order for the ‘Confirm Boxes’ to be actually effective, BOTH stages need to be combined with a correct implementation of ‘Form Tokens’.