1

I'm working with Apache and want to use .htaccess to achieve the following:

  • Rewrite /api/get to get.php
  • Rewrite /api/report to report.php
  • Only allow access to these URLs/scripts

Essentially, I want to allow only these two specific endpoints (/api/get and /api/report), and prevent access to anything else.

What ive tried:

RewriteEngine on RewriteRule ^api/get$ /get.php [L] RewriteRule ^api/report$ /report.php [L] Order deny,allow Deny from all <Files "get.php"> Allow from all </Files> <Files "report.php"> Allow from all </Files> 

Resulting in access being denied to everything except /get.php and /report.php

RewriteEngine on RewriteRule ^api/get$ /get.php [L] RewriteRule ^api/report$ /report.php [L] RewriteRule ^ - [F] 

Leading to complete access denial

2
  • 1
    The [OR] in your second attempt makes little sense. You request /api/get, so the first condition does not match, but the second one does - and so the following rule applies. Commented Oct 16, 2024 at 13:30
  • 1
    It would be helpful if you state what happens in your 3 "attempts". Commented Oct 16, 2024 at 17:28

1 Answer 1

1

You can do it like this on Apache 2.4:

RewriteEngine on # Rewrite requests to "/api/get" and "/api/report" RewriteRule ^api/(get|report)$ $1.php [END] # Block everything else, including direct requests to "/get.php" and "/report.php" RewriteRule ^ - [F] 

Note the use of the END flag (as opposed to L) on the first rule (requires Apache 2.4+). This prevents any further rules being processed (for the request) should this rule be met. (An L flag simply prevents additional rules being processed during the current pass only by the rewrite engine.)

The $1 backreference contains either get or report as captured from the initial request URL. This allows your two rules to be easily combined.

No need for the slash-prefix on the RewriteRule substitution (2nd argument) in the above rule. This ensures we rewrite directly to a file-path, as opposed to a URL-path (although it would get there in the end).


Aside:

RewriteRule ^api/get$ /get.php [L] RewriteRule ^api/report$ /report.php [L] RewriteRule ^ - [F] 

This is close, but without an additional condition on the last rule, the use of the L flag on the first two rules would result in all requests being blocked.

If on Apache 2.2, this could be written like this, making use of the REDIRECT_STATUS environment variable:

RewriteRule ^api/get$ /get.php [L] RewriteRule ^api/report$ /report.php [L] RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteRule ^ - [F] 

The use of the REDIRECT_STATUS env var ensures that only direct requests (from the client) are processed (ie. blocked) and not rewritten requests by the previous two rules. On the initial pass by the rewrite engine, the REDIRECT_STATUS var is empty, but after the first successful internal rewrite it is set to 200 (as in a 200 OK HTTP status).

RewriteCond %{REQUEST_URI} !^/api/get$ [OR] RewriteCond %{REQUEST_URI} !^/api/report$ RewriteRule ^ - [F] RewriteRule ^api/get$ get.php [L] RewriteRule ^api/report$ report.php [L] 

As mentioned in comments, the logic is incorrect on the first rule. If you OR two negated mutually exclusive expressions the result will always be true and the request is always blocked.

However, the request would still be blocked for the same reason as mentioned above.

Sign up to request clarification or add additional context in comments.

1 Comment

This worked for me, thank you. I appreciate the detailed explanation; it makes a lot more sense now

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.