htaccess restrict access to ALL pages but referrer - wordpress

I managed to restrict access to my site using the .htaccess directives below. It works pretty well BUT I found that people other than referrer success to access direct page like https://example.com/**pages**/ and from there can go back to home. How can I restrict to all site but the referrer (so all tree from my root URL).
# Serve everyone from specific-domain (and internal requests)
RewriteCond %{HTTP_REFERER} ^https?://www\.your-domain\.com/ [OR]
RewriteCond %{HTTP_REFERER} ^https?://www\.specific-domain\.com/
RewriteRule ^ - [L]
# everybody else receives a forbidden
RewriteRule ^ - [F]

From discussion on your other question, it seems you have been putting these directives in the wrong place. It is a WordPress site and the directives have been placed after the WordPress front-controller, ie. after the # BEGIN WordPress ... # END WordPress code block.
This is actually a very common mistake. But order matters.
By placing them at the end of the file they are simply never going to be processed for requests to example.com/<wordpress-url>, because the request has already been routed to the WordPress front-controller (index.php).
These blocking directives need to go at the very top of the .htaccess file. Importantly they must go before the # BEGIN WordPress section.
You should NOT place these directives inside the WordPress code block since WordPress maintains this section and will likely overwrite any custom directives you place here.
You do not need to repeat the RewriteEngine On directive (which appears later in the file - the order of this directive does not matter). In fact, if there are multiple RewriteEngine directives then the last directive wins and controls the entire file/context.
UPDATE#1:
is there a way to exclude a single page from the directives so that this page can still be available even from non referrer - it would be a login page
Yes, you can add an additional condition to the first block that checks for this URL. For example:
# Serve everyone from specific-domain (and internal requests)
RewriteCond %{REQUEST_URI] ^/login$ [OR]
RewriteCond %{HTTP_REFERER} ^https?://www\.your-domain\.com/ [OR]
RewriteCond %{HTTP_REFERER} ^https?://www\.specific-domain\.com/
RewriteRule ^ - [L]
# Everybody else receives a forbidden
RewriteRule ^ - [F]
UPDATE#2:
However, since this is a WordPress site, you still need processing to continue to the front-controller (the # BEGIN WordPress section later in the file) in order to route the URLs. This would explain why you are seeing 404s for /<page> and other WordPress URLs despite the Referer presumably being set correctly.
To resolve this, change the [L] flag in the first RewriteRule to [S=1] (skip 1 rule), so instead of stopping further processing (the effect of the L / last flag), it simply skips the following rule that blocks access for everyone else. And continues on to the WordPress front-controller.
For example:
:
RewriteRule ^ - [S=1]
# Everybody else receives a forbidden
RewriteRule ^ - [F]
Alternatively, you could reverse the logic...
# Block everyone from "other" domains except for specific URLs
RewriteCond %{REQUEST_URI] !^/login$
RewriteCond %{HTTP_REFERER} !^https?://www\.your-domain\.com/
RewriteCond %{HTTP_REFERER} !^https?://www\.specific-domain\.com/
RewriteRule ^ - [F]
# BEGIN WordPress
:

Related

Wordpress/Apache rewrite/redirect rule and regex

I need to do some apache rewrite/redirect rules to external webservice in case of 404 error for specific file extensions: .jpg, .png, etc. Wordpress is used here.
So, if 404 occurs at:
https://test.com/folder/subfolder/year/month/filename.jpg
I want to redirect it to:
https://test1.com/folder/subfolder/year/month/filename.jpg (external webservice, not the same phisical server)
I've tried such a configuration in htaccess, didn't work as expected:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*) test1.com/folder/subfolder//$year$\/$month$\/([^\s]+(\.(?i)(png | jpg | gif | svg))$)/
Do you have any ideas how to do it right way?
Any suggestions appreciated.
With your shown samples, attempts; please try following htaccess rules file. These rules are written as per shown domain names which are samples/tests, so you need to change values as per your actual values when you use them in your system. We also need to make sure that both (test.com and test1.com) are sharing same directory structure in your actual apache server.
Also make sure to clear your browser cache before testing your URLs.
RewriteEngine ON
RewriteCond %{HTTP_HOST} ^(?:www\.)?test\.com$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/?$ https://test1.com/$1 [R=301,L]
To "redirect" URLs of the form /folder/subfolder/<year>/<month>/<file>.<png|jpg|gif|svg> where /folder/subfolder/ is static and the other elements are variable and which do not exist on the filesystem you would need to do something like the following before the WordPress code block. ie. before the # BEGIN WordPress section.
# Redirect certain non-existent image files to another server
RewriteRule ^folder/subfolder/\d{4}/\d\d/[\w-]\.(png|jpg|gif|svg)$ https://test1.com/$0 [R=302,L]
# BEGIN WordPress
:
The <year> is a 4-digit number and <month> is a 2-digit number. The filename can consist of the characters 0-9, a-z, A-Z, _ (underscore) and - (hyphen).
This should presumably be a 302 (temporary) redirect, not a 301 (permanent), otherwise if the resource should become available at the source domain then it won't be accessible to those users who have visited the URL before (they will be redirected from cache).
To avoid the external redirect it may be preferable to "proxy" the request to the other domain. (This is invisible to the end user.) Although this potentially involves additional configuration server-side, as you would need to configure the source server as a "reverse proxy". You can then replace the R=302 flag in the above rule with P (proxy).

