I have a primarily Ajax-driven site, the content of which is populated by making requests to an "operator" PHP script.
While typically these requests originate in Javascript, there are occasions when it's useful to query my operator from within another PHP script.
The method I have been using is to pass a URL with query string through file_get_contents() — and then to parse the returned JSON with json_decode().
For multiple reasons, I'd like to avoid this implementation, though... I see in my error logs that the URL requests are a lot more susceptible to failure for whatever reason — and I've read that it's not very efficient.
My 1st attempt to make a generic query_operator($query_string)-type function simply require()-ed operator.php within an output buffer, captured with ob_get_contents(). I also temporarily reset the $_REQUEST array with parameters parsed from the $query_string.
This approach had too many shortcomings — problems with variable scope and the MySQL connection, specifically.
My 2nd attempt involved using the backtick operator (equivalent to shell_exec()), and mapping the $argv arguments to the $_REQUEST array.
This approach actually works very well, but on the host I'm using, the PHP (cli) version is set a 4.4.8 — and I need 5.2.x. Assuming I can't switch the (cli) version, what's the next best way to sandbox a request to another PHP script, with a query string? Any suggestions greatly appreciated.
Here's what my 2nd attempt looks like:
function query_operator($query) {
$query = '--'.str_ireplace('&', ' --', $query);
$contents = `php operator.php $query`;
if ($json = json_decode($contents, true)) {
return $json;
} else {
return $contents;
}
}
The best thing to do, in the long run, is to factor your code.
Whatever logic operator.php is doing that is needed should live in some library, which can then be used by operator.php and any other script that needs it.
When you do that, you'll avoid all the overhead of an extra PHP process, communication between two processes, and probably all your json-encoding/decoding.
If factoring is too much work to take on now, either of the strategies you describe should work as a kludge. It might be worth looking into why your make-a-loopback-http-request method (the first thing you described) caused errors. It really ought to work well, even if it's inefficient.
Related
I am keeping record of every request made to my website. I am very aware of the security measurements that need to be taken before executing any MySQL query that contains data coming from query strings. I clean it as much as possible from injections and so far all tests have been successful using:
htmlspecialchars, strip_tags, mysqli_real_escape_string.
But on the logs of pages visited I find query strings of failed hack attempts that contain a lot of php code:
?1=%40ini_set%28"display_errors"%2C"0"%29%3B%40set_time_limit%280%29%3B%40set_magic_quotes_runtime%280%29%3Becho%20%27->%7C%27%3Bfile_put_contents%28%24_SERVER%5B%27DOCUMENT_ROOT%27%5D.%27/webconfig.txt.php%27%2Cbase64_decode%28%27PD9waHAgZXZhb
In the previous example we can see:
display_errors, set_time_limit, set_magic_quotes_runtime, file_put_contents
Another example:
/?s=/index/%5Cthink%5Capp/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=ctlpy.php&vars[1][]=<?php #assert($_REQUEST["ysy"]);?>ysydjsjxbei37$
This one is worst, there is even some <?php and $_REQUEST["ysy"] stuff in there. Although I am able to sanitize it, strip tags and encode < or > when I decode the string I can see the type of requests that are being sent.
Is there any way to detect a string that contains php code like:
filter_var($var, FILTER_SANITIZE_PHP);
FYI: This is not a real function, I am trying to give an idea of what I am looking for.
or some sort of function:
function findCode($var){
return ($var contains PHP) ? true : false
}
Again, not real
No need to sanitize, that has been taken care of, just to detect PHP code in a string. I need this because I want to detect them and save them in other logs.
NOTE: NEVER EXECUTE OR EVAL CODE COMING FROM QUERY STRINGS
After reading lots of comments #KIKO Software came up with an ingenious idea by using PHP tokenizer, but it ended up being extremely difficult because the string that is to be analyzed needed to have almost prefect syntax or it would fail.
So the best solution that I came up with is a simple function that tries to find commonly used PHP statements, In my case, especially on query strings with code injection. Another advantage of this solution is that we can modify and add to the list as many PHP statements as we want. Keep in mind that making the list bigger will considerably slow down your script. this functions uses strpos instead of preg_match (regex ) as its proven to perform faster.
This will not find 100% PHP code inside a string, but you can customize it to find as much as is required, never include terms that could be used in regular English, like 'echo' or 'if'
function findInStr($string, $findarray){
$found=false;
for($i=0;$i<sizeof($findarray);$i++){
$res=strpos($string,$findarray[$i]);
if($res !== false){
$found=true;
break;
}
}
return $found;
}
Simply use:
$search_line=array(
'file_put_contents',
'<?=',
'<?php',
'?>',
'eval(',
'$_REQUEST',
'$_POST',
'$_GET',
'$_SESSION',
'$_SERVER',
'exec(',
'shell_exec(',
'invokefunction',
'call_user_func_array',
'display_errors',
'ini_set',
'set_time_limit',
'set_magic_quotes_runtime',
'DOCUMENT_ROOT',
'include(',
'include_once(',
'require(',
'require_once(',
'base64_decode',
'file_get_contents',
'sizeof',
'array('
);
if(findInStr("this has some <?php echo 'PHP CODE' ?>",$search_line)){
echo "PHP found";
}
I do not have control over the code I'm executing. This is a third party function, but not user-entered. These are things that are versioned so it is impractical that I poke there and change all die()'s into something more sane. Because a new version is coming from time to time and then I could paradoxically make the code even more insecure by trying mess with it poor error handling.
so let's say we have a function:
fuction myfunc() {
// lot's of complicated code
if (!is_file('myfile.txt') exit('file not found');
// and so on
}
What I'm trying to do is to somewhat run that piece of code and return to my main thread and then act accordingly with that error.
I've tried die() or eval() but this returns the whole script.
Bummer ?
A Hail Mary approach is to use runkit's runkit_function_redefine or function_override to redefine the functions die and exit to throw an Exception instead.
A potential problem is that the 3rd party can catch those exceptions and might not deal with them correctly. It's also very likely that you can't properly deal with the exception either.
You can use register_shutdown_function to run code after exit has been called. You are somewhat limited in what you can do at this point as some services have already been shut down (such as autoloading). I think you can still output content, not sure about sessions and other headers.
Another approach would be to run the code in a seperate php process (or http request), for instance by calling php through exec.
A more solid approach can be to add predicitions to your own code, ensuring the bad states are never reached when calling the 3rd party code. It is possible that not all preconditions can be met.
Ideally only code that is an entry point (like a router script) may exit. Using exit anywhere else is just shoddy programming really.
If you have not read Halcyon's answer, you should have a look at it first.
Since you mention eval(), I assume you have the code as a string. I will refer to both die() and exit() by just the latter, but things should be relevant for both.
You can try and replace occurrences of die() and exit() with something, and then eval. It's simple but that can be very messy.
One thing to look out for, IF you decide to do this, is that you may end up replacing occurrences which are not really 'code'. For example, echo "Let him exit()";.
Also, when you consider possible equivalent syntax, like exit (); , exit; or exit(1);, it gets much more unpleasant. You'll have to handle those with a regex.
But if you can safely assume that
those two signatures (die() and exit()) are the only ones you need to worry about; and
that strings (or other content) are not going to contain those 'phrases'
then you can use this approach.
I could not find the reason why my request fail for the following
My php code is:
if (isset($_COOKIE["user"])) {
echo '<p><h3><strong>Welcome '.$_COOKIE["param"].'</strong></h3></p>'; .....
When i request exec('ls -al') as param , the php code did not run the command.
On the response of the request it was like parameterized:
Welcome exec('ls -al')
What may the reason that failed this execution?
$_COOKIE["param"] is a string. You are echoing it. It is not supposed to run anything.
If you wanted to run a command in your PHP, you would have to use eval(). But as for running a command from a cookie value:
DON'T DO IT!
So you're saying that the value of $_COOKIE['param'] is exec('ls -al'), and you're expecting that to run when you echo it out?
That's not how it works. The value of that cookie will be the string value "exec('ls -al')", not the result of the executed code. If you think about it for a second, you'll understand why it would be a bad idea for a cookie to be able to auto-execute code.
It's not really a great idea to be running random commands through exec() anyway, especially if that input came from a user (which cookies do - the user can and will change them to try to attack you).
Instead, you should be using other input that your code can interpret as a signal to run certain code. For example, you could have the param value hold the string list files, and your code would see that value and run exec('ls -al') for you.
You still shouldn't be execing code to do this though, since it's very easy to accidentally run dangerous commands that way. Instead, you should use PHP's built-in functions as much as possible, and only after sanitizing your inputs and only running known values.
For your case, PHP has a bunch of functions that let you interact with the filesystem of your server. Use those to get a list of files on the system instead.
i would like to know if there is a possible injection of code (or any other security risk like reading memory blocks that you weren't supposed to etc...) in the following scenario, where unsanitized data from HTTP GET is used in code of PHP as KEY of array.
This supposed to transform letters to their order in alphabet. a to 1, b to 2, c to 3 .... HTTP GET "letter" variable supposed to have values letters, but as you can understand anything can be send to server:
HTML:
http://www.example.com/index.php?letter=[anything in here, as dirty it can gets]
PHP:
$dirty_data = $_GET['letter'];
echo "Your letter's order in alphabet is:".Letter2Number($dirty_data);
function Letter2Number($my_array_key)
{
$alphabet = array("a" => "1", "b" => "2", "c" => "3");
// And now we will eventually use HTTP GET unsanitized data
// as a KEY for a PHP array... Yikes!
return $alphabet[$my_array_key];
}
Questions:
Do you see any security risks?
How can i sanitize HTTP data to be able use them in code as KEY of an array?
How bad is this practice?
I can't see any problems with this practice. Anything you... errr... get from $_GET is a string. It will not pose any security threat whatsoever unless you call eval() on it. Any string can be used as a PHP array key, and it will have no adverse effects whatsoever (although if you use a really long string, obviously this will impact memory usage).
It's not like SQL, where you are building code to be executed later - your PHP code has already been built and is executing, and the only way you can modify the way in which it executes at runtime is by calling eval() or include()/require().
EDIT
Thinking about it there are a couple of other ways, apart from eval() and include(), that this input could affect the operation of the script, and that is to use the supplied string to dynamically call a function/method, instantiate an object, or in variable variables/properties. So for example:
$userdata = $_GET['userdata'];
$userdata();
// ...or...
$obj->$userdata();
// ...or...
$obj = new $userdata();
// ...or...
$someval = ${'a_var_called_'.$userdata};
// ...or...
$someval = $obj->$userdata;
...would be a very bad idea, if you were to do it with sanitizing $userdata first.
However, for what you are doing, you do not need to worry about it.
Any external received from GET, POST, FILE, etc. should be treated as filthy and sanitized appropriately. How and when you sanitize depends on when the data is going to be used. If you are going to store it to the DB, it needs to be escaped (to avoid SQL Injection. See PDO for example). Escaping is also necessary when running an OS command based on user data such as eval or attempting to read a file (like reading ../../../etc/passwd). If it's going to be displayed back to the user, it needs to be encoded (to avoid html injection. See htmlspecialchars for example).
You don't have to sanitize data for the way you are using it above. In fact, you should only escape for storage and encode for display, but otherwise leave data raw. Of course, you may want to perform your own validation on the data. For example, you may want dirty_data to be in the list of [a, b, c] and if not echo it back to the user. Then you would have to encode it.
Any well-known OS is not going to have a problem even if the user managed to attempt to read an invalid memory address.
Presumably this array's contents are meant to be publicly accessible in this way, so no.
Run it through array_key_exists()
Probably at least a little bad. Maybe there's something that could be done with a malformed multibyte string or something that could trigger some kind of overflow on a poorly-configured server... but that's pure (ignorant) speculation on my part.
I'm used to the habit of checking the type of my parameters when writing functions. Is there a reason for or against this? As an example, would it be good practice to keep the string verification in this code or remove it, and why?
function rmstr($string, $remove) {
if (is_string($string) && is_string($remove)) {
return str_replace($remove, '', $string);
}
return '';
}
rmstr('some text', 'text');
There are times when you may expect different parameter types and run different code for them, in which case the verification is essential, but my question is if we should explicitly check for a type and avoid an error.
Yes, it's fine. However, php is not strongly typed to begin with, so I think this is not very useful in practice.
Additionally, if one uses an object other than string, an exception is a more informative; therefore, I'd try to avoid just returning an empty string at the end, because it's not semantically explaining that calling rmstr(array, object) returns an empty string.
My opinion is that you should perform such verification if you are accepting input from the user. If those strings were not accepted from the user or are sanitized input from the user, then doing verification there is excessive.
As for me, type checking actual to data, getted from user on top level of abstraction, but after that, when You call most of your functions you already should now their type, and don't check it out in every method. It affects performance and readability.
Note: you can add info, which types is allowed to arguments for your functions by phpDoc
It seems local folks understood this question as "Should you verify parameters" where it was "Should you verify parameter types", and made nonsense answers and comments out of it.
Personally I am never checking operand types and never experienced any trouble of it.
It depends which code you produce. If it's actually production code, you should ensure that your function is working properly under any circumstances. This includes checking that parameters contain the data you expect. Otherwise throw an exception or have another form of error handling (which your example is totally missing).
If it's not for production use and you don't need to code defensively, you can ignore anything and follow the garbage-in-garbage-out principle (or the three shit principle: code shit, process shit, get shit).
In the end it is all about matching expectations: If you don't need your function to work properly, you don't need to code it properly. If you are actually relying on your code to work precisely, you even need to validate input data per each unit (function, class).