How to tell .htaccess to only allow requests to index.php and app/dist/* folder?
If this is your main problem: "I have sensitive data everywhere"
That is solved the easiest and most reliably by moving that sensitive to somewhere outside of your web root...
Consider a web root (your DocumentRoot
) that only contains the index.php
When there is no other data in there you don't need any complex rules to protect it either...
You can then use for instance the Alias
directive (in preferably your main server configuration file, or if you prefer a .htaccess
file in your web root) or mod_rewrite rules to map URI's to documents stored in directories outside of your DocumentRoot directories/files to specifically allow access.
i.e.
.
`-- some-path
|-- app
| `-- dist
| |-- index.css
| |-- index.html
| `-- index.js
|-- src
| `-- configurations.json
`-- www.example.com
|-- .htaccess
`-- index.php
Where your main apache configuration defines /some-path/www.example.com
as the DocumentRoot
for www.example.com.
The .htaccess
can then be something such as this exposes the /some-path/app/ directory and all its contents as the URI path http://www.example.com/app/
# /some-path/www.example.com/.htaccess
# exposes/some-path/app/ directory as the URI path `http://www.example.com/app/`
Alias "/app" "/some-path/app"
Or be more specific with Alias "/app/dist" "/some-path/app/dist"
or creative with a regex in an AlaisMatch
directive.
The <Files>
and <FilesMatch>
directives only target files, not directories. If you have access to the server config then you'd perhaps use a <Directory>
container.
Using mod_rewrite
In .htaccess
you can use mod_rewrite to restrict access to anything other than /index.php
or /app/dist/
.
For example:
RewriteEngine On
RewriteRule !^(index\.php$|app/dist/) - [F]
The above will respond with a 403 Forbidden for any request that is not /index.php
or does not start /app/dist/
. If you wish to return a 404 instead then change F
to R=404
.
The !
prefix on the regex negates the regex. Note that the URL-path matched by the RewriteRule
pattern does not start with a slash.
If you only want to respond with a 403 for requests that would map to actual files or directories (and 404 otherwise) then add a couple of conditions that check the filesystem (but note that filesystem checks are relatively expensive, so unless you need them, don't use them). For example:
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule !^(index\.php$|app/dist/) - [F]
Only if the requested URL is not in the allowed "group" and maps to a file or directory is the RewriteRule
directive actioned.
However, I would assume your URLs don't actually contain index.php
(do they?), in which case the user requests /
and mod_dir issues an internal subrequest for /index.php
(the DirectoryIndex
). In which case, you'll need to make the index.php
optional.
For example:
RewriteRule !^((index\.php)?$|app/dist/) - [F]
Using an Apache Expression
Alternatively, you can do this with an Apache expression (Apache 2.4)
<If "%{REQUEST_URI} !~ m#^/((index\.php)?$|app/dist/)#">
Require all denied
</If>
The above responds with a 403 for any URL request that is not /
, /index.php
or start with /app/dist/
.
Note that Order
, Allow
, Deny
, etc. are older Apache 2.2 directives and are officially deprecated on Apache 2.4.
Using mod_setenvif
Another alternative is to use mod_setenvif and set an environment variable if one of the permitted URL-paths is requested and only permit access if this env var is set.
For example:
SetEnvIf Request_URI "^/((index\.php)?$|app/dist/)" ALLOWED
Require env ALLOWED
The above sets the ALLOWED
env var if the any of the permitted URL-paths are requested. The Require
directive then requires this env var to be set to grant access, otherwise a 403 is returned.