Re-Authentication for expired Tokens
Background
The introduction of CSRF Protection migitates the risk of Cross Site Request Forgery (CSRF) attacks on Geeklog sites. At the same time, however, it inconveniences Admin users, since an expired token will invalidate a request and may lead to data loss.
Re-authentication (currently only implemented in the 1.6.2hg development version) attempts to address this problem.
How it works
Following the recommendations for the use of security tokens, a call to SEC_checkToken() will check the token for validity. Previously, that function simply returned false when the token was not valid.
From now on, when SEC_checkToken() detects an invalid token, it will instead display a re-authentication form. This form explains what just happened and asks the user to enter their username and password. If the user provides the correct information, the previous request is recreated and sent again automatically. As a result, the last changes are not lost and the request is processed as if a valid token had been found.
Recreating Requests
The re-authentication form contains the information from the last request (GET or POST) in hidden fields, i.e. the entire $_GET and $_POST arrays, as well as the information from $_FILES, if files were uploaded with the failed request (the uploaded files themselves are temporarily stored in the site's 'data' directory).
On proper authentication, the GET or POST request is recreated from this information. A new security token is added and the request is sent to the original URL again. So from the target script's point of view, it looks like a regular request with a valid token came through.
In other words: The re-authentication and recreation of the request is entirely transparent. For scripts that already used CSRF protection, no code changes are required.
Well, there's one small exception ...
Uploaded Files
First of all, if you expect files to be uploaded in your code, you need to call the new function SECINT_recreateFilesArray() somewhere after the call to SEC_checkToken() and before you access the $_FILES array for the first time. This function will ensure that a proper $_FILES array is recreated from the information provided in the recreated request.
Files uploaded through the original request (the one with the expired token) are rescued and moved to the site's 'data' directory. This is necessary, as the files would automatically be deleted by PHP otherwise. As a result, the rescued files can no longer be moved with move_uploaded_file() since that function only works on files that were uploaded with the last POST request.
If you are using Geeklog's upload class (upload.class.php), this is handled automatically for you.
If you are using your own upload handling, then check the $_FILES array for an '_gl_data_dir' entry, e.g. $_FILES['file1']['_gl_data_dir']. If such an entry is present and not false, then use rename() instead of move_uploaded_file() to move the uploaded file to its destination. The 'tmp_name' entry will already contain the correct path (for the 'data' directory), so you don't need to (and shouldn't) bother with its actual location.
Known Issues
- Re-authentication does not work for users that authenticate against OpenID (it does, however, work with other remote authentication modules like LDAP and LiveJournal).
- When using a server running as localhost on Mac OS X, the recreated request may fail due to the current IP address being ::1 in the session but 127.0.0.1 in the recreated request.
Solution: Use the machine's Bonjour name (xxx.local) instead of localhost.