url masking via htaccess rewrite is not working

Not sure if this is the right section of Stackoverflow to ask my question...
But here it is:
So I am using the below on the .htaccess file:
RewriteEngine On
RewriteRule ^sale?$ /discount-page/
So that when people visit example.com/sale page, they see content from example.com/discount-page/
But when I visit example.com/sale it shows 404 error saying that the URL /discount-page is not available on this server...
Why is it happening?
Here's how my entire .htaccess file looks like:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Can anyone help please?
When using WordPress, you can't simply rewrite the URL in .htaccess to the %postname% (the real URL) since WP still looks at the REQUEST_URI in order to route the URL. Even though you are rewriting /sale to /discount-page/ (the actual URL), WordPress sees /sale (the requested URL) - which doesn't exist inside WP; hence the 404.
Although not your intention, you could change this to an external redirect to get around this problem (which also avoids a potential duplicate content issue). For example:
RewriteRule ^sale$ /discount-page/ [R,L]
(I removed the ? in ^sale?$, as that does look erroneous. Or do you really want to match /sale or /sal?)
Alternatively, you could try rewriting to the underlying "plain" permalink. ie. explicitly pass the %post_id%. This is different to rewriting to the %postname%, since WP shouldn't need to check the REQUEST_URI in order to route the URL. For example:
RewriteRule ^sale$ /index.php?p=123 [L]
Where 123 is the %post_id% of your discount-page. By rewriting directly to index.php, you are effectively bypassing WP's front-controller.
Note that this must go before the standard WordPress directives in .htaccess (aka the front-controller).
However, I still feel there should be a more WordPress-like way of doing this, which is why I initially suggested asking this question over on the WordPress Stack. However, if you do that, don't mention ".htaccess". What you are really creating is a URL alias or something like that. For example: Have two different URLs show the homepage

FOSRestBundle double leading slash in route

I'm trying to handle a wrongly coded leading slash route in an Android application. It is trying to reach our system using:
//api/1.0/store/products/video/USD.json
but should normaly be
/api/1.0/store/products/video/USD.json
so this is causing a route not found exception in our app.
I cannot change the android application! I must find a way to make the wrong route work!
What i've tried:
Splitting the controller in two, one with the standard "/api" prefix and one with a prefix of "//api", didn't work, i think FOSRestBundle is fixing that for me live, so all my routes are still only 1 leading slash
Using a rewrite rule in .htaccess (See below) to rewrite the rule before i get problems, this would be the best strategy as it would keep my app and integration tests clean
Attempt using HTACCESS
RewriteRule /api/(.*) api/$1 [L]
This rule is supposed to work if i test it on "http://martinmelin.se/rewrite-rule-tester/" but in my htaccess it doesn't. Here's the content of my .htaccess.
Can anyone help me figure out a solution?
# Use the front controller as index file. It serves as a fallback solution when
# every other rewrite/redirect fails (e.g. in an aliased environment without
# mod_rewrite). Additionally, this reduces the matching process for the
# start page (path "/") because otherwise Apache will apply the rewriting rules
# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
DirectoryIndex index.php
<IfModule mod_rewrite.c>
RewriteEngine On
# Rewrite double leading slash routes to single leading slash routes
RewriteRule /api/(.*) api/$1 [L]
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the app.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
# Sets the HTTP_AUTHORIZATION header removed by apache
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect to URI without front controller to prevent duplicate content
# (with and without `/app.php`). Only do this redirect on the initial
# rewrite by Apache and not on subsequent cycles. Otherwise we would get an
# endless redirect loop (request -> rewrite to front controller ->
# redirect -> request -> ...).
# So in case you get a "too many redirects" error or you always get redirected
# to the start page because your Apache does not expose the REDIRECT_STATUS
# environment variable, you have 2 choices:
# - disable this feature by commenting the following 2 lines or
# - use Apache >= 2.3.9 and replace all L flags by END flags and remove the
# following RewriteCond (best solution)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^index\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]
# If the requested filename exists, simply serve it.
# We only want to let Apache serve files and not directories.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .? - [L]
# Rewrite all other queries to the front controller.
RewriteRule .? %{ENV:BASE}/index.php [L]
</IfModule>
<IfModule !mod_rewrite.c>
<IfModule mod_alias.c>
# When mod_rewrite is not available, we instruct a temporary redirect of
# the start page to the front controller explicitly so that the website
# and the generated links can still be used.
RedirectMatch 302 ^/$ /index.php/
# RedirectTemp cannot be used instead
</IfModule>
</IfModule>
Okay, I tried, and failed to match the requested uri, so I will suggest you different approach, if you find it suitable. How about if we just replace all double leading slashes with single ones?
What I mean is something like that:
RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]
The following tests on my project were successful:
/admin//orders => /admin/orders
//admin//orders//5 => /admin/orders/5
And lastly, I pasted yours as well:
//api/1.0/store/products/video/USD.json
gave this:
No route found for "GET /api/1.0/store/products/video/USD.json"
which is I believe what we are looking for. Hope you can use this solution as a temporary one until someone else provides a better one.

