Deny request with environment variable - apache

I am using apache. I have a header variable which name is GEO_COUNTRY. I want something like that:
If GEO_COUNTRY == "USA" THEN DENY THE REQUEST
Is this possible with using .htaccess?
Ps: I know Stackoverflow rules, I researched it and nothing find so I couldn't try anything.

Here is how you can deny the request if env var GEO_COUNTRY is set and the value is usa
RewriteEngine on
RewriteCond %{ENV:GEO_COUNTRY} ^usa$ [NC]
RewriteRule ^ - [F,L]

Related

How to write an IF contains condition matching 2 ENV variables set via RewriteRules

To give context, the goal:
Using apache httpd I need to test a contextual segment of the request uri is contained within a cookie value sent in the header before redirect the user to a splash page for cookie confirmation, or allowing them access to the site.
Given the following:
url: http://www.example.com/en/gb/main.html
cookie: ;acceptedCookies=fr,en,de,it
If the language segment of the url = "en", and this is amongst the users acceptedCookies. Then allow the user access to the main site, else redirect the user to the splash page.
What I've tried:
SetEnvIf Host ^ uriCountryCode=NUL
SetEnvIfNoCase Request_URI "^(.+)?\/([a-zA-Z]{2})\/[a-zA-Z]{2}\/.+$" uriCountryCode=$2
SetEnvIf Host ^ acceptedCookieList=EMP
SetEnvIf Cookie "(^|;\*)acceptedCookies=([^;]+)?" acceptedCookieList=$2
#1st.
<If "%{acceptedCookieList} =~ %{uriCountryCode}">
// Doesn't work
</If>
#2nd.
<If "env('acceptedCookieList') =~ env('uriCountryCode')">
// No luck
</If>
#3rd.
<If "env('acceptedCookieList') =~ /env('uriCountryCode')/">
// Now I'm just guessing
</If>
#4th.
RewriteCond %{acceptedCookieList} !%{uriCountryCode}
RewriteCond %{REQUEST_URI} !^/en/gb/splash.html$ [NC]
RewriteRule ^(.+)$ /mt/en/splash [L,R=301]
I've recently learnt that some of these modules i.e env('x') won't load SetEnvIf variables dues to the SetEnvIf variables not loading early enough to be accessible but i'm trying to find a httpd solution to this my problem
mod_rewrite can set environment variables.
Use a 302 redirect (Moved Temporarily) instead of a 301 redirect (Moved Permanently).
Matching against an arbitrary regex provided by the client (i.e. the contents of the acceptedCookies cookie) is dangerous. Nevertheless, the httpd expressions language doesn't have a built-in "contains" function and so it's non-obvious how to avoid the regex matching. This will make your server(s) susceptible to DoS attacks.
All that said, consider something like:
RewriteCond %{HTTP_COOKIE} acceptedCookies=([^;]+)
RewriteRule ^.*$ - [E=COOKIE_ACCEPTED_LANGS:%1]
RewriteCond %{REQUEST_URI} ^/([^/]+)/.*$
RewriteRule ^.*$ - [E=URL_LANG:%1]
RewriteCond expr %{ENV:URL_LANG} =~ %{ENV:COOKIE_ACCEPTED_LANGS}
RewriteCond %{REQUEST_URI} !^/en/gb/splash.html$ [NC]
RewriteRule ^.*$ /mt/en/splash [R]
Following #Avi solution will work, but any solution allowing client-side values unknown in length to perform validation is fundamentally flawed, posing the potential risk of exceeding buffers and DOS.

How can I use .htaccess to block access when a parameter is empty?

I have URLs like this: page.php?param1=xxx&param2=yyy
Using .htaccess, I want to block access when param2 is not specified or is empty. I don't mind about param1. So the following should be blocked:
page.php?param2=
page.php?param1=somevalue
page.php
But these should be allowed:
page.php?param2=somevalue
page.php?param1=somevalue&param2=anothervalue
I'm aware of mod_rewrite deny acces if parameter equals something, but my RegEx isn't good enough to modify that answer for my purposes.
My server is running Apache 2.4 on CentOS.
You can use:
RewriteEngine on
RewriteCond %{QUERY_STRING} !(^|&)param2=[^&]+(&|$)
RewriteRule ^page\.php$ - [NC,F]

apache SetEnvIf access query string

How do you access the query string from SetEnvIf? Somethig like:
SetEnvIf Query_String "p=path/to/file$" got_path
UPDATE:
In htaccess, I have:
SetEnvIf Request_URI !/folder/page1\.html$ NO_COOKIE
Header unset Cookie env=NO_COOKIE
RewriteRule (.*) /h.php?ref=$1 [L]
Basically, I ask h.php to take control of all user requests. And I use SetEnvIf to allow cookies only for /folder/page1.html.
However, it seems like Request_URI is always set to "h.php" and never to " /folder/page1.html" (maybe because of the redirection). For that reason I added ref=$1 to try to recognize which url it is being redirected from. Therefore I need to read the query string from SetEnvIf.
I hope I am making some sense.
You don't need to add a query string for this.
You can use:
# always start with NO_COOKIE=1
RewriteRule ^ - [E=NO_COOKIE:1]
# unset NO_COOKIE when URI is /folder/page1.html
RewriteCond %{THE_REQUEST} /folder/page1\.html
RewriteRule ^ - [E=!NO_COOKIE]
Header set NoCookie %{NO_COOKIE}e
RequestHeader set NoCookie %{NO_COOKIE}e

Redirect a range of IPs using RewriteCond

