Only allow redirects within the same domain with mod_rewrite - apache

I would like to limit any redirects to URLs within the same application. Is this possible with ISAPI Rewrite (mod_rewrite for IIS)? Basically I want to prevent against open redirection attacks.
One example is where a URL may come from a query string, or some other source. I want to check that any use of that URL, for a redirect, is only permitted if it's within the same domain. For example: Response.Redirect("some URL");
Mine is an ASP.NET application, running under IIS 6.

You can try to use the following to check the domain in query string and show 403 Forbidden if it's an external one:
RewriteBase /
RewriteCond %{QUERY_STRING} !^.*yourdomain.com.* [NC]
RewriteRule .? - [F]

You'll need to do that check on ASP.NET side, not to allow redirects outside your domain. Once redirect instruction is sent to client, your server will never get another chance to bump in because client will immediately go to other domain.
If you don't control ASP.NET code of this application you may try to use Helicon Ape (instead of ISAPI_Rewrite). Helicon Ape has more features and also offers outbound response rewrites, so it may intercept "redirect" response of your application before it is sent to client. Two options are available:
mod_header with "Header" directive;
mod_replace with "HeaderReplacePattern" directive

Related

Apache mod_rewrite redirect subdomains on specific basis

I'm developing an application that is running on my domain.
All works as expected, but I cannot seem to find any good answer to my problem relating subdomains.
This application allows for different clients to register themselves and get their own "environment" inside the application.
E.g. if client1 registers himself, his environment will be at https://main.application.com/v/client1
Now, as you can see, this is quite ugly. I want him to be able to go to https://client1.application.com/ and in the background it would show him https://main.application.com/v/client1.
I've read this is possible with apache rewrite.
My case is a little bit more complex than a simple rewrite, I'm guessing. What I'm trying to achieve is this:
User goes to | Has to redirect to
client1.application.com | main.application.com/v/client1
client1.application.com/register | main.application.com/v/client1/register
client1.application.com/dashboard | main.application.com/dashboard
client1.application.com/... | main.application.com/...
As you can see, the only time I want to redirect with the /v/client1 appended to my domain, is when somebody is trying to register or trying to reach the login page for their environment. In all other scenarios, I just want to take what's behind the URL and append it to main.application.com (which is where the main app runs). I also don't want the users to notice the redirect, but that the URL in the address bar stays the same.
I've tried to come up with a bit of pseudocode that explains what I want to do:
If subdomain.application.com/ or subdomain.application.com/register
--> take subdomain and paste it like this:
main.application.com/v/SUBDOMAIN/ or main.application.com/v/SUBDOMAIN/register
Else
--> Redirect to main.application.com/URL
e.g. client1.application.com/dashboard --> main.application.com/dashboard
But I'm completely lost on how I should write it with a Rewrite.
Has anybody got experience in this matter that would be able to help me out with those rewrites here? I'm new to this and I cannot find documentation for my specific case.
Assuming that all requests to those host names ("sub domains") are handled by the same http host (by means of a ServerAlias or simply using the default fallback host) this should be pretty straight forward...
do not rewrite any requests directly to example.com or www.example.com
rewrite requests to other hosts that do not specify any path
rewrite requests to other hosts that specify the /register path
no treatment for other paths required if your http host uses the same file system layout (DOCUMENT_ROOT) for all these hosts ("sub domains")
That leaves is with this:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^example\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule ^ - [END]
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$
RewriteRule ^/?$ /v/%1 [END]
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$
RewriteRule ^/?register/?$ /v/%1/register [END]
In case you receive an internal server error (http status 500) using the rule above then chances are that you operate a very old version of the apache http server. You will see a definite hint to an unsupported [END] flag in your http servers error log file in that case. You can either try to upgrade or use the older [L] flag, it probably will work the same in this situation, though that depends a bit on your setup.
This implementation will work likewise in the http servers host configuration or inside a dynamic configuration file (".htaccess" file). Obviously the rewriting module needs to be loaded inside the http server and enabled in the http host. In case you use a dynamic configuration file you need to take care that it's interpretation is enabled at all in the host configuration and that it is located in the host's DOCUMENT_ROOT folder.
And a general remark: you should always prefer to place such rules in the http servers host configuration instead of using dynamic configuration files (".htaccess"). Those dynamic configuration files add complexity, are often a cause of unexpected behavior, hard to debug and they really slow down the http server. They are only provided as a last option for situations where you do not have access to the real http servers host configuration (read: really cheap service providers) or for applications insisting on writing their own rules (which is an obvious security nightmare).

