I have successfully forbidden access to any kind of author pages whether trough /author/username/ or the ?author={#id} query string.

I did this with this added to the beginning of my htaccess file:

<IfModule mod_rewrite.c>
    RewriteCond %{REQUEST_URI} ^/author/
    RewriteRule .* - [F]
    RewriteCond %{QUERY_STRING} ^author=([0-9]*)
    RewriteRule .* - [F]
</IfModule>

But the same doesn't work when wordpress is physically in a subdirectory.

The first part works:

RewriteCond %{REQUEST_URI} ^/subdir/author/
RewriteRule .* - [F]

But no matter how I try to edit the second part, the /subdir/?author=1 takes me to the /subdir/usernumber1/ and that is forbidden alright, but this defeats the whole purpose of this.

Any ideas?

Edit:

Yes, I was trying to prevent user names from showing.

In the last moment yesterday I was able to come up with a solution:

<IfModule mod_rewrite.c>
    RewriteCond %{REQUEST_URI} ^/subdir/author/
    RewriteRule .* - [F]
    RewriteCond %{REQUEST_URI} ^/subdir/
    RewriteCond %{QUERY_STRING} ^author=([0-9]*)
    RewriteRule .* - [F]
</IfModule>

I may be able to shorten it based on the answers below(for which I'm very thankful).

And yes this is placed in the subdir.

The first snippet was placed in the root dir, which did not worked(or maybe some of the solutions that I tried along the way actually worked but I had the redirect to the author page already cached, I don't know for sure).

The question is about doing this with .htaccess, but why not disabling author pages from within WordPress instead?

This would achieve the same result while making the subdirectory concern irrelevant altogether (and also works regardless of permalink structure settings)

Sample code that sets all urls to author pages to a 404 error:

add_action( 'template_redirect',
        function() {
                if ( isset( $_GET['author'] ) || is_author() ) {
                        global $wp_query;
                        $wp_query->set_404();
                        status_header( 404 );
                        nocache_headers();
                }
        }, 1 );
add_filter( 'author_link', function() { return '#'; }, 99 );
add_filter( 'the_author_posts_link', '__return_empty_string', 99 );

(code taken from this plugin: Disable Author Archives)

  • 1
    no wander no one uses the plugin ;) (just joking) as this code is very sub optimal, for example it will send the user for the top of the page when clicking the authors link, and in any case the redirect probably happens in the canonical redirect and therefor the whole thing is pointless if it is intended to not expose user names which is probably what the OP is after. – Mark Kaplun Aug 9 at 18:18
  • for the record this is my solution to the overall problem - wordpress.org/plugins/prevent-user-name-and-email-leakage If you will inspect the code you will see that there are more leakage issues than the one everybody is concerned about, although IIRC my research when I wrote the code there is no good way to remove it from the html by a plugin and the best way is to edit the theme. – Mark Kaplun Aug 9 at 18:28
  • Yes, I've tried using wordpress functions before and it resulted in a redirect and exposed user names, that's why I wanted to do it in the .htaccess file since I can edit it. It's a totally custom theme that is used on this site, and it does not display usernames or emails anywhere. – D. Dan Aug 10 at 7:32

This is probably best handled the "WordPress way" as @Iceable suggests, rather than using .htaccess, however, to answer your specific queries...

But no matter how I try to edit the second part...

You don't need to edit the "second part". The "second part" simply checks the query string, not the URL-path, which does not change when WordPress is installed in a subdirectory.

Also, assuming the .htaccess file is located inside the subdirectory that WordPress is installed in then your directives can be simplified. There is no need to reference the subdirectory:

RewriteRule ^author/ - [F]
RewriteCond %{QUERY_STRING} ^author=([0-9]*)
RewriteRule .* - [F]

These directives will work regardless of where WP is installed, providing the .htaccess file is located in the root of the WP install.

It is more efficient to check the URL-path using the RewriteRule pattern (when possible), rather than checking against the REQUEST_URI server variable. Also, the RewriteRule pattern matches against the URL-path less the directory-prefix (so this naturally works for any subdirectory without additional work). Whereas the REQUEST_URI server variable contains the entire URL-path, so any subdirectory must be explicitly accounted for.

Also, there is no need for the <IfModule mod_rewrite.c> container, unless these directives are intended to be optional.

I assume you are trying to prevent scanners obtaining your site's user names. And for security I believe in blocking at the first perimeter gate possible i.e. .htaccess not PHP.

No idea why subdirs cause an issue; you could try adding your condition to htaccess files in both root and your WP subdir it certainly won't do any harm. I use a rewrite condition pretty similar to yours and it works for me on sites with WP in subdir or not:

RewriteCond %{QUERY_STRING} author=
# redirect away from site
RewriteRule (.*) https://www.fbi.gov/investigate/cyber/%1 [R=302,L]

I also use a modified version of Jeff Starr's 6G "firewall" to additionally check for the WPScan User Agent. This scanner is popular with hackers and also used by some online "enter a URL" security scanners to identify admin users, use of vulnerable plugins etc etc. Obviously users can change the UA but legitimate online scanners and script kiddies don't seem to bother:

<IfModule mod_setenvif.c>
  # numerous 6G UA Checks (OMITTED)
  #check for WPScan
  SetEnvIfNoCase User-Agent "WPScan" bad_bot
  # Apache >= 2.3
  <IfModule mod_authz_core.c>
    <RequireAll>
    Require all Granted
    Require not env bad_bot
    </RequireAll>
  </IfModule>
</IfModule>

re M Kaplun's comment on OP:

I wasn't aware of Mark's plugin; and despite my comments on PHP it is obviously a great out of the box one stop solution. I take a different approach (which "solves" the problem of username leakage by themes also mentioned by Mark).

Change display name (via WP Dashboard) and author slug (edit "user_nicename" in users table; or use Edit Author Slug plugin) to be completely different to username.

So:

  1. requests with author querystring (hackers) are redirected (2 lines of htaccess above).

  2. author links added to posts by themes still friendly & work. They take you to relevant "author's page" - but the author slug no longer identifies username. e.g. on my site the (valid) author link (display name "AW") takes you to https://wptest.means.us.com/author/not-for-scanners/ for a list of my posts.

This is not practical for sites with lots of authors. Maybe ( @Mark Kaplun @mark-kaplun )'s plugin could be extended to automate slug changes (hashing all user_nicename in the DB?)?

Are publicly viewable usernames a risk?

Wordpress.org consensus is that user name "leakage" is not a security risk . Yet it provides the potential for some users to be hacked on first attempt (no brute force needed).

You do not need to be a genius to realise that the friendly url slug /author/hclintongmailcom means their is an author with email and (case insensitive) user name of hclinton@gmail.com.

There are hacker password lists for 1 Billion plus (? from recollection) email addresses (try yours against a small subset https://haveibeenpwned.com/); and many users use the same never changing password across sites. So an author with an email username and a password compromised on another site might be "hacked" at first attempt on your site.

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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