How can I secure my $_GETs in PHP? - php

My profile.php displays all the user's postings,comments,pictures. If the user wants to delete, it sends the posting's id to the remove.php so it's like remove.php?action=removeposting&posting_id=2. If they want to remove a picture, it's remove.php?action=removepicture&picture_id=1.
Using the get data, I do a query to the database to display the info they want to delete and if they want to delete it, they click "yes". So the data is deleted via $POST NOT $GET to prevent cross-site request forgery.
My question is how do I make sure the GETs are not some javascript code, sql injection that will mess me up.
here is my remove.php
//how do I make $action safe?
//should I use mysqli_real_escape_string?
//use strip_tags()?
$action=trim($_GET['action']);
if (($action != 'removeposting') && ($action != 'removefriend')
&& ($action != 'removecomment'))
{
header("Location: index.php");
exit();
}
if ($action == 'removeposting')
{
//get the info and display it in a form. if user clicks "yes", deletes
}
if ($action =='removepicture')
{
//remove pic
}
I know I can't be 100% safe, but what are some common defenses I can use.
EDIT
Do this to prevent xss
$oldaction=trim($_GET['action']);
$action=strip_tags($oldaction);
Then when I am 'recalling' the data back via POST, I would use
$posting_id = mysqli_real_escape_string($dbc, trim($_POST['posting_id']));
if ($action == 'removeposting')
{
//get the posting id from the user
$getposting_id = htmlspecialchars(trim($_GET['posting_id']));
//basic checks for the posting id
if (empty($getposting_id)){
//header ("Location: index.php");
echo '<p>Sorry, no posting was specified for removal.</p>';
exit();
}
if (!is_numeric($getposting_id))
{
echo "Not an integer";
exit();
}
//Also have check to see if the posting_id is the user's. If so, can delete

Because you aren't storing $action and only using it in your conditional, it's not necessary to do all the trimming/stripping/escaping. The simple string comparisons is enough in terms of "safety," though I recommend using === instead of ==.
Alternatively, if you were storing a $_GET or $_POST value into an integer column of a MySQL database, for example, you could simply pass the value into intval() before storing it in the database. If you need to store plain text, just pass it through mysql_real_escape_string() before storing it. You can also use preg_match() or preg_replace() to make sure you are only storing valid values (different patterns for different uses, e.g. /^\d{5}(?:-?\d{4})?$/ for zip codes).

To prevent against any SQL injection you should use mysqli_real_escape_string OR you can use Prepared Statements that accomplish the same thing.
To prevent any javascript, you could use strip_tags in concert with htmlspecialchars.

I know I can't be 100% safe
ahahahaha :)
if your question regarding only action, and it is used only to determine the code to run, it IS safe by any means.
But some info for you:
POST doesn't prevent cross-site request forgery. unique token does.
You didn't post actual action code, so just to be sure - I hope you check user's id whan perform these actions

Use the mysqli_real_escape_string as noted elsewhere. Also, of course this does nothing to prevent XSRF. You'll need tokens containing some entropy for that.
See also: http://www.owasp.org/index.php/Main_Page

$_GET is completely safe until you try to glue (concatenate) it to the other things in your program like:
SQL to be executed (in which case you should use mysqli_real_escape_string() or another escaping technique that is advised with the database that you are using)
HTML to be outputted (in which case you should pass it through htmlspecialchars() before concatenation or printing/echoing)
URL to be navigated to by the user (in which case you most likely should pass it through urlencode())
JavaScript to be executed by the browser (in which case you should pass it through json_encode())
If you want to have an url in javascript embedded in html that you want to be inserted in database then you should pass value that you receive from $_GET (also $_POST, $_COOKIE and other similar outside sources) through all those functions in order appropriate to this scenario, namely
mysql_real_escape_string(htmlspecialchars(json_encode(urlencode($_GET['val']))));
If the only thing you do is compare your $_GET['action'] to some strings then you are perfectly safe without doing any escaping at all.

Related

How to integrate these pieces of code to protect against session hijacking

