.htaccess Escaping Periods - .htaccess

I recently had an RFI attack where the query string had a bunch of ../../../ and I'd like to modify .htaccess to prevent any ../ in the query string.
I was trying this until I realized the period needed to be escaped:
RewriteCond %{QUERY_STRING} ../
RewriteRule .* - [F]
I then changed it to:
RewriteCond %{QUERY_STRING} \.\./
RewriteRule .* - [F]
But it still forbids any / in the query string.
Also, If I have the rule in {REQUEST_URI} would that make the {QUERY_STRING} redundant?
Thanks.
EDIT:
I have had success getting this to work by:
RewriteCond %{QUERY_STRING} (\.\./)
However, RewriteCond %{REQUEST_URI} \.\./ or RewriteCond %{REQUEST_URI} (\.\./) does not. I've also tried /\.\./ & (/\.\./)

The %{QUERY_STRING} is everything after the ?, so your rules successfully block a URL like htis:
http://domain.com/blah.php?../../../path
But your URI won't be checked. You can check against both by amending your rule:
RewriteCond %{QUERY_STRING} \.\./ [OR]
RewriteCond %{REQUEST_URI} \.\./
RewriteRule .* - [F]

Related

Htaccess query string

I am trying to make:
http://www.specialisedorthoticservices.co.uk/image.php?object_type=detailed&image_id=140&window=popup
become this:
http://www.specialisedorthoticservices.co.uk
The result of the query no longer exists and the re-direct doesn't seem to work see code below:
RewriteCond %{REQUEST_URI} ^/image\.php$
RewriteCond %{QUERY_STRING} ^object_type=detailed&image_id=140&window=popup$
RewriteRule ^(.*)$ http://www.specialisedorthoticservices.co.uk [R=301,L]
Remove the slash before image.php. In fact, why not just shorten it? To not append the query string you need a terminating question mark like so
RewriteEngine On
RewriteCond %{QUERY_STRING} ^object_type=detailed&image_id=140&window=popup$
RewriteRule ^image\.php$ /? [R=301,L]

Force redirect for certain files (based on referer) and trigger a 404 page otherwise

We distribute different versions of a software product through a single download link. The delivery is based on the referer in conjunction with a default value, which works fine. In addition the user should be redirected to a 404-page, in case the wrong filename was used.
At the moment the .htaccess-file looks like this:
# stop directory listing
Options -Indexes
# turn rewrite engine on
RewriteEngine On
# force 404 if file name is missing or wrong
RewriteCond %{REQUEST_URI} !^(download_mac\.zip|download_pc\.zip)$
RewriteRule (.*) 404/index.html [L]
# an example based on the referer
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-a\.com [OR]
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-b\.com
RewriteRule ^(download_mac\.zip|download_pc\.zip)$ domain_ab/$1 [L]
# last rule if no referer matches
RewriteRule ^(download_mac\.zip|download_pc\.zip)$ default/$1 [L]
So I have one issue and one additional question with this file:
The first rule, to force 404, is very greedy and gets the error page every time, no matter what URL is called. I also tried single statements like RewriteCond %{REQUEST_URI} !^download_mac\.zip$ without any effect. How can I fix this?
How can I get rid of the filenames in any other rule? I tried things like RewriteRule ^(.*)$ default/$1 [L] but it gives me a hard time and an 500 Internal Server Error.
You can avoid repeating your filenames by using an Env variable like this:
RewriteRule ^(download_mac\.zip|download_pc\.zip)$ - [E=ALLOWED:$1,NC]
RewriteCond %{ENV:ALLOWED} ^$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /404/index.html [L]
RewriteCond %{ENV:ALLOWED} !^$
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-a\.com [OR]
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-b\.com
RewriteRule ^ /domain_ab/%{ENV:ALLOWED} [L]
RewriteCond %{ENV:ALLOWED} !^$
RewriteRule ^ /default/%{ENV:ALLOWED} [L]
You can just move the rewrite rule to the end. The other rules handle the valid cases and if none of them matches the last rule applies
# an example based on the referer
RewriteCond %{HTTP_REFERER} ^http://([^.]+\.)*domain-[ab]\.com
RewriteRule ^download_(mac|pc)\.zip$ domain_ab/$0 [L]
# last rule if no referer matches
RewriteRule ^download_(mac|pc)\.zip$ default/$0 [L]
# force 404 if file name is missing or wrong
RewriteRule ^ 404/index.html [L]

Rewriting urls using mod_rewrite : Error with multiple rules

