4

Does the use of mod_rewrite make PHP array injection (web parameter key tampering) impossible when the keys are unknown (and hard to guess)?

Let's say we have the following URL:

https://example.com/product.php?id=1&action=show

example.com decided to rewrite there URLs to a prettier version like:

https://example.com/product/1

Therefor they use the following RewriteRule:

RewriteRule ^/product/(.*)$ /product.php?id=$1&action=show [L]

Now the keys are id and action and those values are 1 and show. I understand the values will be rewrited, no protection is involved anyhow. Injections are still possible and so on. But the keys cannot be changed assuming they are unknown. In this example I used the guessable keys id and action but they could as well be two completely long and random keys.

Now my question is about the keys. I could inject one or multiple [] in the parameter to make that the value of that id an PHP array instead of string. Like this:

https://example.com/product.php?id[]=1&action=show

For a rewrited URL their is no way to do so unless you know the key. Am I right? In this example the following will still be possible because they key is easy to guess. The below example the URL will know have the key id two times and use the last one with the injected [].

https://example.com/product/1?id[]=1

But assuming the keys were not known and easy to guess. Let's say:

RewriteRule ^/product/(.*)$ /product.php?7b8d164d7820713ef5be524d2bde7828999c78d6=$1&28c4abba80b7a2038328e54a81f51367ead9172a=show [L]

I suppose that then there is no way to inject [] without knowing the keys.

Additionally, when you check the current URL in your PHP script for the characters ? and & you can prevent bypasses like https://example.com/product/1?id[]=1. In my opinion then array injection or altering the key is not possible anymore just the value can be changed. Right?

1
+50

It will obfuscate the actual location of the script, but on it's own there is nothing preventing an attacker from guessing/dirbustings/etc the product.php file and accessing it directly. The attacker would have to then identify the correct parameter names (id & action). Once the attacker is accessing the file directly the rewrite rule does not apply.

So you could potentially raise the minimum effort required to attack your script, however you would need may rewrite rules and they are not very performance friendly so you could be introducing a denial of service condition in the process.

  • Good answer! But, I'm aware of finding the file and params and so bypassing the RewriteRule with a direct request. This raised the off-topic question: is it a good idea to disallow a non-rewrited url in the accepted requests? Anyway, in case the parameter is not that simple as shown in the last example, then direct access is unlikely when the parameters are not used in the front-end source code but just in the back-end and RewriteRule. So without knowing the actual parameter, injections like ?key[]=value won't be possible right? Cause the key is unknown and hard to guess. Right? – Bob Ortiz Jul 14 '16 at 14:25
  • 4
    I'm just going to hazard a guess that you're trying to solve the wrong problem. I setup a local php file with var_dump($_GET) and your rewrite rule. Then I accessed it with http://localhost/product/123?id[]=123 and id was an array. Making the parameter name difficult to guess would help, but depending on your code it may be possible to append ?junk[]=junk and trigger the same behaviour. It would be far better to use input validation to ensure that the id (and other parameters) are in fact the data type you expect with is_numeric or a similar function. – wireghoul Jul 14 '16 at 23:01
  • I like your last comment here, with the results of a test. Can you please add them in the answer itself? – Bob Ortiz Aug 3 '16 at 10:51
0

Good way to approach it is to sanitize user input in dedicated PHP method shortly after request is invoked.

This has several advantages:

  • You are always sure that only right formatted arguments are submitted, e.g. ints are ints and strings are strings without anything unusual
  • That the correct number of arguments is passed so for example there's no way to add another argument and make script do something else

If you can match two of the above, you would likely be able to remove some existing bugs like passing incomplete list of arguments and not properly initializing variables.

This gives you better structural approach to you PHP code and really the mandatory input validation.

The input validation is normally done by standard methods, however before routing request it's good to have one place to sanitize them - this is good and valid method because what is important to sanitize input before multiple other methods are called.

So this way the best is to always call one controller method, and check if all arguments are matching (existing) and are of the required types (in the controller method which mainly does checking and after that just calling some other service), for example (it's just semi-code for showing the logic in the controller):

//router
if($_GET['action'] === 'showItem') {
    showItemController();
}

//controller
function showItemController() {
    try {
        $id = $_GET['id'];
        if(!isint($id)) {
           throw new Exception("id '{$id} is wrong");
        }
        $output = showItem($id);
        render($output);
    } catch(Exception $e) {
      logError($e);
      displayGenericFail();
    }
}

//service
function service($id) {
    $item = new Item($id);
    return $item->getHtml();
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.