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

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.

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).

htaccess restrict access to ALL pages but referrer

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
:

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

.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

site 5x faster via mod_rewrite, but CSS images are broken

I am using .htaccess to accelerate a site with the following redirects:
request for http://example.com/images/name.jpg routed to http://i.example.com/name.jpg
request for http://example.com/css/name.css routed to http://c.example.com/name.css
From listening to the Stack Overflow podcast, I learned that this could make a site faster, since the browser can download more files simultaneously (apparently two streams per domain, although this is unconfirmed).
Indeed, the difference is dramatic; the page loads about five times as fast!
I have not touched the original folders and images -- I am just using mod_rewrite to change the addresses from example.com/images/ to i.example.com/:
rewritecond %{HTTP_HOST} !^i\.example\.com [NC]
rewriterule ^images/([^/]+)$ http://i.example.com/$1 [L]
rewritecond %{HTTP_HOST} !^c\.example\.com [NC]
rewriterule ^css/([^/]+)$ http://c.example.com/$1 [L]
The problem I have is that this technique works perfectly for image tags included in html, but doesn't work for images included via stylesheets:
img src=/images/logo.jpg works perfectly
background:url(/images/logo.jpg); does not work
The server error log contains the following entry:
File does not exist: /var/www/html/css/images, referer: http://example.com/page.html
This seems to imply that the rewrite rule is being applied incorrectly.
The stylesheets work if I use:
background:url(http://i.example.com/logo.jpg);
However, in order to avoid rewriting all the style sheets, I'd like to know: why doesn't url rewriting apply to stylesheets the way it does to html img tags.
[update1] This problem exists in Safari 4 Beta, Firefox 3.0.3, and Chrome, but the page works perfectly in IE6.
[update2] Adding [L,R=301] and [L,R=302] did not help.
[update3] I tried the following based on Gumbo's suggestion below:
Redirect externally if path doesn’t match host name:
rewritecond %{HTTP_HOST} !^i\.domain\.com$
rewriterule ^images/([^/]+)$ http://i.domain.com/$1 [L,R=301]
rewritecond %{HTTP_HOST} !^c\.domain\.com$
rewriterule ^css/([^/]+)$ http://c.domain.com/$1 [L,R=301]
Redirect internally; if there's an unnecessary folder name remove it (see server error above):
rewritecond %{HTTP_HOST} ^i\.domain\.com$
rewriterule ^images/([^/]+)$ $1 [L]
rewritecond %{HTTP_HOST} ^c\.domain\.com$
rewriterule ^css/([^/]+)$ $1 [L]
It still didn't work. Bizarrely, the server error is:
File does not exist: /var/www/html/css/var, referer: http://domain.com/page.html
I was able to resolve this by not trying to incorporate directories into the subdomains:
request for domain.com/images/ routed to i.domain.com/images/
request for domain.com/css/ routed to c.domain.com/css/
It works perfectly and is still extremely fast.
There seems to be a bug in modern browsers where a css request that is redirected will apply only the new domain, leaving the original directories as part of the request:
If a css image at url(domain.com/images/name.jpg) is redirected to i.domain.com/name.jpg, the browser will mistakenly request i.domain.com/images/name.jpg.
I found a way to solve this problem if all host names use the same virtual host:
# redirect externally if path doesn’t match host name
RewriteCond %{HTTP_HOST} !^i\.example\.com$
RewriteRule ^images/([^/]+)$ http://i.example.com/$1 [L,R=301]
RewriteCond %{HTTP_HOST} !^c\.example\.com$
RewriteRule ^css/([^/]+)$ http://c.example.com/$1 [L,R=301]
# redirect internally to the file
RewriteCond %{HTTP_HOST} ^i\.example\.com$
RewriteRule !^images/ images%{REQUEST_URI} [L]
RewriteCond %{HTTP_HOST} ^c\.example\.com$
RewriteRule !^css/ css%{REQUEST_URI} [L]
This will do the following:
http://example.com/css/foo externally to http://c.example.com/foo
http://c.example.com/foo internally to /css/foo
http://example.com/images/bar externally to http://i.example.com/bar
http://i.example.com/bar internally to /images/bar
As well as correcting mismatching paths and host names:
http://i.example.com/css/foo externally to http://c.example.com/foo
http://c.example.com/images/bar externally to http://i.example.com/bar
A mismatch occurs when the requested stylesheet http://example.com/css/foo is redirected to http://c.example.com/foo and an image URI reference like /images/bar inside the stylesheet is resolved from this new base URI and thus leading to http://c.example.com/images/bar instead of the initial http://example.com/images/bar.

Resources