skip to Main Content

I have a WordPress site, where I grant access to users through an O2Auth provider, so they never have to query wp-login.php. But, when users log out, they need to query for wp-login.php?action=logout&_wpnounce=dead0beef

I want to protect wp-login via .htaccess, Require valid-user

So can I add a Require directive to also allow action=logout?

I tried these without success:

SetEnvIf Request_URI "o2a-login" o2a-user
...
Require env o2a_user
Require expr "(%{QUERY_STRING} =~ logout)"
Require expr "%{QUERY_STRING} in { 'action=logout(.*)', 'action=logout', '.*logout.*' }"
Require expr "%{QUERY_STRING} in {'wp-login.php?action=logout.*'}"

Or as an alternative way – Can I respect wp-logged-in users at Apache?

2

Answers


  1. Chosen as BEST ANSWER

    Ok, I don't know if that's a very good solution but it works for me:

    • First I created a symlink in the wp html root (mostly /var/www/html/) ln -s wp-login.php mySecretLogin.php
    • Then I added rewrite rules like @MrWhite suggested, to only allow logout AND mySecretLogin as referrer
    • And prodected mySecretLogin by authentication
    <IfModule mod_rewrite.c>
     RewriteEngine On
     RewriteCond %{HTTP_REFERER} !^https://mysite.tld/mySecretLogin(/|.php)$
     RewriteCond %{QUERY_STRING} !^action=logout(&|$)
     RewriteRule ^wp-login.php$ - [F]
    </IfModule>
    
    

    and

    <FilesMatch "^mySecretLogin.php$">
      AuthType Basic
      AuthName "Password please!"
      AuthUserFile /path/to/.htpasswd
      Require valid-user
    </FilesMatch>
    

    This way the wp-login.php is only allowed for log-out or via mysite.tld/mySecretLogin.php with a password.


  2. they need to query for wp-login.php?action=logout&_wpnounce=dead0beef

    If you simply want to allow the action=logout URL parameter (at the start of the query string) and block all other requests to wp-login.php then you can use the following mod_rewrite directives before the WordPress front-controller, near the top of the .htaccess file:

    RewriteCond %{QUERY_STRING} !^action=logout(?:&|$)
    RewriteRule ^wp-login.php$ - [F]
    

    The above states, for all requests to /wp-login.php that do not have action=logout at the start of the query string then send a 403 Forbidden.

    Can I respect wp-logged-in users at Apache?

    You can’t determine whether a user is actually logged in to WP from .htaccess. You can check that a cookie is set, but you can’t authenticate the value of that cookie (with the WP session) – so anyone could potentially set that cookie.

    I wanted to leave wp-login open for admin login without O2A instead of totally blocking it. But I think I will just add anouther allowed query string to do the job.

    You could potentially check for a "private" (known only to you) query string to perhaps obfuscate the login.


    UPDATE:

    The "obfuscation" string is what I tried. I can access the login form then but the "wp-login" action redirectis back to the URI without this string. So after pressing login I get redirected to the forbidden site and can’t log in

    You could perhaps set a cookie when passing your secret key in the URL and use this cookie to actually authorise the request instead (survives redirects)? For example:

    # Set Cookie if "secret key" successfully passed in the query string
    # Remove secret key from query string (via 302 redirect)
    RewriteCond %{QUERY_STRING} (.*)(?:^|&)(secret-name)=(secret-value)(&.*|$)
    RewriteRule ^wp-login.php$ /$0?%1%4 [CO=%2:%3:example.com:0:/:secure:HttpOnly,R,L]
    
    # Incorporate test if "secret key" cookie is present
    RewriteCond %{QUERY_STRING} !^action=logout(?:&|$)
    RewriteCond %{HTTP_COOKIE} !bsecret-name=secret-valueb
    RewriteRule ^wp-login.php$ - [F]
    

    The %N backreferences in the RewriteRule substitution string and flags arguments refer to the captured subpatterns in the preceding CondPattern.

    The "obfuscation string", ie. secret-name=secret-value pair, is used to set the cookie on a redirect. So the cookie can be immediately read (and authorise access) on the redirected request. The redirect also removes this "obfuscation string" from the visible query string.

    Note that the session cookie is only set on secure HTTPS connections and is not available to JavaScript.

    Alternatively, it would be more secure/easier to authorise by client IP address, but if you have a dynamic IP that may not be practical. For example:

    RewriteCond %{QUERY_STRING} !^action=logout(?:&|$)
    RewriteCond %{REMOTE_ADDR} !=203.0.113.111
    RewriteRule ^wp-login.php$ - [F]
    

    203.0.113.111 is your external IP address. Note that since we’re using the = prefix on the CondPattern this is an exact string match (not a regex), so the dots do not need to be backslash escaped.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search