Denying access to URLs then IP blocks in htaccess - apache

I'm trying to block bad bots from clicking certain links to one site running Apache 2.4. Here is what I am trying in htaccess:
RewriteEngine On
# Check for the suspect querystring first
RewriteCond %{QUERY_STRING} gclid=(.*)
RewriteRule .* - [E=IsAdClick:1]
# Filter on those requests with an ad string
<IfDefine IsAdClick>
# BAN USER BY IP
Order Deny,Allow
Deny from 172.64.0.0/13
Deny from 173.245.48.0/20
...
</IfDefine>
The deny rules work if they are by themselves, but for the life of me I cannot get the conditional to work. I've tried other things like
<If "%{QUERY_STRING} =~ /gclid=.*?/">
# BAN USER BY IP
Order Deny,Allow
Deny from 172.64.0.0/13
Deny from 173.245.48.0/20
...
</If>
but there is no effect. Traffic still comes through. What am I missing? I don't want to write a whole bunch of RewriteCond for each IP, nor change the .config files. Thanks.
Update: According to this SO post it seems that IfDefine only responds to command line parameters. Ref:
The IfDefine directive in Apache, Only , ONLY and when I say only i
mean ONLY, responds to parameters passed at the command line. Let me
emphasize that a little. ONLY COMMAND LINE!
How to achieve the effect I'm looking for though?

This took a lot of trial and error, but this seems to be working on THE_REQUEST which include any querystring data:
# Filter on those requests with an adwords string
<If "%{THE_REQUEST} =~ /gclid=/i">
# BAN USER BY IP
Order Deny,Allow
Deny from 172.64.0.0/13
Deny from 173.245.48.0/20
...
</If>
Still, I'd like to know why my second attempt in my question failed.

Related

Using HTTP Host in filesmatch in htaccess