I have following code in .htaccess
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)(/([^/]+))?(/(edit)+)(/([^/]+))?/?$ edit.php?secret=Y7qD7&category=$1&slug=$3&edit=$5&part=$7 [L]
RewriteRule ^([^/]+)(/([^/]+))?/?$ content.php?category=$1&slug=$3 [L]
RewriteRule ^(/)?$ content.php [L]
What I expect to achieve is
http://example.com/test/test1/edit/part to edit.php?category=test&slug=test1&edit=edit&part=part
http://example.com/test/edit/part to edit.php?category=test&slug=&edit=edit&part=part
(above rewrite is working as expected)
`http://example.com/test/test/` to `content.php?category=test&slug=test`
`http://example.com/test/` to `content.php?category=test&slug=`
(Please note that there is no "/edit/" & "/part/" in above 2 urls)
for above two rewrites, first one is working fine but the second one is not working as expected. The last one get rewrite to content.php?category=content.php&slug= which is not correct.
Also trailing slash should not make a difference for the rewrite.
Could somebody please show me what I'm doing wrong here?
I didn't check why the rule in your question doesn't work as expected, but you may try this instead:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/([^/]+)/?([^/]*)?/?([^/]*)?/?([^/]*)?/?
RewriteRule .* edit.php?key1=%1&key2=%2&key3=%3&key4=%4 [L]
Maps silently:
http://example.com/val1/ up to
http://example.com/val1/val2/val3/val4/ with or without trailing slashes
To:
http://example.com/edit.php?key1=val1&key2=val2&key3=val3&key4=val4
The maximum quantity of valN values passed in the incoming URL, is 4. The minimum is 1. That range can be adjusted modifying the rule, though.
When any valN is not present in the incoming URL, the value in the corresponding key-value pair in the query added to the substitution URL, will be empty.
However, the key will always be present in the query as all keys are fixed strings not passed by the incoming URL.
This rule-set is tested and working and it should be tested without any other rule that might get in conflict with it. I didn't check the other rules in the question and can't say if they work or if they could affect this one. That was not part of the question.
UPDATE
Redirecting to edit.php:
Mapping to edit.php is required only when there are 3 or 4 folders in the URL-path.
The modified rule-set is:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !edit\.php [NC]
RewriteCond %{REQUEST_URI} ^/([^/]+)/([^/]+)/([^/]+)/?([^/]*)?/?$ [NC]
RewriteRule .* edit.php?key1=%1&key2=%2&key3=%3&key4=%4 [L,QSA]
Maps silently:
http://example.com/val1/val2/val3/ up to
http://example.com/val1/val2/val3/val4/ with or without trailing slashes
To:
http://example.com/edit.php?key1=val1&key2=val2&key3=val3&key4=val4
The maximum quantity of valN values passed in the incoming URL, is 4. The minimum is 3.
Redirecting to content.php:
Mapping to content.php is very similar to the previous one, except is done only when the number of folders is 1 or 2.
So the rule-set is basically the same with less regex groups:
RewriteCond %{REQUEST_URI} !content\.php [NC]
RewriteCond %{REQUEST_URI} ^/([^/]+)/?([^/]*)?/?$ [NC]
RewriteRule .* content.php?key1=%1&key2=%2 [L,QSA]
Maps silently:
http://example.com/val1/ up to
http://example.com/val1/val2/ with or without trailing slashes
To:
http://example.com/content.php?key1=val1&key2=val2
The maximum quantity of valN values passed in the incoming URL, is 2. The minimum is 1.
The complete rule-set is like this:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !edit\.php [NC]
RewriteCond %{REQUEST_URI} ^/([^/]+)/([^/]+)/([^/]+)/?([^/]*)?/?$ [NC]
RewriteRule .* edit.php?key1=%1&key2=%2&key3=%3&key4=%4 [L,QSA]
RewriteCond %{REQUEST_URI} !content\.php [NC]
RewriteCond %{REQUEST_URI} ^/([^/]+)/?([^/]*)?/?$ [NC]
RewriteRule .* content.php?key1=%1&key2=%2 [L,QSA]
Hope I understood what you want.

how to generic .htaccess to prevent hotlink

The following code works fine:
RewriteCond %{HTTP_REFERER} !^http://superwebx.com/.*$ [NC]
RewriteRule .*\.(jpe?g|gif|bmp|png|swf|css)$ - [F]
but I want to make a generic script serve me for several sites I manage, but fails try to get
RewriteCond %{HTTP_REFERER} !^http://%{HTTP_HOST}/.*$ [NC]
RewriteRule .*\.(jpe?g|gif|bmp|png|swf|css)$ - [F]
You can't use variables inside the regex. You can work around this by using a RegEx backreference like so:
RewriteCond %{HTTP_REFERER} ^https?://([^/]+)/ [NC]
RewriteCond %1#%{HTTP_HOST} !^(.+)#\1$
RewriteRule \.(jpe?g|gif|bmp|png|swf|css)$ - [F]
(note the # is just used as a boundry. It could be any character that isn't used in domain-names.)
Very old one, but here's your answer:
RewriteCond %{HTTP_HOST}##%{HTTP_REFERER} !^([^#]*)##https?://\1/.*

RewriteRule - a.php?a=123 to /b/123

I am trying to get Apache to redirect /a.php?a=123 to /b/123 (where 123 could be any number between 1 and 9999) but can't seem to get it to work.
This is what I have in htaccess:
RewriteEngine on
RewriteRule ^a.php?a=([0-9]+) /b/$1 [L]
RewriteRule ^a.php$ /c/ [L]
With this going to a.php?a=123 results in 404, but going to just a.php works as expected.
I tried escaping the ? (RewriteRule ^a.php\?a=([0-9]+) /b/$1 [L]) but it still doesn't work.
What am I doing wrong please?
The query string is not part of the URI path that is tested in the RewriteRule directive. This can only be tested with a RewriteCond directive:
RewriteCond %{QUERY_STRING} ^a=([0-9]+)$
RewriteRule ^a\.php$ /b/%1? [L,R]
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^a\.php$ /c/ [L,R]
But if you want it the other way (requests of /b/123 are redirected to /a.php?a=123):
RewriteRule ^b/([0-9]+)$ a.php?a=$1 [L]

Resources