htaccess rule - Take the Place of Symlinked Files - .htaccess

I'm working on this legacy project that has a rather odd setup that I'm looking to get rid of but my htaccess skills are a little lacking in this department.
Here's the directory structure.
/index.php
/www
page1.php -> symlink to index.php
page2.php -> symlink to index.php
page3.php -> symlink to index.php
/www is the public directory and people visit http://site/page1.php. However, each of those files with an * actually symlinks to /index.php.
I find this arrangement idiotic and would like to get rid of the symlinks and simply have any /www/*.php request simply point at index.php without the page actually redirecting to index.php.
Any ideas for an htaccess rule(s) that could solve this problem? At its most basic core, I'd like to keep the same functionality without having to have a thousand symlinked files.

It looks like the index.php file is not in your document root (which I'm assuming is www), and because of that, I don't think there's a way you can do this from your .htaccess file. In order to access something outside of your document root, you'll need to setup an alias in either your server config or your vhost config:
# Somewhere in vhost/server config
Alias /index.php /var/www/path/to/index.php
# We need to make sure this path is allowed to be served by apache, otherwise
# you will always get "403 Forbidden" if you try to access "/index.php"
<Directory "/var/www/path/to">
Options None
Order allow,deny
Allow from all
</Directory>
Now you should be able to access /var/www/path/to/index.php. Note that other files in the /var/www/path/to directory is safe as long as you don't create an Alias (or AliasMatch or ScriptAlias) that points to them. Now that you can access index.php via the /index.php URI, you can setup some mod_rewrite rules in the .htaccess file in your document root (www) to point things to index.php:
# Turn on the rewrite engine
RewriteEngine On
# Only apply the rule to URI's that don't map to an existing file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Rewrite all requests ending with ".php" to "/index.php"
RewriteRule ^(.*)\.php$ /index.php [L]
This will make it so when you request http://site/page1.php, the browser's address bar is unchanged but the server actually serves /index.php, which is aliased to /var/www/path/to/index.php.
You can tweak the regular expression ^(.*)\.php$ to something more appropriate if need be. This just matches anything that ends with a .php, including /blah/bleh/foo/bar/somethingsomething.php. If you want to limit the directory depth, you can tweak the regular expression to ^([^/]+)\.php$, etc.

Related

Restrict access to TYPO3 backend via .htaccess

I'm trying to restrict access to the TYPO3 backend and the install tool. Beacause of that, the IPMaskList isn't the best thing to do so. I tried an .htaccess file in the /typo3 directory and it worked quite well to certain point. The following code was used to accomplish that:
RewriteEngine On
RewriteCond %{REMOTE_ADDR} !=<my_ip>
RewriteRule ^(.*)$ https://example.com [R=301]
Only the computer with the listed ip can access the index.php or install.php, which is very good. But as soon as I click the login button, and the URL changes to https://example.com/typo3/login?loginProvider=1433416747, it throws a 404 error. First, I thought it was the configured IP, as the server is requesting a page, and not my computer, but I don't know how to implement that.
The problem might just be that you are missing the L flag on the RewriteRule. The missing L flag will cause processing to continue through the remaining directives which probably includes a front-controller pattern. Typo3 then generates a 404 because https://example.com is not a valid "Typo3" URL.
But also...
First, I thought it was the configured ip, as the server is requesting a page, and not my computer,
If the server itself is also making an HTTP request (although not sure why) then you will also need to permit the server's IP address in your rule. For example:
RewriteCond %{REMOTE_ADDR} !=<my_ip>
RewriteCond %{REMOTE_ADDR} !=<server_ip>
RewriteRule ^ https://example.com/ [R=301,L]
Additional changes:
Missing L flag. (Mentioned above)
Missing trailing slash after the hostname (the browser "corrects" it).
No point capturing the URL-path in the RewriteRule pattern.
Although if you simply ant to restrict access then why not serve a "403 Forbidden" instead. Change the RewriteRule accordingly:
:
RewriteRule ^ - [F]
(L flag not required here.)
UPDATE:
No, by default there's no .htaccess in that dir, only the one in the root dir. Only with a .htaccess in the typo3 dir it's resulting in a 404. That's my only content in this particular .htaccess.
By enabling the rewrite engine in the subdirectory then it's going to completely override any mod_rewrite directives in the parent .htaccess file (by default), regardless of whether you are accessing the site by your IP or not. It would seem there are mod_rewrite directives in the parent/root .htaccess file that are required for your Typo3 installation to function (a front-controller pattern perhaps). (I had assumed these were all in the /typo3/.htaccess file.)
There are two solutions:
Move the above rule to the top of the root .htaccess file, adjusting accordingly. And delete the /typo3/.htaccess file. For example:
# In the root ".htaccess" file
RewriteCond %{REMOTE_ADDR} !=<my_ip>
RewriteRule ^typo3(/|$) - [F]
OR
Don't use mod_rewrite to block the request. For example, use an Apache expression with mod_authz_core instead. For example:
# In the "/typo3/.htaccess" file
<If "! -R '<my_ip>'">
Require all denied
</If>

.htaccess: ??/index.php --> ??/, built on a relative path

Remove indx.php from URL; always redirect ??/ from ??/index.php
...including subdirectories, which may have their own .htaccess and index.php.
I'm using Apache with .htaccess.
I have a webapp with index.php in a subdirectory of the domain, say here:
example.tld/somedir/
But, it could be installed to any directory, such as these...
example.tld/anotherdir/
sub.domain.tld/
another.tld/
Each has its own index.php and its own .htaccess, for our purposes
On example.tld/somedir/: example.tld/, sub.example.tld/, et cetera also have their separate index.php and .htaccess, for their separate purposes
I need this to still work if placed in a subdir example.tld/dir/ of a WordPress or October or SuitCRM installation at example.tld/.
Always hide index.php via .htaccess
I want to make sure that:
All above four / (root) addresses link to index.php in whatever same directory.
index.php always redirects to / (root)
Examples
example.tld/anotherdir/index.php -> example.tld/anotherdir/
sub.domain.tld/index.php -> sub.domain.tld/
another.tld/index.php -> another.tld/
I need something like this
RewriteRule ^.*$ /{$PWD}/index.php [L,QSA]
...and any Rewrite statements that must precede it.
These Questions do not provide an answer:
htaccess redirect index.php to root (including subdomains)
This does not address subdirectories, only subdomains
This redirects example.tld/dir/index.php to example.tld/, but I need example.tld/dir/
htaccess remove index.php from url
This only removes indx.php from example.com/index.php/dir/subdir
This does not remove index.php from example.com/dir/index.php like I need
.Htaccess redirect index.php
This never got a working Answer
This redirects example.tld/dir/index.php to example.tld/, but I need example.tld/dir/
Redirect to index.php of .htaccess dir
This requires to specify /dir/, which I can't do.
This redirects example.tld/dir/index.php to example.tld/, but I need example.tld/dir/
The Answers don't work for the OP.
htaccess remove index.php and index.php/
This removes subdirectories from the URL also.
Redirect all to index.php using htaccess
This also requires to specify /dir/ in example.tld/dir/index.php
Answer is: RewriteRule ^.*$ /mvc/index.php [L,QSA], which I can't use.
.htaccess - simple redirect: index (with no extension!) / index.html / index.php to root
Does not address subdirectories, which I need.
Removing index.php from URLS with .htaccess
This redirects example.tld/dir/index.php to example.tld/, but I need example.tld/dir/
To serve index.php from the requested directory you use mod_dir's DirectoryIndex directive (which is probably already set in the server config, although defaults to index.html only) - you do not need mod_rewrite for this. For example:
# Serve "index.php" from the requested directory
DirectoryIndex index.php
This instructs Apache to serve index.php from whatever directory is requested. eg. Request /foo/bar/ then /foo/bar/index.php is served via an internal subrequest (no redirect). If index.php is not present in that directory you'll get a 403 Forbidden response (assuming directory listings - as generated by mod_autoindex - are disabled).
To remove index.php from any URL that is requested directly you can use mod_rewrite. For example:
RewriteEngine On
# Remove "index.php" from any URL and redirect back to the "directory"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.+/)?index\.php(/|$) /$1 [R=301,L]
The above will redirect as follows, preserving the requested protocol and hostname:
/index.php to /
/foo/index.php to /foo/
/foo/bar/index.php to /foo/bar/
/fooindex.php - NO REDIRECT (404 expected)
/foo/index.php/bar (containing path-info) to /foo/ (path-info removed)
/foo/index.phpbar - NO REDIRECT (404 expected)
The (optional) capturing group (.*/)? contains the part of the URL-path before index.php. This is then available in the substitution string using the $1 backreference. In the case when /index.php is requested in the document root, this is empty. When a subdirectory is present then this contains a string of the form subdir/, including the trailing slash.
If you have no other directives in your .htaccess file then you don't strictly need the condition that checks against the REDIRECT_STATUS environment variable. This condition ensures that only direct requests are redirected in the case when you have a front-controller pattern later in the file that might rewrite requests to index.php.
If you do have other directives in the file then the order can be important. This rule that removes index.php via an external redirect must go before any existing rewrites, near the top of the file.
Note that this removes index.php from the URL regardless of whether the requested URL actually maps to a real file or whether the preceding URL-path even exists as a physical directory. So, /<something>/index.php is redirected to /<something>/ regardless of whether /<something>/ is a physical directory or not. This check can be implemented at the cost of an additional filesystem check - but it's probably not required.
NB: Test first with a 302 (temporary) redirect to avoid potential caching issues. Only change to a 301 (permanent) redirect once you have tested that it works as intended.
UPDATE#1:
These Questions do not provide an answer:
htaccess redirect index.php to root (including subdomains)
This does not address subdirectories, only subdomains
This redirects example.tld/dir/index.php to example.tld/, but I need example.tld/dir/
Actually, the first question you've linked to does answer your question, with regards to removing index.php from the requested URL. It does address subdirectories and would redirect example.tld/dir/index.php to example.tld/dir/ (not example.tld/ as you've stated).
The part of the question that discusses subdomains is a bit misleading as it doesn't really have anything to do with subdomains specifically.
The solution presented in the linked question basically does the same sort of thing as I've done above, except that it arguably matches too much (and not enough). It would incorrectly/unnecessarily redirect /fooindex.php to /foo (no trailing slash) and would fail to redirect URLs that contained path-info (which could be malicious). eg. /foo/index.php/bar would fail to redirect but still serve the contents of /foo/index.php (unless AcceptPathInfo had been disabled). Although whether these "errors" would actually cause an issue in your case is another matter.
UPDATE#2:
I have the code exactly in the directory for example.tld/dir
The code above assumes the .htaccess file is located in the document root. If the .htaccess file is located in the directory of where the app is installed then you would need to modify the above like so:
# Remove "index.php" from any URL and redirect back to the "directory"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} ^/(.+/)?index\.php
RewriteRule (^|/)index\.php(/|$) /%1 [R=301,L]
The %1 backreference (as opposed to $1) refers to the captured group in the preceding CondPattern. This naturally includes the full URL-path, so avoids having to hardcode the directory in which the .htaccess file is located.
This applies to the directory that contains the .htaccess file and any subdirectories thereof. Note that, by default, this completely overrides any mod_rewrite directives that might be present in the parent .htaccess file (mod_rewrite directives are not inherited by default).
...including subdirectories, which may have their own .htaccess and index.php.
If additional sub-subdirectories have their own .htaccess file then this may or may not work depending on the directives used in these sub-subdirectory .htaccess files and/or how mod_rewrite inheritance is configured.
mod_rewrite directives do not inherit by default. So, if the .htaccess file in the sub-subdirectory enables the rewrite engine then the above mod_rewrite directives in the parent directory will be completely overridden (they are not even processed).
If, on the other hand, the .htaccess file in the sub-subdirectory uses directives from other modules then this may not be an issue.