I am trying to match my sitemap based on host and it doesn't seem to be working. Can you help me figure this out.
My sitemap is sitemap-localhost.xml since i am running on my local
I have tried
<FilesMatch (sitemap-%{HTTP:Host}.xml)>
Order Deny,Allow
Allow from all
</FilesMatch>
<FilesMatch "sitemap-%{HTTP:Host}.xml">
Order Deny,Allow
Allow from all
</FilesMatch>
<FilesMatch sitemap-%{HTTP:Host}.xml>
Order Deny,Allow
Allow from all
</FilesMatch>
But nothing seems to work. The problem is I have two domains pointing to the same folder in the server and the two domains have two sitemaps.
FilesMatch directive is designed to match against files only. You can not check HTTP_HOST header or URL path using this directive, only filename with its extension is allowed in the pattern.
If you want deny access to an xml file of a specific Host ,for example To deny access to thishost.com/sitemap.xml you can use mod-rewrite` .
RewriteEngine on
RewriteCond %{HTTP_HOST} ^thishost\.com$
RewriteRule ^/?sitemap\.xml$ - [R=403,L]
This will return a 403 error to clients if they visit thishost.com/sitemap.xml .
The leading slash ( /? ) in the pattern above is optional so that the Rule can work in both contexts htaccess and server.config .

Restrict acess Basic Auth to all but one file+query string

I need to prevent access to all files in a dir but one specific file, with a specific query string. I've been trying this so far, but I REQUEST_URI doesn't have the QUERY STRING
SetEnvIf Request_URI ^index.php?myquery$ noauth=1
AuthType Basic
AuthUserFile /home/user/.htpasswd
AuthName "Pass"
Order Deny,Allow
Satisfy any
Deny from all
Require valid-user
Allow from env=noauth
Again, the user should only be able to access index.php?myquery. Not index.php or anything.php?myquery
SetEnvIf cannot access the query string in Apache 2.2. In 2.4, you could access the query string in a 2nd SetEnvIf or just use <if>
Here's a simple example in mod_rewrite though that works in 2.2 vhost context:
RewriteEngine ON
RewriteCond %{REQUEST_URI} =/index.php
RewriteCond %{QUERY_STRING} =myquery
RewriteRule .* - [E=noauth:1]
Note: doesn't work in htaccess/per-dir context
Don't think you can do what you want here since you can't use mod_rewrite to alter the request (auth module happens before rewrite module) and you can't match against the query string in the request URI. You may need to do something with some redirect trickery, maybe something like:
make a symlink of index.php called index2.php (so that they are the same file)
make the SetEnvIf call match simply ^/index.php
Within the index.php script (probably near the very top), have it look for whether or not there's a myquery query string, and if not, redirect the request to /index2.php
When the browser is told to go to /index2.php instead, it gets asked for authentication
If the browser enters the correct auth, index.php gets executed (because of step #1).
If you are using Apache 2.4, SetEnvIf and mod_rewrite workarounds are no longer necessary since the Require directive is able to interpret expressions directly:
Apache 2.4 treats Require directives that are not grouped by as if they were in a , which behaves as an "or" statement.
Allow access to /callbacks/foo
Require expr %{REQUEST_URI} =~ m#^/callbacks/.*#
Require valid-user
Allow access to /callbacks/foo?secret_var=42 :
Require expr %{QUERY_STRING} = 'secret_var=42'
Require valid-user
This example would allow access to /callbacks/foo?secret_var=42 but require a username and password for /callbacks/foo :
<RequireAny>
<RequireAll>
# I'm using the alternate matching form here so I don't have
# to escape the /'s in the URL.
Require expr %{REQUEST_URI} =~ m#^/callbacks/.*#
Require expr %{QUERY_STRING} = 'secret_var=42'
</RequireAll>
Require valid-user
</RequireAny>
More examples.

Block IP access to specific page only

I need to block access from a certain IP address to one page of a website only, not the entire website.
Here's what I have, but doesn't seem to be working (I switch out offending IP to mine and am still abel to access after refresh/cache dump etc)
<Files specificpage.php>
order deny,allow
deny from XX.XXX.XXX.XX
</Files>
Is there a better way of doing this or does anything jump out here?
thx
You can actually mod_rewrite rules for finer control here. Place this in your root .htaccess:
RewriteEngine On
RewriteCond %{REMOTE_ADDR} =XX.XXX.XXX.XX
RewriteRule ^specificpage\.php$ - [F,NC]

Apache 2.2 - "Allow from" only if QUERY_STRING matches

I'm trying to limit one of my servers to only one specific request, but after 2 hours of trying couldn't come up with a working solution. Basically I'm looking for something similar to the <If ...> directive, but I only have Apache 2.2 (this is a fact, and I cannot update to 2.4).
I have 4 Servers: frontend[1-3] and backend1. frontend[1-2] are allowed to do anything on backend1, but frontend3 should only be allowed to make 1 specific request. In Apache 2.4 it would look something like this:
<Location />
Order allow,deny
Allow from frontend1
Allow from frontend2
<If "%{QUERY_STRING} =~ /foobar/myfunc/[^/]*$">
Allow from frontend3
</If>
</Location>
How can I do the same in Apache 2.2? I tried using SetEnvIf, but since it hasn't got logical AND it was a mess and didn't work (I have to match the host and the URL, since frontend3 is only allowed to do "myfunc").
Found a way with the help of mod_rewrite:
RewriteEngine On
# Matching the host "frontend3"
RewriteCond %{REMOTE_ADDR} ^1\.2\.3\.4$
# Matching the request "/foobar/myfunc?do=something"
RewriteCond %{QUERY_STRING} ^do=something$
# Setting an environment variable if host & request match
RewriteRule ^/foobar/myfunc$ - [E=allowthis:1,L]
<Location />
Order allow,deny
Allow from frontend1
Allow from frontend2
Allow from env=allowthis
</Location>

Dynamic IP .htaccess blocklist?

Is it possible to block users from IP adresses with a dynamic file-based blocklist?
So, suppose the .htaccess looks like:
order Deny,Allow
Deny from 123.156.0.1
Deny from 10.0.0.10
Allow from all
Can this list be made dynamic, for example:
order Deny,Allow
[include Deny list here]
Allow from all
Another option would of course be to fix it with PHP, but it is preferable to let Apache handle this.
According to the Apache docs, it doesn't seem to be possible to read values from a text file.
However, you could include a configuration file containing the IP addresses. They would have to be in Apache's conf file format, though.
This should work:
order Deny,Allow
include conf/IPList.conf
Allow from all
It's even possible to include whole directories, even though it's not recommended.
I use the RewriteMap feature from Apache's RewriteModule, as a whitelist like this:
## WHITELIST IPS ##
RewriteMap ipslist txt:/path/to/whitelist.txt
RewriteCond %{REMOTE_ADDR} ^(.*)$
RewriteCond ${ipslist:%1|black} ^black$ [NC]
RewriteRule (.*) - [F]
With some tweaking, you could make this a blacklist.