.htaccess redirects if the condition doe not match/ negative condition

I am modifying the .htaccess file of a legacy PHP web application. I am not familiar with apache .htaccess syntax. I found this tutorial. What I am trying to do is that I am trying to redirect all the requests to a URL/ path if the request URL is not a specific URL/ path. For example, all the requests to the website will be redirected to localhost/my-custom-page unless the request URL is localhost/my-custom-page.
I know how to redirect mapping 1 to 1 as follows:
RewriteEngine on
RewriteRule ^my-old-url.html$ /my-new-url.html [R=301,L]
But, what I am trying to do is that redirecting all the requests to the specific page unless the request is to that page. Even the home page will be redirected to that page. How can I do that?
When I tried the following solution
RewriteEngine on
RewriteCond %{REQUEST_URI} !/my-new-url\.html
RewriteRule ^ /my-new-url.html [R=301]
I get the error
I want to check using OR condition as well. For example, if the path is not path-one or path-two, redirect all the requests to path-one.
Your question is a bit vague, due to your wording. But I assume this is what you are actually looking for:
RewriteEngine on
RewriteCond %{REQUEST_URI} !/my-new-url\.html
RewriteRule ^ /my-new-url.html [R=301]
In case you receive an internal server error (http status 500) using the rule above then chances are that you operate a very old version of the apache http server. You will see a definite hint to an unsupported [END] flag in your http servers error log file in that case. You can either try to upgrade or use the older [L] flag, it probably will work the same in this situation, though that depends a bit on your setup.
It is a good idea to start out with a 302 temporary redirection and only change that to a 301 permanent redirection later, once you are certain everything is correctly set up. That prevents caching issues while trying things out...
This rule will work likewise in the http servers host configuration or inside a dynamic configuration file (".htaccess" file). Obviously the rewriting module needs to be loaded inside the http server and enabled in the http host. In case you use a dynamic configuration file you need to take care that it's interpretation is enabled at all in the host configuration and that it is located in the host's DOCUMENT_ROOT folder.
And a general remark: you should always prefer to place such rules in the http servers host configuration instead of using dynamic configuration files (".htaccess"). Those dynamic configuration files add complexity, are often a cause of unexpected behavior, hard to debug and they really slow down the http server. They are only provided as a last option for situations where you do not have access to the real http servers host configuration (read: really cheap service providers) or for applications insisting on writing their own rules (which is an obvious security nightmare).
RewriteCond %{REQUEST_URI} !/my-new-url\.html
RewriteRule ^ /my-new-url.html [R=301]
There are a few potential issues with this, particularly since you hint in a comment that you are perhaps using a front-controller to "route" the URL.
This redirect satisfies the conditions outlined in the question, but does assume that you have no other rewrites, have an essentially "static site" and are not linking to any static resources.
You are missing an L (last) flag, so processing will continue through the file and possibly be rewritten if you have later rewrites.
If you are rewriting the URL to a front-controller in order to route the URL (as you suggest in comments) then this redirect will break, as it will redirect away from the front-controller. You need to only redirect direct requests, ie. when the REDIRECT_STATUS environment variable is empty.
If you are linking to any static resources in the same file space then these will also be redirected. You need to create an exception for any static resources you are using, either by file extension (eg. (css|js|jpg|png)) or by location (eg. /static).
So, try the following instead:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} !\.(js|css|jpg|png)$
RewriteRule !^my-custom-url$ /my-custom-url [R=302,L]
You don't need a separate condition to implement the exception for the URL you are redirecting to. It is more efficient to do this directly in the RewriteRule pattern.
The first condition ensures we are only redirecting direct requests and not rewritten requests to your front-controller.
The second condition avoids any static resources also being redirected. You could alternatively check the filesystem path if all your resources are stored under a common root. Or, as a last resort, implement filesystem checks (ie. RewriteCond %{REQUEST_FILENAME} !-f) if your static resources are too varied - but note that this is less efficient.
You will need to clear your browser cache before testing, since any earlier (erroneous) 301s are cached persistently by the browser.

Rewrite URL .htaccess - Apache server