Using .htaccess to prevent a DDOS attack not working with Permalinks

We have become the victim of a vicious DDOS attack on a WordPress site.
Thankfully, they should be easily removed as they are GET requests with the string ?ptrxcz appended to the end of the URL.
With this in mind we have set up rules to give 403 permission error pages to requests that fulfill this using .htacess. The trouble is these don't appear to work with permalinks installed also.
Here is my full .htaccess file as it is.
RewriteEngine On
RewriteCond %{QUERY_STRING} .*ptrxcz.*
RewriteRule (.*) - [F]
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
The beginning part is redirecting users with ptrxcz to the 403 page. This works perfectly if I remove the WordPress rules underneath it, but with them included it just never works.
Frustratingly using a negative regex with the QUERY_STRING search works in reverse correctly (blocking everything except request with the query string, as so:
RewriteCond %{QUERY_STRING} !.*ptrxcz.*
(Note the added !)
Does anyone have any idea:
Why it doesnt work with permalinks
How I can make it work with permalinks
Why a negative regex on the query string works but not a positive one.
I had the same problem, but it was severe enough that I brought up a small web server to act as a front end and filter out these requests. The relevant iptables rule is:
iptables -A INPUT -p tcp --dport 80 -m string --to 70 --algo bm --string 'ptrxcz_' -j DROP
It instructs the system to examine up to the first 70 characters of the request and if it finds 'ptrxcz_ ', to silently drop the request. I tried returning an error message, but the bandwidth consumed by the error code was not worth it considering there would never be a user on the other end of the connection to read the error.
I created a blog post describing the steps I took:
http://web.htcomp.net/?pageid=85&blogid=2
Larry
If you replace QUERY_STRING in the code above with THE_REQUEST then this works fine and does exactly as required within WordPress.

.htaccess: Rewrite to folder except if cookie exists or before a date bypassing WordPress rewrite

I find myself migrating a static site to a WordPress-based website fairly frequently these days. Once I've finished development of the WordPress website on a test server, I then want to install it on the current website domain, but without affecting the old static site- until the site goes live.
My idea is to move the current non-WordPress website to a folder /old/ and get all requests to rewrite to this folder (and so for SEO purposes keeping all the urls the same).
To allow myself and other authorized people through I want to check for a cookie (that will be set via a simple "login" php file since I can't rely on static IP addresses) or if the current date and time is after the live date then let the WordPress rewrite rules take their course to give access to the WordPress website.
This will also allow me to add a simple countdown timer on the current or old site after which the new site will go live automatically at live date.
My simple login.php script is like this:
<?php
setcookie("login", "loggedin", time()+3600,"/");
?>
<h3>Welcome, you are logged in</h3>
<p>Click here to visit the home page</p>
I thought the following might be the best way to acheive this, but it doesn't work (I get a Internal Server Error). The first section checks to see if the login cookie exists and if it doesn't and the current date and time is before 8pm on July 20 2012 it will rewrite all requests to the /old/ folder. I've modified the WordPress rewrite section to exclude the /old/ folder.
RewriteCond %{HTTP_COOKIE} !^.*login.*$ [NC]
RewriteCond %{TIME} < 20120720200000
RewriteCond %{REQUEST_URI} !^/old/
RewriteRule (.*) http://domain.com/old/$1 [L]
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_URI} !^/(old/.*)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Can someone help me with what I want to achieve?
The RewriteCond directive takes 2 arguments, but you are giving it 3 when comparing %{TIME} and that's causing apache to return a 500 server error.. If you look at the lexicographical comparisons in RewriteCond, there can't be a space after the comparitor (mod_rewrite is kind of dumb like that). So that line needs to look like this:
# no space here -----V
RewriteCond %{TIME} <20120720200000
That should deal with the 500 server error.
The other thing about your rules is that the rule's target, http://domain.com/old/$1, will cause apache to 302 redirect because you are including the http://domain.com in the target. If you want it to rewrite internally (so the URL in the browser's address bar doesn't change), you need to remove that bit.
A simpler way would be to install plugin called Maintenance mode
Then create a 503.php for the theme.
add this to the beginning of the file:
<?php if (!is_user_logged_in())
{
header("Location: http://example.com/old");
}
else
{
//WHATEVER YOU LIKE
}?>
That way, logged in users can browse the WP-site, and others will get redirected to the /old website.
users must login beforehand # http://example.com/wp-login.php

Resources