Currently I am redirecting all users except for the IP 12.345.678.90 using:
RewriteEngine On
RewriteCond %{REQUEST_URI} !/maintenance$
RewriteCond %{REMOTE_HOST} !^12\.345\.678\.90
RewriteRule $ /maintenance [R=302,L]
What syntax would I use to allow a range? In my Allow list I have:
Allow from 123.45.678.90/28
Would it work if I just update the REMOTE_HOST line to:
RewriteCond %{REMOTE_HOST} !^12\.345\.678\.90/28
If you're using Apache HTTPD 2.4 or later, you can use expressions to match REMOTE_ADDR against a CIDR mask.
The short form looks like this:
RewriteCond expr "-R '192.168.1.0/24'"
The following longer form is also available, but the documentation suggests it is less efficient:
RewriteCond expr "%{REMOTE_ADDR} -ipmatch '192.168.1.0/24'"
That makes the full solution to your example something like this:
RewriteEngine On
RewriteCond %{REQUEST_URI} !/maintenance$
RewriteCond expr "! -R '12.345.678.90/28'"
RewriteRule $ /maintenance [R=302,L]
You probably want the %{REMOTE_ADDR} to match against, but you can't use CIDR notation as the %{REMOTE_ADDR} is literally the remote address and you can use a regular expression to try to match against it. So for 123.45.67.89/28, (123.45.67.80 - 123.45.67.95), you'd have to do something like this:
RewriteCond %{REMOTE_ADDR} !^123\.45\.67\.8[0-9]$
RewriteCond %{REMOTE_ADDR} !^123\.45\.67\.9[0-5]$
Although this is an old question, I find it still very relevant. An alternative that does allow CIDR notation is the following (example is in a virtualhost apache conf file):
<VirtualHost *:80>
.
.
.
<Files maintenance>
Require all denied
Require ip 12.345.678.90/28
</Files>
.
.
.
</VirtualHost>
As a sidenote, I suspect, without having done any testing or finding any evidence, that this method is "faster" than the RewriteCond expr "-R '192.168.1.0/24'" methods mentioned.
This is for the simple reason that at this high level there appears to be less computational steps involved.
N.B. a requester from an IP that is denied will see a "Permission denied" or "Forbidden" type response. You can make this prettier by adding in a custom 404 page that responding with a 200/OK (this way Google won't penalise your domain). The 200/OK has to be the first line of your custom 404 page. For example in PHP, the first line would read:
<?php header("Status: 200 OK"); ?>
You'd want to do this for a legit page you redirect to. Actual 404s should respond with 404 to keep us from ending up with a ton of useless search engine results down the road.
Try this in .htaccess. It's working.
RewriteCond %{REMOTE_ADDR} !^123\.456\.789\.[0-255]
I like to use the following which allows partial address matching. In Your virtualHost/htaccess file
SetEnvIf HOST "siteYouAreworkingON.com" ACCESS_CONTROL<br>
SetEnvIf Remote_Addr "list of full or partia ipadresses separated by |"<br>
RewriteCond %{ENV:ACCESS_CONTROL} 1<br>
RewriteRule .* http://gohere.instead [L,R]
Hope it helps.

How to use SetEnv with a URL parameter

I'm trying to implement language switching in .htaccess, and the only thing left now is to handle clients which don't support cookies. To do that, I must set prefer-language when the user clicks a link with a language parameter.
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} (?:^|&)language=(en|fr|no)
RewriteRule ^(.*)$ $1? [cookie=language:%1:.example.com,env=language:%1,R]
SetEnv prefer-language $language
The problem is with the last line - The value is always set to empty. It works if I hardcode it, but not if I try to refer to a variable. Is there some special syntax to refer to environment variables in this context, or is there some other way to set prefer-language?
Edit: Cross-posted to Apache users list.
You can set environment variables with mod_rewrite as well. Actually, you already did that (see env/E flag).
I can’t test it with mod_negotiation myself, but the following should work and set the prefer-language:
RewriteCond %{QUERY_STRING} ^((?:[^&]&)*)language=(en|fr|no)&?([^&].*)?$
RewriteRule ^ %{REQUEST_URI}?%1%3 [L,CO=language:%2,R]
RewriteCond %{HTTP_COOKIE} (^|[,\s])language=([^\s,;]+)
RewriteRule ^ - [L,E=prefer-language:%2]
SetEnvIf REDIRECT_prefer-language (.+) prefer-language=$1
But it would be far easier if you put the language identifier into the URL path like /en/…:
SetEnvIf Request_URI ^/(en|fr|no)/ prefer-language=$1
SetEnvIf REDIRECT_prefer-language (.+) prefer-language=$1
I don’t know if you need the additional/second SetEnvIf variable.
Looks like there's no support for variables in SetEnv, but here's a working configuration if someone else is trying to do the same. It's a simpler kind of language selection, since it just copies the language parameter from the referer to the current URL if it's not changed:
RewriteEngine On
RewriteBase /
# Keep the language parameter if specified in the last URL
RewriteCond %{HTTP_REFERER} ^(?:.*[&?])?language=(en|fr|no).*$
RewriteCond %{QUERY_STRING} !^(?:.*&)?language=(en|fr|no).*$
RewriteRule ^(.*)$ $1?language=%1 [redirect=permanent]
# Set the language from the URL parameter
RewriteCond %{QUERY_STRING} ^(?:.*&)?language=(en|fr|no).*$
RewriteRule ^ - [env=prefer-language:%1]
# Cache only when the language parameter is set
<IfDefine !prefer-language>
Header set Vary *
</IfDefine>