Difference between revisions of "Re-Authentication for expired Tokens"
(added a screenshot of the re-authentication form) |
m (added a link to the Troubleshooting Authentication Problems page) |
||
(3 intermediate revisions by the same user not shown) | |||
Line 3: | Line 3: | ||
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. | 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 ( | + | Re-authentication (as of Geeklog 1.7.0) attempts to address this problem. |
[[Image:Reauthentication.png|center|Request for re-authentication]] | [[Image:Reauthentication.png|center|Request for re-authentication]] | ||
Line 19: | Line 19: | ||
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. | 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 | + | In other words: '''The re-authentication and recreation of the request is entirely transparent. For scripts that already use CSRF protection, no code changes are required.''' |
− | |||
− | |||
=== Uploaded Files === | === Uploaded Files === | ||
Line 30: | Line 28: | ||
If you are using your own upload handling, then check the <tt>$_FILES</tt> array for an <tt>'_gl_data_dir'</tt> entry, e.g. <tt>$_FILES['file1']['_gl_data_dir']</tt>. If such an entry is present and not <tt>false</tt>, then use <tt>rename()</tt> instead of <tt>move_uploaded_file()</tt> to move the uploaded file to its destination. The <tt>'tmp_name'</tt> 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. | If you are using your own upload handling, then check the <tt>$_FILES</tt> array for an <tt>'_gl_data_dir'</tt> entry, e.g. <tt>$_FILES['file1']['_gl_data_dir']</tt>. If such an entry is present and not <tt>false</tt>, then use <tt>rename()</tt> instead of <tt>move_uploaded_file()</tt> to move the uploaded file to its destination. The <tt>'tmp_name'</tt> 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. | ||
+ | |||
+ | |||
+ | == Using SEC_checkToken == | ||
+ | |||
+ | It is important that you only call <tt>SEC_checkToken()</tt> when you expect a token. In other words, do '''NOT''' do this: | ||
+ | |||
+ | <pre>$token_valid = SEC_checkToken(); // don't do this! | ||
+ | |||
+ | switch ($_POST['mode']) { | ||
+ | case 'delete': | ||
+ | if ($token_valid) ... | ||
+ | break; | ||
+ | |||
+ | case 'save': | ||
+ | if ($token_valid) ... | ||
+ | break; | ||
+ | |||
+ | case 'edit': | ||
+ | // token not checked here | ||
+ | display_editor(); | ||
+ | break; | ||
+ | }</pre> | ||
+ | |||
+ | In the above example, a token check is required for the 'delete' and 'save' cases, but not for 'edit'. However, <tt>SEC_checkToken()</tt> is also being called in the 'edit' case. In Geeklog versions 1.5.0 - 1.6.1, this would only cause <tt>SEC_checkToken()</tt> to return <tt>false</tt> for this case - but since the return value isn't checked, this would do no harm. From now on, however, this case would trigger the re-authentication form to be displayed! | ||
+ | |||
+ | So the proper use of <tt>SEC_checkToken()</tt> would be: | ||
+ | |||
+ | <pre>switch ($_POST['mode']) { | ||
+ | case 'delete': | ||
+ | if (SEC_checkToken()) ... | ||
+ | break; | ||
+ | |||
+ | case 'save': | ||
+ | if (SEC_checkToken()) ... | ||
+ | break; | ||
+ | |||
+ | case 'edit': | ||
+ | // token not checked here | ||
+ | display_editor(); | ||
+ | break; | ||
+ | }</pre> | ||
Line 36: | Line 75: | ||
* Re-authentication does not work for users that authenticate against OpenID (it does, however, work with other remote authentication modules like LDAP and LiveJournal). | * 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.<br>'''Solution:''' Use the machine's Bonjour name (''xxx''.local) instead of localhost. | * 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.<br>'''Solution:''' Use the machine's Bonjour name (''xxx''.local) instead of localhost. | ||
+ | |||
+ | Also see: [[Troubleshooting Authentication Problems]] | ||
[[Category:Development]] | [[Category:Development]] |
Latest revision as of 17:08, 27 November 2010
Contents
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 (as of Geeklog 1.7.0) 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 use CSRF protection, no code changes are required.
Uploaded Files
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.
Using SEC_checkToken
It is important that you only call SEC_checkToken() when you expect a token. In other words, do NOT do this:
$token_valid = SEC_checkToken(); // don't do this! switch ($_POST['mode']) { case 'delete': if ($token_valid) ... break; case 'save': if ($token_valid) ... break; case 'edit': // token not checked here display_editor(); break; }
In the above example, a token check is required for the 'delete' and 'save' cases, but not for 'edit'. However, SEC_checkToken() is also being called in the 'edit' case. In Geeklog versions 1.5.0 - 1.6.1, this would only cause SEC_checkToken() to return false for this case - but since the return value isn't checked, this would do no harm. From now on, however, this case would trigger the re-authentication form to be displayed!
So the proper use of SEC_checkToken() would be:
switch ($_POST['mode']) { case 'delete': if (SEC_checkToken()) ... break; case 'save': if (SEC_checkToken()) ... break; case 'edit': // token not checked here display_editor(); break; }
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.
Also see: Troubleshooting Authentication Problems