My website is getting bombarded with requests that are referred from an IP address.
[Sat Dec 14 22:03:14 2013] [error] [client XXX.XX.XX.XX] client denied
by server configuration: /home/user/public_html/folder/folder/,
referer: http://XXX.XXX.XXX.XXX/
You see the referrer isn't a domain name like a legit refer would be, instead it's from an IP and it bombards my website thousands of times. I have blocked the IP address and similar ones like this:
RewriteCond %{HTTP_REFERER} XXX\.XXX\.XXX [NC]
RewriteRule .* - [F]
But how can I block all referrers coming from an IP address? As far as my website is concerned the vast majority if not every single user will visit my site from a domain refer not IP address. Only a visitor with malicious intent will come vis IP refer as I am experiencing now.
RewriteCond %{HTTP_REFERER} *\.*\.* [NC]
RewriteRule .* - [F]
I tried this thinking it would work but it doesn't. I thought maybe this would be a wild card for each set of digits. But it gave a large amount of errors in the logs...
If you want to match any string that is formed like an ip address it will look something like
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1-3}\.[0-9]{1,3}
the regex for "1 to 3 digits, four times, separated by period". Obviously you could test for just three groups of digits, but that's the general idea. A shorthand for [0-9] is \d "any digit" - and since the first three groups are the same (up to three digits followed by period) you can make the expression more compact by grouping them.
That means you might want to try this
RewriteCond %{HTTP_REFERER} (\d{1,3}\.){3}\d{1,3} [NC]
RewriteRule .* - [F]
Related
I have a lot of old urls inbound pointing to incorrect locations, trying to forward to new location. These are going to the root directory so I can't just forward everything.
One way to get a good chunk of them on to the new place is finding ones with a session ID in the query string. It always has 32 characters, preceded by s=
https://www.example.com/some-url-name-1233/?s=ba4a8a734b666b8d43499e5d497599a6
Need to move that to (and drop the session ID)
https://www.example.com/newfolder/some-url-name-1233/
I can't get the .htaccess redirect to match that string.
I've tried multiple ways, most recent being:
RewriteRule ^(.*)s=([^.]{32})$ https://www.example.com/newfolder/$1 [L,R=301]
Any suggestions?
This is an often answere, fully documented issue: you cannot access a request's query string by means of a RewriteRule. You need to use a RewriteCond for that:
RewriteEngine on
RewriteCond %{QUERY_STRING} ^s=[^&]{32}(&|$)
RewriteRule ^ https://www.example.com/newfolder%{REQUEST_URI} [L,R=301,QSD]
I also fixed some other details.
The user agent blocking code in my .htaccess file stopped working, though I didn't make any recent changes to it. To troubleshoot this I changed the user agent in FF and created a sub-directory with its own .htaccess file and one php file. In that file I added code to display the $_SERVER['USER_AGENT'] string. It shows the UA I am using and is:
Mozilla/5.0 (compatible; Konqueror/4.2; Linux) KHTML/4.2.96 (like Gecko)
In my .htaccess file I have the following but when I visit that location I am not blocked.
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} "^Konqueror$" [NC]
RewriteRule ^ - [F]
I added the following, with my real IP, after the above to verify the rewrite was working and it blocked me:
RewriteCond %{REMOTE_ADDR} ^12\.23\.45\.666
RewriteRule ^ - [F]
Does anyone know what the problem is?
This won't work due to the "^" at the start and the "$" at the end of your matching pattern in the RewriteCond. These two special characters anchor a regular expression to the beginning and the end of the subject, so the search string. So your condition will only match of the header contains the exact string "Konqueror" with nothing before or after that. That is not what you want.
The word "Konqueror" appears in the middle of that string you send as a user agent. So you want to match any string that contains the word "Konqueror" most likely. Just leave both special characters away and you are happy.
You can also remove the quote characters, they are not required.
So simply use that condition:
RewriteCond %{HTTP_USER_AGENT} Konqueror [NC]
I am trying to do the following:
User visits URL with query parameter: http://www.example.com/?invite=1234
I then want them to be deep linked into the app on their iOS device, so they go to: app_name://1234
Any suggestions on how to accomplish this in my .htaccess file?
I tried this but it doesn't work:
RewriteEngine On # Turn on the rewriting engine
RewriteRule ^invite/(.*)/$ app_name://$1 [NC,L]
If RewriteRule won't work, can anyone send me an example code for RewriteCond or JavaScript to achieve what I need?
Not sure how this will work with the iOS device, but anyway...
RewriteRule ^invite/(.*)/$ app_name://$1 [NC,L]
This doesn't match the given URL. This would match a requested URL of the form example.com/invite/1234/. However, you are also matching anything - your example URL contains digits only.
The RewriteRule pattern matches against the URL-path only, you need to use a RewriteCond directive in order to match the query string. So, to match example.com/?invite=1234 (which has an empty URL-path), you would need to do something like the following instead:
RewriteCond %{QUERY_STRING} ^invite=([^&]+)
RewriteRule ^$ app_name://%1 [R,L]
The %1 backreference refers back to the last matched CondPattern.
I've also restricted the invite parameter value to at least 1 character - or do you really want to allow empty parameter values through? If the value can be only digits then you should limit the pattern to only digits. eg. ^invite=(\d+).
I've include the R flag - since this would have to be an external redirect - if it's going to work at all.
However, this may not work at all unless Apache is aware of the app_name protocol. If its not then it will simply be seen as a relative URL and result in a malformed redirect.
I've been browsing the symfony2 framework source. In the htaccess file for their example website, I found the %{REQUEST_URI}::$1 written as follows:
RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
The comment above that rule explains
The following rewrites all other queries to the front controller. The condition ensures that if you are using Apache aliases to do mass virtual hosting, the base path will be prepended to allow proper resolution of the app.php file; it will work in non-aliased environments as well, providing a safe, one-size fits all solution.
However, that doesn't explain the ::$1 or ::\2.
Are they backreferences? If not, what are they? What is their purpose?
I have encountered almost the same htaccess file in my Zend project, and here are my thoughts and hope it helps.
The htaccess file (located at the Zend project directory, same as index.php) says
RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$
RewriteRule ^(.*)$ - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]
Suppose Zend is installed at http://mydomain.tld/zend (let's call it yourdomain later on)
and we are requesting yourdomain/mycontroller/myaction
Therefore %{REQUEST_URI} will be /zend/mycontroller/myaction.
Note that $1, which is the pattern in the RewriteRule directive in the htaccess context [1], "will initially be matched against the filesystem path, after removing the prefix that led the server to the current RewriteRule (e.g. app1/index.html or index.html depending on where the directives are defined)".
Therefore $1 will be mycontroller/myaction.
And %{REQUEST_URI}::$1 will be /zend/mycontroller/myaction::mycontroller/myaction.
The above string will be matched against ^(/.+)(.+)::\2$. Note that for the two capturing groups in round braces i.e., (/.+)(.+) before :: many combinations can match that. For example:
Group 1: /z
Group 2: end/mycontroller/myaction
or
Group 1: /zend/mycontroller/myactio
Group 2: n
and anything in between is a valid match. In fact, the most interesting one would be
Group 1: /zend/
Group 2: mycontroller/myaction
which (is the only case that) makes backreference \2 (after ::) to the second group a match.
In this case, /zend/ will be stored in the environment variable BASE which is what the first RewriteRule does. The %1 refers to the first matched string in RewriteCond which is /zend/.
Looking at the second RewriteRule, it is clear that why there is a need for this. As index.php can only be found in /zend/index.php, we need to add /zend/ in front of index.php.
Here we assume to use the URL-path as Substitution for the second RewriteRule directive. Refer to [1] and search for "A DocumentRoot-relative path to the resource to be served" under the RewriteRule Directive section.
All the above leave the query string unchanged/untouched. It is up to index.php how to parse the query string (as well as the URI).
Lastly goes the case where Zend is installed at the domain root.
%{REQUEST_URI} will be /mycontroller/myaction.
$1 will be mycontroller/myaction.
The string to be matched by RewriteCond will be /mycontroller/myaction::mycontroller/myaction.
This time the second group in (/.+)(.+) will never match mycontroller/myaction as there needs to be at least one letter following the initial backslash for the first group, making the second group as close as ycontroller/myaction but not exactly mycontroller/myaction so there cannot be a match.
As a result, the first RewriteRule is not used. The BASE enviornment variable will not be set, and when the second RewriteRule uses it, it will simply be empty.
References
[1] http://httpd.apache.org/docs/current/mod/mod_rewrite.html
The $1 in %{REQUEST_URI}::$1 references the matched string of the RewriteRule directive, i.e., the matched string of .* in ^(.*). So %{REQUEST_URI}::$1 is expanded to the requested URI path as supplied by the user, and the current internal URI path and query, separated by ::.
The pattern ^(/.+)(.+)::\2$ is used to find a prefix (first capturing group) which makes the remaining part match the part behind the :: (\2 is a back reference to the matched string of the second capturing group of the pattern).
If such a match is found, the prefix is stored in the environment variable BASE ([E=BASE:%1], where %1 references the matched string of the previous successful RewriteCond pattern match).
At the moment I am just matching numbers, letters, dashes and underscores in my .htaccess file:
RewriteRule ^([A-Za-z0-9-_]+)/?$ index.php?folder=$1
I also want to match full stops in the string. I don't want to use:
(.*)
I have tried:
([.A-Za-z0-9-_]+)
([\.A-Za-z0-9-_]+)
([\\.A-Za-z0-9-_]+)
([A-Za-z0-9-_\.]+)
None of which seem to work.... how can I escape the full stop so it matches a full stop!
---------- Additional information ----------------
As an example:
mydomain.com/groups/green/ should go to index.php?folder=green
In addition I am also re-writing subdomains over the top of this (I think this is causing the complication)...
anotherdomain.com should map to index.php?folder=anotherdomain.com
I have succesfully re-written the subdomain with the following rule:
# external group domain name
RewriteCond %{ENV:Rewrite-Done} !^Yes$
## exclude requests from myhost.com
RewriteCond %{HTTP_HOST} !^www\.myhost\.com
## allowed list of domain masking domains
RewriteCond %{HTTP_HOST} ^(anotherdomain.com|extra.domain.com|external.otherdomain.com)
RewriteRule (.*) /groups/%1/$1
I think this is where the complication lies.
---------------- Solution ----------------------
Despite not finding a solution to the exact problem above, I have worked around it by changing the first re-direct (which maps the external domains) from:
RewriteRule (.*) /groups/%1/$1
to:
RewriteRule (.*) /groups/external/$1&external_domain=%1
The second re-write (on the folder) can then interpret the "external domain" variable instead of the folder.
Your first option is the simplest and is correct. Inside square brackets . has no special meaning, so you include it verbatim without any special escaping needed.
Actually there is a small problem with the second dash in 0-9-_. If you want a dash inside square brackets you should place it at the beginning of the character class. Otherwise it will have its special meaning of defining a character range:
([-.A-Za-z0-9_]+)
If that doesn't work there is something else wrong with your RewriteRule. For instance, if this is a global rule rather than per-directory (no RewriteBase) then URLs will begin with a slash /.