Reputation: 154
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?
Upvotes: 1
Views: 386
Reputation: 154
Ok, I don't know if that's a very good solution but it works for me:
ln -s wp-login.php mySecretLogin.php
mySecretLogin
as referrermySecretLogin
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.
Upvotes: 1
Reputation: 45914
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-value\b
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.
Upvotes: 1