On my website, I would rename the URL on address bar, from
domain.com/economy/article.php?id=00
to
domain.com/economy/id-name-article.html
I wrote this .htaccess file:
RewriteEngine On
RewriteRule ^([0-9]+)-([^\.]*)\.html$ http://domain.com/economy/article.php?id=$1 [L]
I have an anchor with this href: href="economy/id-name-article.html" and when I click on it, the server is redirected on article.php, it runs the script in the correct way and I can view the article, but on the address bar is still written domain.com/economy/article.php?id=00 instead domain.com/economy/id-name-article.html. Why?
This happens only on my online server, while locally it's all right.
The mod_rewrite module is issuing a redirect to your browser rather than transparently rewriting the url, causing you to see the new url in your browser.
Try removing the http://domain.com portion from your RewriteRule to see if it avoids the redirect to your browser by changing the rule to:
RewriteRule ^([0-9]+)-([^\.]*)\.html$ /economy/article.php?id=$1 [L]
If that fails, you could also use the proxy flag [P] to force apache to transparently fetch the page and return it to your users without the redirect. I don't recommend this approach since it can have security implications but it should work if the above doesn't.
EDIT: To clarify, rewriting the url with a fully-qualified domain rather than a relative uri tells apache that the redirect is on a different server, and therefore it doesn't know that the new url is accessible on the same host without redirecting the client.

Apache rewrite rule - prevent rewritten URL appearing in browser URL bar

I have a rewrite rule which is looking for a particular URI. When it matches the particular URL it rewrites it with a proper file path so the required content can be found. It then changes the protocol to HTTPS and allows the request to pass through.
I have two problems;
I don't want the rewritten path to appear in the users browser - i want to maintain the vanity url
I do want the HTTPS protocol to appear indicating to the user that they are accessing the site over a secured conection.
I have tried a couple of options but no success. If i include the [R] flag the URL and protocol remain unchanged but that is not the desired effect
Any suggestions on how i can achieve this?
This is my rule;
RewriteMap redirectsIfSecure txt:/myserver/content/secure_urls.txt
RewriteCond ${lowercase:%{REQUEST_URI}} ^/(.+)$
RewriteCond ${redirectsIfSecure:%1|NOT_FOUND} !NOT_FOUND
RewriteRule ^(.*)$ https://myserver.com${redirectsIfSecure:%1} [PT]
From the mod_rewrite documentation:
If an absolute URL is specified, mod_rewrite checks to see whether the
hostname matches the current host. If it does, the scheme and hostname
are stripped out and the resulting path is treated as a URL-path.
Otherwise, an external redirect is performed for the given URL. To
force an external redirect back to the current host, see the [R] flag
below.
If you rewrite the request to a fully qualified URL (that is, anything starting with http://, https://, etc) that doesn't match your ServerName, then mod_rewrite will issue an HTTP redirect, which will cause the client browser to request the resource from the new location.
If you're not trying to switch between http and https you can use a proxy rule (the P flag) to have Apache make the request on behalf of the client and return the result, thus masking the rewritten URL.
However, if you're trying to upgrade from http to https (or the other way around), this will always require a client redirect.

Forward one domain to another based on request header

I have a requirement that I want to check the request headers and according to that I want to forward the incoming request to appropriate sub domain of my company.
For example:
request header A is coming then it goes to a.domain.com always (no matter request comes to a.domain.com or b.domain.com)
Similarly request header B is coming then it goes to b.domain.com always.
Although I can do this by changing my application (checking the request headers in it) and then forwarding the request but I want that instead of request reaching application server, it should be handled by web server at the first.
Is there something available (some way like CGI) which can handle IIS as well as Apache both as my company has sub domains hosting applications on these two.
Any help is greatly appreciated. Thanks
In Apache you can use mod_rewrite to direct the request to another domain, something like the following perhaps:
rewriteEngine on
rewriteBase /
rewriteCond %{HTTP_HOST} ^A$
rewriteRule ^(.*) http://a.domain.com/$1 [L,R=301]
This needs to be scoped appropriately by putting it in a .htaccess file in the appropriate directory or in a site configuration element.
IIS (depending on the version) also supports a rewrite module. For IIS 6 you can look at IIRF which has a syntax similar to mod_rewrite. For IIS 7 take a look at the URL Rewrite Module which has a simple GUI that imports mod_rewrite rules.