2

I am looking at ways to restrict direct access to the Wordpress Uploads folder. I've read a handful of Stackoverflow and blog posts about using "wordpress_logged_in" in .htaccess to check if a person is logged in and if they are not to restrict them. See example of a snippet below.

However, I also read a post that was written almost 10 years ago that it would be preferable to do this via PHP as checking for a cookie isn't very secure and could be hackable. However, since then Wordpress has improved how cookies are done and are more secure as I understand it.

Old Stackoverflow thread here.

How to Protect Uploads, if User is not Logged In?

How hackable is checking for a cookie if a person is logged in? Is the idea here that a person could Brute Force the cookie? For me this solution is more straightforward and something I can easily wrap my head around.

Htacess Example here - Check to see if a person is logged in:

<IfModule mod_rewrite.c>
    RewriteCond %{REQUEST_FILENAME} (.*)
    RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_([a-zA-Z0-9_]*) [NC]
    RewriteRule .* - [F,L]
</IfModule>

3 Answers 3

2

Check to see if a person is logged in:

<IfModule mod_rewrite.c>
    RewriteCond %{REQUEST_FILENAME} (.*)
    RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_([a-zA-Z0-9_]*) [NC]
    RewriteRule .* - [F,L]
</IfModule>

The same applies as it did 10 years ago. This code in .htaccess doesn't have anything to do with how WordPress might be setting cookies. And this does not "check to see if a person is logged in". It simply checks that a string that matches the regex wordpress_logged_in_([a-zA-Z0-9_]*) does not appear anywhere in the Cookie header. The "problem" here is that anyone can create a request that passes a value in the Cookie header that passes your test. Since it is well known that WP sets such a cookie then it is not difficult to guess.

The only way to check that the request is "logged in" to WordPress is to use PHP.


Aside: The first RewriteCond directive that checks against REQUEST_FILENAME is superfluous since it simply checks against anything. The NC flag on the second condition should not be used in such checks, since you are now unnecessarily increasing the range of strings that would pass the test (eg. wOrDpReSs_LoGgEd_In_ would pass). Consequently, including A-Z in the hash portion is unnecessarily - the hash is always lowercase (and always 32 chars long AFAIK). The L flag is not required when used with the F flag (it is implied) and the regex .* will block all requests if that cookie does not exist, not just access to the WordPress uploads folder. You should also avoid using the <IfModule mod_rewrite.c> wrapper for anything security related, since a "failure" in your server config (ie. mod_rewrite being erroneously disabled) would allow unrestricted access, instead of breaking with an error (which would be preferable).

So, the above should be written like this:

RewriteCond %{HTTP_COOKIE} !(?:^|;\s)wordpress_logged_in_[a-z0-9_]{32}=
RewriteRule ^wp-content/uploads/ - [F]

The regex (?:^|;\s)wordpress_logged_in_[a-z0-9_]{32}= specifically checks for that cookie name (more specific), rather than a string that occurs anywhere in the Cookie header (too general).

(Although, to clarify, this is really no more "secure" than the original code snippet.)

4
  • Thanks. I marked this as the correct answer as you went above and beyond. Much appreciated. Commented Jun 21, 2021 at 2:32
  • Question for you. Reviewing the post about verifying via PHP. In my case I need to lockdown most of the design assets as well. Like header images. How much overhead do you think this will add to page speed? Commented Jun 21, 2021 at 4:57
  • @Work-Together2013 "How much overhead do you think this will add to page speed?" - The only way is to test it. It depends on your server and how it's implemented. It's certainly a significant overhead compared to simply serving a static resource (often from client-side cache), but it may still be perfectly OK. Consider "caching" the authenticated state in the server-side session to avoid potentially repeated DB checks for multiple resources on the same page. You'll also need to ensure that client-side caching is disabled, which will further impact performance.
    – MrWhite
    Commented Jun 21, 2021 at 22:29
  • Thanks for your comments! Commented Jun 22, 2021 at 17:53
2

Nothing has changed here. The reason it was a bad idea 10 years ago is because it’s a bad idea. Not because of a flaw in WordPress.

With your htaccess example all I would need to do is create a cookie with the name wordpress_logged_in_a and now I have access.

This is not something WordPress could improve. To know whether a user should have access you need to know whether the cookie is for a valid session, and that information is in the database. The existence of the cookie proves nothing on its own.

2

How hackable is checking for a cookie if a person is logged in? Is the idea here that a person could Brute Force the cookie? For me this solution is more straightforward and something I can easily wrap my head around.

I think you can fool it with a simple command line curl request like:

curl --cookie "..." https://example.com/wp-content/uploads/2021/06/test.jpg 

containing a cookie that matches the test in

RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_([a-zA-Z0-9_]*) [NC]

That's why e.g. Moodle opens the uploaded user files via PHP to handle the user permissions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.