I'm using these docs to integrate a certain level of protection against session hijacking (bottom of page).
While I can understand the basics of what the article explains, I'm still new to all this and I'm just not able to pin-point what I should do.
I get how this would work:
<?php
session_start();
if (isset($_SESSION['HTTP_USER_AGENT']))
{
if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT']))
{
/* Prompt for password */
exit;
}
}
else
{
$_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
}
?>
... and I kinda understand how this can make the above more secure:
<?php
$string = $_SERVER['HTTP_USER_AGENT'];
$string .= 'SHIFLETT';
/* Add any other data that is consistent */
$fingerprint = md5($string);
?>
However, I'm stuck at combining the two into one working script. The docs state:
we should pass this fingerprint as a URL variable.
What does that mean? Do I need to pass the fingerprint in the URL and then use $_GET on each page? Anyone who can help me combining these two snippets of code into one file that I can include in all my PHP files?
yes, you'd need to add this token to any urls and then check it on every page.
Basically what you're trying to accomplish is what cryptographers call a NONCE
(number used once). The idea is to generate the NONCE using the params and then validate that the params haven't been tampered with.
Ideally this should be a hash salted with something random
and used once. There are many libraries that will take care of it for you.
Remember that hashes are not symmetric, i.e you can't un-hash request variables to see that it's the same thing.
What you can do is take a hash of the parameters and compare the hashes. It's important to remember about salts, because without them you'd be susceptible to rainbow tables.
Also if you use $_REQUEST rather than $_GET you can reuse the same logic for both $_POST and $_GET
You can take a look at this library for example, http://fullthrottledevelopment.com/php-nonce-library
you can also borrow the nonce generating code from Wordpress

PHP redirect within a function call

