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.