.htaccess need help to serve requests to index.php in non root folder

I have a specific website structure:
root:
styles.css
pages/index.html
folder_with_assets_1
folder_with_assets_2
folder_with_images
I've renamed index.html to index.php in order to get rid of .html extension in the URL
But the problem is that index.php is located not in a root folder, it's in pages folder.
Which right .htaccess rules could solve the problem in order to redirect requests to pages folder?
UPDATE
the screenshot with folder structure:
On the face of it, this just looks a standard front-controller pattern. Whether the front-controller is located inside a subdirectory or directly in the document root is largely irrelevant - the process is the same.
Assuming you are using the .htaccess file in the document root and there is no discernable pattern to the page URLs...
For example, using mod_dir FallbackResource:
FallbackResource /pages/index.php
Or, using mod_rewrite:
DirectoryIndex /pages/index.php
RewriteEngine On
RewriteRule (^|/)index\.php - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . pages/index.php [L]
UPDATE#1:
It's "onepage" website format with plenty of JS and CSS. There are only local URLs pointing to sections (href tag) and AJAX call to specific PHP files
In that case, it just looks like you need to change the DirectoryIndex - you don't need a front-controller pattern (as discussed above) at all.
For example:
DirectoryIndex /pages/index.php
Now, a request for the "homepage", ie the document root https://example.com/ will serve /pages/index.php.
UPDATE#2:
From your screenshot, it looks like directory listings (mod_autoindex) are enabled. These should be disabled at the top of the .htaccess file:
Options -Indexes
UPDATE#3:
From your screenshot, it would seem that what you have called "root" in your file structure is not actually your website's "document root", since you are accessing this location via a /test subdirectory, ie. localhost/test/. The directives above are assuming these files are located in the "document root", ie. localhost/ and there is no /test subdirectory. (Which I expect is how it is structured on your "live" environment?)
If your .htaccess file is located in the /test subdirectory and you are requesting localhost/test/ (as per your screenshot) then you will need to adjust this accordingly:
For example:
DirectoryIndex /test/pages/index.php
However, that will not work on the live site (assuming you don't have a /test subdirectory on live). Instead, you can simply omit the slash prefix, to make it relative.
For example:
DirectoryIndex pages/index.php
This should work OK in your case since you have a SPA (just a homepage URL).

Can htaccess prevent all access to unwanted files?

I'm building something that I want to release as an open source project. To make it easier to use I'd like to go without the public-folder approach, where you hide all other files than index.php (and assets) from public_html. Meaning, I'd like to do it like WordPress, where you simply toss the code on a server and it works, in that URL you tossed it in.
Here is the content of my htaccess-file:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
</IfModule>
Does this code really prevent access to other files? For example, is there any way an attacker could access vendor/Acme/Libraries/Foo.php? Based on my tests it does, but that doesn't mean there isn't a way to circumvent it.
Let's look at your rule closely:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
Here this rule is saying that if request is NOT for a valid file then rewrite it to /index.php. Which means /index.php will be invoked for any non-file requests but that also means you are allowing direct access to all the files.
btw QSA is useless here and can be removed.
You cited Wordpress here. Which basically uses /index.php for any non-file, non-directory requests thus allowing direct access to any valid file OR directory.
If you really want to block access to all the files and directories then you probably will need this rule:
RewriteRule ^ index.php [L]
but I am not sure if you want to handle direct access to resources like images, js/css files via index.php also.
Yes, an attacker can still access your other code files, using only the rule you provided. But:
On a properly configured server, a call to vendor/Acme/Libraries/Foo.php would execute that file, not display its contents. Which might or might not be good enough, and there's still the possibility of a configuration error that would display the source code.
You can block web access to the remaining files by adding Deny directives, for example:
<Location />
Order deny,allow
Deny from all
<Files index.php>
Allow from all
</Files>
</Location>

Subdomain mod_rewrite (htaccess) to relative directory

I am having a bit of trouble rewriting sub-domains to directories that reside above the web root. I have had plenty of experience with mod_rewrite before, but this particular problem is beyond me.
From what I can tell, mod_rewrite is throwing a tantrum because I insist on using relative directories (..) to determine the directory in which the sub-domain files are located.
Unfortunately, there are two restrictions from my client's specifications:
Putting the sub-domain as a sub-directory of the web root is not an option. The sub-domain must not be accessible from anywhere except the specific sub-domain (there are likely to be directory clashes).
This means http://subdomain.example.com/ must not be accessible from http://example.com/subdomain/ as that directory may be used in the application on the root domain.
An absolute path to the sub-domain files is not known to the client as shared hosting will be used.
If anyone could help me with this problem it would be greatly appreciated! I'd love to start using this in future projects as well, it's quite an elegant solution compared to how we currently deal with sub-domains... If anyone can get it working that is!
Edit: Thought it might be useful to point out that on requesting http://subdomain.example.com/ a 400 Bad Request is returned, rather than a 500 Internal Server Error that I expected. Everything works as expected when requesting the root domain.
Current .htaccess file.
# Begin Rewrite Module for http://*.example.com/
# ==============================================
<IfModule mod_rewrite.c>
# Turn the rewrite engine on.
RewriteEngine On
RewriteBase /
# Map subdomains to their respective directories.
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$
RewriteRule (.*) /../public_subdomains/%1/$1 [L]
# Rewrite all requests for the root domain to always be served through "index.php".
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /index.php/$1 [L]
</IfModule>
Current directory structure.
/
application/
cgi-bin/
framework/
public_html
public/
css/
images/
js/
.htaccess
index.php
public_subdomains/
mysubdomain/
index.php
anothersubdomain/
index.php
How you implement this depends on how your host implements subdomains. Some simply map onto your DOCROOT. Others provide a control panel to allow you to do that subdomain -> subdomain docroot yourself. If (2) applies then what you want is already provided, so I'll assume (1) in this ans.
First point to note is that rewriting in an htaccess per-directory context is really URI mapping botched onto the DOCROOT hierarchy. ".." is not allowed and will throw a 500. In practice your are stuck within the domain's DOCROOT.
So public_domains must be a sub directory of DOCROOT -- in your case public_html.
However, you can still simply prevent any direct access to public_html/public_domains by a simple rule:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} /public_domains(/|$)
RewriteRule ^ - [F,L]
See my Tips for debugging .htaccess rewrite rules for more hints. You only want to barf on requests with public_domains on the entry pass. Also remember that you don't include the leading / and targets are relative to DOCROOT for a base of /.

Resources