I am currently displaying errors on my website using this code:
<?php
$failure = strip_tags($_GET['failure']);
if($failure!=""){
echo '<div class="error">';
echo $failure;
echo '</div>';
}
?>
However, I am curious if this is safe. Is it?
while this solution would change a little bit your approach, why not have an errors.php file with this structure?
$error[1] = 'some error message';
$error[2] = 'some other error message';
$error[3] = '...'; // you get the point
And the just send an ID as the error:
somepage.php?failure=2
Then, include this code where you usually display your errors:
if($_GET['failure'] && array_key_exists($_GET['failure'],$error) {
echo $error[$_GET['failure']];
}
Just be sure to include errors.php in your config.php file (or whatever your main configuration's file name is).
Why?
Errors are often repeated, this way you can use them over and over again.
If you want to translate the site to another language, this system will be very helpful.
If you need to change a word on an error message, you will just have to change it once in the errors.php file.
IMHO it is much much safer to use ints than strings in this case.
You can (and of course always should, hat tip #DaveRandom) do a htmlspecialchars() after strip_tags in order to prevent some clever construction from getting past the tag stripper. I have never seen a working exploit doing that successfully but it can't hurt taking additional precautions.
If you do all that, this looks safe.
Note that there is a limit on the maximum size of a GET request - 1kb is a safe maximum amount.
Depending on what version of PHP you have, filter_input() is a decent alternative.
Related
this is my first time using PHP in a real project environment. The project is pretty simple, take an existing, working PHP site and update the HTML to be consistent with HTML5. After designing the HTML, I am inserting the PHP from the previous site. This works most of the time, but I get a few errors. For instance:
<?
$sec = $_GET['sec'];
if ($sec == "1") {
echo ('Success!');
}
?>
Is causing the error:
Notice: Undefined index: sec in /file_that_holds_site_build.
Of course that is only if the url doesn't include the append tag (=1) that alerts the message.
So the question is this, what am I missing that causes the $GET when there is no $sec? How do I eliminate this error on first page load?
You're getting that notice because you're trying to access an array index that doesn't exist in some scenarios. Here's how you should be getting the data out of the request.
$sec = array_key_exists('sec', $_GET) ? $_GET['sec'] : null;
Thanks to everyone who provided possible answers to this question. It was Daniel that came up with the easiest fix. Again, I am just adjusting someone else's code to work, so a universal solve would involve too much of my own writing. To the point, the final code looks like this:
<?
if (isset($_GET["sec"])){
$sec = $_GET['sec'];
if ($sec == "1") {
echo ('Success! Your username and password have been sent via email.');
}}
?>
Notice the added if statement. As I said in a comment to Daniel, SO SIMPLE!
Thanks again for everyone's help. I hope to be likewise of service to you all soon.
Simple just use isset($_GET['sec']) to check for the parameter 'sec' before using it in the php code. That should eliminate the error. This is quite trivial I suppose.
I often simply extract() the wohle $_GET super global and then either get the desired variable or not. As a kind of "declaration" I initialize each expected variable first with false. This way I find it much easier to handle than individually doing a check like if(isset($_GET['element'])) ...
$var1=$var2=$var3=false; // my desired variables
extract($_GET); // everything I get from the form
// or: extract($_REQUEST);
if ($var1) { /* do something with it */ }
Possible security risk:
Of course you should be aware that everybody could simply include their own variable as an argument to he page ...
What I am trying to do is change a variable in fileb from filea. Kind of like using fileb as a config file in a way.
Example:
File A:
require_once "fileb.php";
if($power == 'off') {
exit;
}
if($test1 == 'one') {
echo "The first option is selected";
} elseif($test1 == 'two') {
$power = 'off';
}
File B:
$power = 'on';
So in this example a user id prompted for $test1, if they reply with "one" they get a echo. What I want to do is make it so if they reply with "two" it shuts down the page, and not just for them but for everyone. I am trying to do all of this without using a DB, that would be too easy lol. Thanks for the help!
I am trying to do all of this without using a DB, that would be too easy
There's a reason using a database for this is easy. It's the correct way to accomplish this task. Modifying actual PHP code files is a famously bad idea. (And one that somebody on Stack Overflow has almost weekly, it seems.)
If you include the file as part of the executing code, you can use the variable as any other. This allows you to manipulate the variable in a transient way, but not manipulate the code which creates the variable.
What you're trying to do is persist that changed variable. In order to do that, it needs to be written somewhere outside of the application. Databases are really good for that sort of thing. You could also write to a simple text file (a string of text, structured XML, etc.) though in that case you'll have to manually watch out for concurrent writes and other such errors. (Databases are really good at that too, which makes them ideally suited for multi-thread/multi-user applications like web apps.)
I suppose you could treat the PHP file itself as an editable text file like any other. (Since PHP is, after all, just text.) But, again, that's a really bad idea. For one thing, parsing out exactly the value you want and writing back a change only to that value is going to be very difficult. Also, you run the risk of breaking a file which is treated as executable code which opens up all sorts of potential risks.
Just write to a database, or to a file, or to any other simple data persistence medium outside of the application.
Your fileb is lacking the <?php ... ?> tags. Without those, you "code" is never seen as code. it'll just be treated as plain text.
file b:
<?php
$power = 'on';
file c:
Hello
<?php
$foo = 'world!';
file a:
<?php
include('fileb.php');
echo $power;
include ('filec.php'); // "Hello" is immediately output
echo $foo; // tell PHP to put the $foo var, which will print out "world!"
Creating a rating system and the info is not being transmitted through my $_GET variable. The code is below
if (isset($_GET['item'], $_GET['rating'])){
echo 'Works!';
}
The variable is being entered in this code below
<?php echo number_format(
$article['rating'],1); ?>
<div class = "rate">
Rate:
<?php
for ($x =1; $x<= $maximum_rating; $x++){
?>
<a href="prestige.php?item=<?php echo $article['id']; ?>&rating=<?php echo $x;?>">
<?php echo $x; ?></a>
<?php
}
?>
I am fairly new to programming so any ideas or tips would be greatly appreciated.
There are a couple of things you should do.
1.
Instead of
prestige.php?item=<?php echo $article['id']; ?>&rating=<?php echo $x;?>
Use
prestige.php?<?= http_build_query(array('item' => $article['id'], 'rating' => $x), '&') ?>
This will escape the parameters. Vars $article['id'] and $x could contain characters that break the HTML or URL.
2.
Look at the Net tab in your Firebug/Chrome dev toolbar. Are there any redirects? What headers are sent?
Also look at the address bar to see if prestige.php really is loaded with the GET parameters.
3.
Use a debug tool like XDebug to step through your code. You might have some code that resets the $_GET vars. Personally I use the IDE PHPed, but it's kinda expensive.
The code you posted works. So the snag must be in the code you did not post:
maybe the prestige.php page has a PHP error that prevents it from displaying anything; start with an empty file containing just <?php echo 'OK so far'; ?>.
maybe the page contains code (security checks, frameworks...) that kills $_GET. (reduce the page to a minimum working case, without include/requires)
maybe the page does work, but the output gets snarked by an untimely ob_end_clean() that was meant to "clean the page" before the real output started; (reduce the page to a minimum working case)
maybe the page works, the string 'Works' is there, but you can't see it due to HTML markup, CSS, or other rendering problems (check the page source)
the URL might be broken because the item code contains invalid URL characters (check what appears in the browser address bar)
there might be an URL rewrite scheme that interferes (check .htaccess and the server logs)
I just remembered something like this happening with international characters in the URL. Try with an ASCII-clean item code to see what happens.
Just to be sure: verify there is no auto_prepend'ed file which might interfere.
Then, it might also be more than one of the above acting together. Often when debugging one unintentionally breaks some code, and even after fixing the first bug, the code doesn't start working again - this doesn't mean the fix was invalid.
I'm sorry -- I'm at the end of my options. I really look forward to knowing what the reason was. (Usually the more explanations I amass, the more the real answer tends to be "none of the above". When it happens to me, sometimes I wonder whether to start to believe in gremlins :-( ).
I am having a problem. I have this code:
$theUrl = $_GET["url"];
include("$theUrl.php");
This gets the url, for example: http://mywebsite.com/index.php?url=test
But what if someone puts in:
http://mywebsite.com/index.php?url=http://theirwebsite.com/someEvilscript
How to avoid this? I want only scripts that i have on my server to be executed and not from other websites. Thanks for help.
One of the good way to handle this is to define a white list of file that can be included. If anything isn't in that list, it should be considered evil and never included.
For example :
<?php
$allowed = array('file1', 'file2', 'file3');
if (in_array($_GET["url"], $allowed)) {
// You can include
} else {
// Error message and dont include
}
?>
Note : As suggested in the comment, the allowed list can be populated dynamically by scanning allowed directory.
You really shouldn't have any code that looks like that. And I mean really. What are you trying to achieve with this? I'm sure there's another way to the same without the risks (and let's say general uglyness).
Like HoLyVieR suggests, whitelisting what can be included is the key to making your current code safe.
Why don't you just create test.php on your site, and use http://mywebsite.com/test.php in the link? This way you can include your initialization script in test.php (and in the other scripts) if needed.
I want to make a programming environment. I will explain it with an example.
One programmer will write that code;
<html>
<head>
<?php definedMetaTags(); ?>
</head>
</body>
Programmer will save this file and then upload to my system. That file will be executed at server side and then they system will turn generated code back.
That definedMetaTags() function will be already written in the system.
An example of Compiler.php:
<?php
require_once("definitionsForProgrammer.php");
include("uploadedfile.php");
?>
My question is that I want to allow that uploadedfile.php only what functions I want. Else, maybe that programmer writes some codes what I want him/her to do. (Deleting files, mysql connection, etc.)
Is there any way to allow a code only specific functions, variables, constans?
If the goal is to allow a user to insert placeholders that will be replaced by some PHP function execution, then there's no need to treat the uploaded file as PHP code:
<html>
<head>
{[definedMetaTags]}
</head>
</body>
Then Compiler.php would look like this:
<?php
require_once("definitionsForProgrammer.php");
$macros = array();
$macros['definedMetaTags'] = definedMetaTags();
$output = file_get_contents("uploadedfile.php");
foreach($macros as $macro=>$value) $output = str_replace("{[$macro]}", $value, $output);
echo $output;
?>
The definedMetaTags() function would need to be reworked so that it returns the tags as a string instead of printing them directly to output.
This method would allow you to define any number of macros without exposing yourself to all the security risks the others here have mentioned.
If you're aiming for security and you want to let them to write functions, then the short answer is: no.
Essentially you're asking for a PHP sandbox which will let you constrain what code can be executed. PHP would have to support this at a fundamental level for it to work. For example, supposing you took the approach of saying "I only allow the user to write a function named 'foo'". Inside that function, though the user can do all kinds of bad things like making system calls, downloading other code and executing it, etc. In order to prevent this you'd need to implement checks at a much lower level in the system.
If you're willing to restrict the scope only to variable definitions then yes you can do it. You can use token_get_all() and token_name() to examine the file to make sure that it doesn't have any code that you don't want in it. For example:
foreach (token_get_all(file_get_contents("uploadedfile.php")) as $token) {
if (is_array($token)) {
echo token_name($token[0]), " ";
} else {
echo $token;
}
}
If you don't like any tokens you see, don't include the file. You could theoretically guard against bad functions this way as well, but it'll require a fair amount of effort to properly parse the file and make sure that they're not doing something bad.
references:
http://www.php.net/manual/en/function.token-get-all.php
http://www.php.net/manual/en/function.token-name.php
http://www.php.net/manual/en/tokens.php
Well, if i'm understanding your question correctly. If you include("uploadedfile.php"); you will acquire everything in it.
What you could do is break your code up into related sections (whether it be via classes or just function definitions in a file) then only include the file/class that you want.
(let me know if that's not what your asking)