[wp-hackers] Rethinking check_admin_referer()
ringmaster at midnightcircus.com
Thu Apr 20 13:52:16 GMT 2006
> 1) The problems present in the current system.
There are many layers to this problem, which I think is what might make
it so confusing.
Here is the current system:
A malefactor creates a link somewhere whose URL would normally be used
by your blog's WordPress to trigger the deletion of a post with a
specific ID (or delete some other indexed item). The expectation is
that you will have already logged in to your blog, so when you visit
that page, you will not have the benefit of the login page as a barrier
to the immediate deletion of that post.
The current system requires that a referer be sent to visit any admin
page (although there are some that are not covered, either by choice or
omission), and that referer must contain a URL from inside your WP admin
This prevents the scenario fairly well, since you must now already be on
an admin page to activate a link that deletes anything. However, there
are some issues with this behavior:
i) User Experience - Some browsers, some proxies, and some firewall
software explicitly block or remove the referer information from the
request. As a result, admin pages do not work properly and provide a
poor error message. This issue has resulted in numerous support
requests, for example:
The last thread demonstrates that this issue has been ongoing for almost
a year. There is also a Codex page dedicated to working around this
problem, possibly implying that it is a common enough complaint to
ii) Security - The system is not impenetrable. If an unfiltered URL to
an admin page that deletes things appears /within/ the admin (such as a
link in a comment from the comment moderation page), and the admin
inadvertently clicks on it, it will trigger the deletion.
> 2) A list of the options.
a) Leave things as is - This option suggests that the small amount of
users affected by this issue are not worth the trouble of any fix.
b) Replace the referer check with nonces - Instead of verifying the
referer at all, forms and links would be modified to include a special
code (a nonce) that would be checked before an action is performed.
Without the presence of this code, the action could either fail with an
error (similar to the current referer check error) or ask "Are You
Sure?" to confirm the action, submitting the original data on to the
action page with an added valid nonce.
Nonces could be generated in these ways:
b-1) One method would simply generate a random value and store it in the
database. When verifying a nonce, WP would compare the submitted nonce
to the one in the database.
b-2) One method would algorithmically generate a nonce based on user,
action, time, and possibly other variables. This nonce would not be
stored on the server, but could be verified algorithmically.
c) Augment the referer check with nonces - Similar to option b, nonces
would be added to forms and links when possible. To verify a page
request, first the nonce would be checked. If it fails, then the
referer would be checked as currently done. If the referer check fails,
then an "Are You Sure?" confirmation would appear. If any of the checks
pass, then no confirmation is displayed and the action continues as normal.
This option could also be pluggable, where a user can control which
method to use by activating plugins. A plugin could also deactivate any
d) Convert every admin action that works via a GET request to a POST
request. GET requests would be made to work only after confirmations.
POST requests would use the existing admin referer check.
> 3) Their relative pros/cons.
a) No new code must be written or supported.
Support requests will likely continue, and the documentation on enabling
referer checks should likely need to be reviewed and enhanced. Those
browsers, proxies, and firewalls that disable access to WordPress' admin
will likely continue to do so. This entire topic of discussion will
likely have been a gigantic waste of time and energy, and we will
probably end up arguing about this again at a later time. ;)
b) We will pick up support for users who currently have trouble with the
referer issue. Support for referers should be reduced, since nothing
needs to be done to "activate" nonces.
Replacing the existing system will require new code, which must be
tested. Most of the code can be centralized (generating and checking
the nonces) but each admin page will most likely be touched. There are
some questions about plugin admin pages that still need to be addressed,
such as how legacy plugins will handle incoming requests since they will
not already have the nonce generating code.
b-1) Provides a higher level of security.
Requires database storage for nonces, increasing database thrash while
operating the admin. May need to store more than one nonce per user
(ie.- +per action, +per IP). Depending on how well the data storage
system works, this option might cause issues with using multiple browser
instances of the admin panel or the back button. This could happen
when, for example, a user clicks the back button to a form that contains
an old, previously used nonce, then submits that form.
b-2) Does not provide absolute security, since nonces generated
algorithmically within a time period are likely to be similar or identical.
Does not require database storage. Nonces could be generated that are
specific to user, action, and time that do not fail after using the back
button or using the admin from two open browsers.
c) Covers all options of b and provides some backwards compatibility for
admin pages (via core or plugin) that do not yet have the nonces
embedded in their links and forms.
Has all of the cons of b.
d) Puts an end to the discussion of whether actions should be performed
on a GET request. Makes it easier to add nonces to the forms, since all
actions will be forms using POST requests.
Requires that a volume of links must be changed into forms, and that CSS
be applied to prevent the admin from turning into an ugly spectacle. By
itself it doesn't really address the presented issues, but might better
enable the application of b or c.
> 4) Your opinion.
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. In the case that checks fail, users will no longer see an
uninformative and prohibitive die() message, but a confirmation that
allows them to continue.
Allowing the system to be pluggable allows people who are more concerned
with security than what b-2 provides to use a plugin to augment that
security. I am of the opinion that the case is very rare that I (or
anyone) would even have the opportunity to click on a malicious comment
link in my admin panel, much less actually do it. I don't believe that
we should waste our efforts writing code for a problem that I'm not even
aware of being in the wild, but allowing for someone else to plug the
hole seems wise.
On the other hand, even I have been affected by the referer issue, and
eliminating this support issue would leave us open to deal with more
The very, very least we could do is already done - making
check_admin_referers() pluggable. You can write a plugin today that
replaces that function with something that returns true no matter what.
It's not secure, but it'll enable the UI for people using those
browsers, proxies, and firewalls. This could be improved by making that
plugin hook in that function able to circumvent the actual check. Any
other changes are going to be more invasive of the admin panel.
Does that cover it?
More information about the wp-hackers