I have looked at some of the other posts made on similar topics but I cannot follow what they are instructing.
Basically my problem is this, I want to redirect to the main log in page of my website after a successful password reset has happened.
Here is what I have so far:
if (isset($_POST['Resetpw'])) {
if ($query == $_GET['token'] & $_POST['password'] == $_POST['confirmed_password']) {
$passwordTest = $_POST['password'];
$result = mysql_query("SELECT `tempTicket` FROM users WHERE `username` = '" . $_POST['username'] . "'limit 1;");
$query = mysql_fetch_array($result);
mysql_query("UPDATE users SET `tempPass` = '$passwordTest' WHERE `username` = '" . $_POST['username'] . "' ");
echo '<div class="success">Password successfully changed!</div> ';
//header("Location: www.google.com");
//exit;
This is all within a function, the commented out part is where I want to redirect to my webpage.
So to wrap it up, can I force the function to redirect to the start page after a function finishes. I am using KISSMVC framework for this project if that matters.
You should remove the echo before the redirect.
What you have commented out should work if you use the full path, e.g.: http://google.com.
Another thing: you should really drop the use of mysql_* functions (it will be deprecated in the future) and use either mysqli_* or PDO.
Yet another thing: you're application is vulnerable to SQL injection.
First, I hope I don't need to go into depth about sanitizing your inputs before accessing the database with them.
I am unaware of the KISSMVC. But I am aware of how PHP and browser-server interactions happen. So I'll approach your question from that format.
I see two things here. One is that you want to give the user an alert when a transaction has successfully happened. That can be done dynamically with a redirect, but it depends on where you send them. If you send the user to a location that you have no control over (your example cited google.com) then you will have to deliver your alert (and your input) with javascript and ajax. The reason for this is because header redirects won't function if you sent some output to the user's browser already. So, you will need to implement some .js into your code that makes an AJAX call to a script that executes your code and returns a success/failure flag, which then triggers a message (of success/failure).
If you do have control of the content you are redirecting to, and you do not wish to touch any .js, you can redirect to an intermediary page that uses a variable that you created to hold the success/failure message, output it to the browser and a button that links to your next page after that with the data appended to the query string. All that can be done in php/MySQL.
Yes, just get rid of the echo statement before it. You cannot echo anything to the screen before a header call.
You might also want to add some error handling so that you are really sure it was successful and switch to prepared statements to avoid sql injection.
Output Buffering
Everyone else here has said you can't echo anything before the header call (including whitespace). But that is fact incorrect. If you use output buffering in the php.ini file for example to output buffer the entire page - then you are free to use header() ANYWHERE in the script (so long as the code does not manually flush it). http://php.net/manual/en/outcontrol.configuration.php
You want to set this in php.ini
output_buffering = On;
And then you can use header() anywhere in your code. Just remember that after a redirect, to use die() or exit() to prevent the PHP page carrying on execution after the redirect.
Without Output Buffering
You must NOT print anything to the browser including whitespace otherwise the headers have already been sent and can no longer be modified by PHP. Output buffering stops this as the entire generated page is sent in one go at the end of the script meaning headers are free to be changed anywhere in the script.
P.S.
As others have mentioned, your SQL is vulnerable to SQL injection and you should no longer be using mysql_* but instead switch to pdo or mysqli_* due to mysql_* being depretiated.

Among $_REQUEST, $_GET and $_POST which one is the fastest?

Which of these code will be faster?
$temp = $_REQUEST['s'];
or
if (isset($_GET['s'])) {
$temp = $_GET['s'];
}
else {
$temp = $_POST['s'];
}
$_REQUEST, by default, contains the contents of $_GET, $_POST and $_COOKIE.
But it's only a default, which depends on variables_order ; and not sure you want to work with cookies.
If I had to choose, I would probably not use $_REQUEST, and I would choose $_GET or $_POST -- depending on what my application should do (i.e. one or the other, but not both) : generally speaking :
You should use $_GET when someone is requesting data from your application.
And you should use $_POST when someone is pushing (inserting or updating ; or deleting) data to your application.
Either way, there will not be much of a difference about performances : the difference will be negligible, compared to what the rest of your script will do.
GET vs. POST
1) Both GET and POST create an array (e.g. array( key => value, key2 => value2, key3 => value3, ...)). This array holds key/value pairs, where keys are the names of the form controls and values are the input data from the user.
2) Both GET and POST are treated as $_GET and $_POST. These are superglobals, which means that they are always accessible, regardless of scope - and you can access them from any function, class or file without having to do anything special.
3) $_GET is an array of variables passed to the current script via the URL parameters.
4) $_POST is an array of variables passed to the current script via the HTTP POST method.
When to use GET?
Information sent from a form with the GET method is visible to everyone (all variable names and values are displayed in the URL). GET also has limits on the amount of information to send. The limitation is about 2000 characters. However, because the variables are displayed in the URL, it is possible to bookmark the page. This can be useful in some cases.
GET may be used for sending non-sensitive data.
Note: GET should NEVER be used for sending passwords or other sensitive information!
When to use POST?
Information sent from a form with the POST method is invisible to others (all names/values are embedded within the body of the HTTP request) and has no limits on the amount of information to send.
Moreover POST supports advanced functionality such as support for multi-part binary input while uploading files to server.
However, because the variables are not displayed in the URL, it is not possible to bookmark the page.
$_GET retrieves variables from the querystring, or your URL.>
$_POST retrieves variables from a POST method, such as (generally) forms.
$_REQUEST is a merging of $_GET and $_POST where $_POST overrides $_GET. Good to use $_REQUEST on self refrential forms for validations.
I'd suggest using $_POST and $_GET explicitly.
Using $_REQUEST should be unnecessary with proper site design anyway, and it comes with some downsides like leaving you open to easier CSRF/XSS attacks and other silliness that comes from storing data in the URL.
The speed difference should be minimal either way.
Use REQUEST. Nobody cares about the speed of such a simple operation, and it's much cleaner code.
Don't worry. But you should still use the second solution (plus an extra check for none of those variables existing), because there are security issues with $_REQUEST (since $_GET and $_POST aren't the only sources for that array).
There was a post about the problems with $_REQUEST yesterday, I believe. Let me go find it.
EDIT: Oh well, not directly a post, but here it is anyway: http://kuza55.blogspot.com/2006/03/request-variable-fixation.html
if (isset($_GET['s'])) {
$temp = $_GET['s'];
}
else {
$temp = $_POST['s'];
}
Use that because it is safer and it won't make noticeable speed difference
$_GET retrieves variables from the querystring, or your URL.>
$_POST retrieves variables from a POST method, such as (generally) forms.
$_REQUEST is a merging of $_GET and $_POST where $_POST overrides $_GET. Good to use $_REQUEST on self refrential forms for validations.
There are certain security concerns involved as a hacker can set a cookie that will override a $_POST or $_GET value. If you handle sensitive data, I would not recommend using $_REQUEST. – Xandor
you can't be used $_GET alternative of $_POST on some case.
When ??
when you want to upload a file.
when you don't won't to show a data in url.
GET also has limits on the amount of information to send. The limitation is about 2000 characters.
Other thing's there are few case when you can't retrieve a data using $_POST
When ?
when data is passed in URL.
For Rest Service
`GET` - Provides a read only access to a resource.
`PUT` - Used to create a new resource.
there is nothing be wrong to use $_REQUEST.
But the way to do that is to check $_SERVER['REQUEST_METHOD'] explicitly, not rely on $_POST being empty for a GET.
I would use the second method as it is more explicit. Otherwise you don't know where the variables are coming from.
Why do you need to check both GET and POST anyway? Surely using one or the other only makes more sense.
I only ever use _GET or _POST. I prefer to have control.
What I don't like about either code fragment in the OP is that they discard the information on which HTTP method was used. And that information is important for input sanitization.
For example, if a script accepts data from a form that's going to be entered into the DB then the form had better use POST (use GET only for idempotent actions). But if the script receives the input data via the GET method then it should (normally) be rejected. For me, such a situation might warrant writing a security violation to the error log since it's a sign somebody is trying something on.
With either code fragment in the OP, this sanitization wouldn't be possible.
I would use $_POST, and $_GET because differently from $_REQUEST their content is not influenced by variables_order.
When to use $_POST and $_GET depends on what kind of operation is being executed. An operation that changes the data handled from the server should be done through a POST request, while the other operations should be done through a GET request. To make an example, an operation that deletes a user account should not be directly executed after the user click on a link, while viewing an image can be done through a link.
I use this,
$request = (count($_REQUEST) > 1)?$_REQUEST:$_GET;
the statement validates if $_REQUEST has more than one parameter (the first parameter in $_REQUEST will be the request uri which can be used when needed,
some PHP packages wont return $_GET so check if its more than 1 go for $_GET, By default, it will be $_POST.
You are prematurely optimizing. Also, you should really put some thought into whether GET should be used for stuff you're POST-ing, for security reasons.
It's ugly and I wouldn't recommended it as a final solution when pushing code live, but while building rest functions, it's sometimes handy to have a 'catch-all' parameter grabber:
public static function parseParams() {
$params = array();
switch($_SERVER['REQUEST_METHOD']) {
case "PUT":
case "DELETE":
parse_str(file_get_contents('php://input'), $params);
$GLOBALS["_{$_SERVER['REQUEST_METHOD']}"] = $params;
break;
case "GET":
$params = $_GET;
break;
case "POST":
$params = $_POST;
break;
default:
$params = $_REQUEST;
break;
}
return $params;
}
Someone creative could probably even add to it to handle command line parameters or whatever comes from your IDE. Once you decide what a given rest-function is doing, you can pick one appropriate for that given call to make sure you get what you need for the deploy version.
This assumes 'REQUEST_METHOD' is set.

Is this code vulnerable to hacker attack?

I am really new to online web application. I am using php, I got this code:
if(isset($_GET['return']) && !empty($_GET['return'])){
return = $_GET['return'];
header("Location: ./index.php?" . $return);
} else {
header("Location: ./index.php");
}
the $return variable is URL variable which can be easily changed by hacker.
E.g i get the $return variable from this : www.web.com/verify.php?return=profile.php
Is there anything I should take care? Should I use htmlentities in this line:
header("Location: ./index.php?" . htmlentities($return));
Is it vulnerable to attack by hacker?
What should i do to prevent hacking?
Apart from that typo on line 2 (should be $return = $_GET['return'];) you should do $return = urlencode($return) to make sure that $return is a valid QueryString as it's passed as parameter to index.php.
index.php should then verify that return is a valid URL that the user has access to. I do not know how your index.php works, but if it simply displays a page then you could end up with someting like index.php?/etc/passwd or similar, which could indeed be a security problem.
Edit: What security hole do you get? There are two possible problems that I could see, depending how index.php uses the return value:
If index.php redirects the user to the target page, then I could use your site as a relay to redirect the user to a site I control. This could be either used for phishing (I make a site that looks exactly like yours and asks the user for username/password) or simply for advertising.
For example, http://yoursite/index.php?return?http%3A%2F%2Fwww.example.com looks like the user accesses YourSite, but then gets redirected to www.example.com. As I can encode any character using the %xx notation, this may not even be obvious to the user.
If index.php displays the file from the return-parameter, I could try to pass in the name of some system file like /etc/passwd and get a list of all users. Or I could pass something like ../config.php and get your database connection
I don't think that's the case here, but this is such a common security hole I'd still like to point it out.
As said, you want to make sure that the URL passed in through the querystring is valid. Some ways to do that could be:
$newurl = "http://yoursite/" . $return;
this could ensure that you are always only on your domain and never redirect to any other domain
$valid = file_exists($return)
This works if $return is always a page that exists on the hard drive. By checking that return indeed points to a valid file you can filter out bogus entries
If return would accept querystrings (i.e. return=profile.php?step=2) then you would need to parse out the "profile.php" path
Have a list of valid values for $return and compare against it
this is usually impractical, unless you really designed your application so that index.php can only return t a given set of pages
There are many ways to skin this cat, but generally you want to somehow validate that $return points to a valid target. What those valid targets are depends on your specification.
If you're running an older version of both PHP 4 or 5, then I think you will be vulnerable to header injection - someone can set return to a URL, followed by a line return, followed by any other headers they want to make your server send.
You could avoid this by sanitising the string first. It might be enough to strip line returns but it would be better to have an allowed list of characters - this might be impractical.
4.4.2 and 5.1.2: This function now prevents more than one header to be
sent at once as a protection against
header injection attacks.
http://php.net/manual/en/function.header.php
What would happen if you put in a page that didn't exist. For example:
return=blowup.php
or
return=http://www.google.co.uk
or
return=http%3A%2F%2Fwww.google.co.uk%2F
You could obfuscate the reference by not including the .php in the variable. You could then append it in the code-behind and check for the existence of the file in your directory / use a switch statement of allowable values before redirecting to it.
In this case, it more depends on what's done with that part of the query string on index.php. If it's being sent to a database query, output, eval(), or exec() yes, its a very common security hole. Most other situations will be safe unfiltered, but its best to write your own general purpose sanitizing function which converts quotes of all varieties to their HTML entity, as well as equals symbols.
The things I would do are:
Define, what type of return values are allowed?
Write down all types of possible return values.
Then, make conclusions: what characters are not allowed, what is the maximum url length, what domains are allowed, etc.
Finally: make a filter function according to above conclusions.
I Thing hacker can do this
you will redirect if $_GET['return'] Contain any thing
the hacker can use it as xss
redirect to virus or any thing like it
but there is no ability to make any thing else

php security for location header injection via $_GET

I've got this code on my page:
header("Location: $page");
$page is passed to the script as a GET variable, do I need any security? (if so what)
I was going to just use addslashes() but that would stuff up the URL...
I could forward your users anywhere I like if I get them to click a link, which is definitely a big security flaw (Please login on www.yoursite.com?page=badsite.com). Now think of a scenario where badsite.com looks exactly like your site, except that it catches your user's credentials.
You're better off defining a $urls array in your code and passing only the index to an entry in that array, for example:
$urls = array(
'pageName1' => '/link/to/page/number/1',
'pageNumber2' => '/link/to/page/number/2',
'fancyPageName3' => '/link/to/page/number/3',
);
# Now your URL can look like this:
# www.yoursite.com?page=pageName1
This is a code injection vulnerability by the book. The user can enter any value he wants and your script will obey without any complaints.
But one of the most important rules – if even not the most important rule – is:
Never trust the user data!
So you should check what value has been passed and validate it. Even though a header injection vulnerability was fixed with PHP 4.4.2 and 5.1.2 respectivly, you can still enter any valid URI and the user who calls it would be redirected to it. Even such cryptic like ?page=%68%74%74%70%3a%2f%2f%65%76%69%6c%2e%65%78%61%6d%70%6c%65%2e%63%6f%6d%2f what’s URL encoded for ?page=http://evil.example.com/.
Yes, you do. Just because you or I can't immediately think of a way to take advantage of that little bit of code doesn't mean a more clever person can't. What you want to do is make sure that the redirect is going to a page that you deem accessible. Even this simple validation could work:
$safe_pages = array('index.php', 'login.php', 'signup.php');
if (in_array($page, $safe_pages)) {
header("Location: $page");
}
else {
echo 'That page is not accessible.';
}
Or, at the very least, define a whitelist of allowed URLs, and only forward the user if the URL they supplied is in the GET variable is in the list.

Categories