[wp-hackers] Rethinking check_admin_referer()

Brian Layman Brian at TheCodeCave.com
Thu Apr 20 16:24:22 GMT 2006

Owen wrote some very important stuff including:
>If we do anything at all, it should be c with b-2.  Option c provides an 
>immediate benefit to user experience by replacing most referer checks 
>with nonces.  
>Does that cover it?

I wonder if we can be a bit more surgical with a fourth option.

Option D. Keep the referrer check there by default, because it does knock
out a lot of attack avenues. Provide a plugin that can disable it.  (Does
anyone mind if I give a whack at writing the plugin?)  Implement a near term
fix to CSRF attacks by adding embedded confirmations to the destructive
actions WP can take.

Possible implementation:

New file: AreYouSure.php
Sample Syntax:
AreYouSure.php?YesAction='/wp-admin/post.php?action=delete?p=123' (something
like that)

1. AreYouSure.php creates a Nonce by hashing the current timestamp truncated
to the current minute with a random number.
2. It then assign the random number to the interactive user. (Cookiewise
perhaps but DB would be more secure)
3. Display an Are you sure? screen that refreshes at 30 seconds to a
standard Time Out screen forcing the user to hit Back and get another 30
seconds to answer and a new nonce.
4. Has the No button send a "back" command and returns the user to the
previous screen. 
5. The Yes button gets the nonce back to the server through link specified
in YesAction with the 30 second nonce tacked on as $nonce (or whatever).
6. Destructive routine in question has a single line pasted into them that
calls VerifyTempNonce($nonce).  VerifyTempNonce first stores the current
time in a variable.  Then it retrieves the random number from the
interactive user, and hashes the current time (to the minute) and if it
matches, the function succeeds.  If it doesn't match, it compares retests
using the previous minute.  If that fails, die(), otherwise allow the
function to succeed.

Possible Actions to protect: Delete Post, Delete Page, Delete Comment,
Delete Category
The links, to these actions, displayed by WP are modified to use
AreYouSure.php. Any direct links to those routines will now die() because
they don't have a nonce.

1. The developers & testers will have a very finite list of areas that have
2. Some real world nonce experience will be gained and we can work at trying
to break it.
3. The developers can have some more design time to think about wp-admin
wide solutions involving: safely bypassing some/all AYS prompts, converting
"action" links from gets to posts, optimizing nonce creation/destruction,
placing hooks in the right location so that a Security Log plug-in could be
written, all the stuff that we are trying to tackle all at once in this
spaghettified thread.
4. The AreYouSure routines could be used even with non protected routines.
The passed nonce would just be ignored.

1. Some areas are not protected.  This would only protects the places we
decide to protect leaving potentially dangerous holes.
2. There could be a hole if cookies are used.  Reading indicates CSRF has
access to cookies.  Assuming someone could create a page that retrieves the
current cookie and then redirects to a known yes link with the Nonce action
embedded.  There would be 1-2 minutes of attack vulnerably after any
protected act was deliberately taken by the admin.  That's a pretty narrow
window to get an admin to click on/display your attack link.

Possible Improvements:
1. The yesaction parameter could easily be obscured by Rot13ing it.
2. AreYouSure.php could create the Nonce by hashing the yesaction variable
with the current timestamp truncated to the current minute and then again
with the random number.  The rest of what I described above would be the
same except that VerifyTempNonce would also have to be passed the current
url with the nonce stripped back out again.  That could narrow the security
hole I mentioned above even further if you can rely on the url passed to
AreYouSure being the same as the url as the destructive routine sees it.
I'm not sure that would always be the case but this might work...

More information about the wp-hackers mailing list