PHP $_GET security, $_POST security best practice - php

It's a well covered topic, but I'd like to get some confirmation on methods of using data from user variables, in a few different situations.
The variable is never used in a database, never stored, only displayed on screen for the user. Which function to use to make sure no html or javascript can screw things up?
The variable is taken into the database, and used in SQL queries.
The variable does both.
At the moment I xss_clean, and strip_tags. I've always done this, just by autopilot. Is there a better technique? Apologies if there's an identical question out there. I kinda assume there is, although I couldn't find one as thorough as this.
Cheers.

Use the appropriate function while outputting, in HTML context, this is htmlspecialchars
Use prepared statements
See 1. and 2. – depending on whether you are displaying the variable or you are using it in a query.

One of worst delusions in the PHP world is that $_GET or $_POST have anything to do with security.
It is not the source but destination that matters
If you have to deal with database, the rules always the same, no matter if the data is coming from $_POST, SOAP request or a database. It has to be ALWAYS the same: placeholders for the data, whitelisting for the everything else.
If you have to output some data into browser, you have to properly prepare it, no matter whether the data is coming from $_POST, SOAP request or a database.
If you have to read from a file - you have to secure the filename, no matter where it coming from, and so on

In the first case htmlspecialchars() probably is the best choice, allowing for users to use all characters like <, >, &, etc.
In the second case you will need to use some database escaping function like mysql_real_escape_string or a prepared statement with PDO or mysqli. Prepared statements are the best choice here but if you are only familiar with mysql then mysql_real_escape_string works fine too. If you are not using mysql then there are similar functions in most SQL APIs.
In the third case do both but separately, with gives you two diffrent results, one for output and one for database.
References:
http://php.net/manual/en/function.htmlspecialchars.php
http://php.net/manual/en/function.mysql-real-escape-string.php
http://php.net/manual/en/book.pdo.php
http://php.net/manual/en/book.mysqli.php

$id="1;drop table users;"; $id=mysql_real_escape_string($id); $sql="SELECT * FROM table
WHERE id=$id";

Related

When to use mysql real escape string

I am totally confused, I've read a few posts but still I am not sure. I do not want to go the prepared statements route since this site is only on our intranet. I've read the following posts, but still I am uncertain.
When to use mysql_real_escape_string?
When to use mysql_real_escape_string()
My question: Should I use mysql-real-escape-string
When only I get user input from a form OR
On all my queries? eg: SELECT * FROM ......
For example in this post it states: You need to call this function when building SQL queries with string literals. You should not call it anywhere else.
What prepared statements do (among other things) is to call a method similar to mysql_real_escape_string()
If you don't use PDO, what is fine, you must understand what are you doing, and you will get the same security level.
The only and simple rule is all raw data needs mysql_real_escape_string() (or similar from other languages)
Examples are:
- Data from user input
- Data that you have stored RAW on DB (witch is the best way) and you are using on a new sql statment
- Data from unknow/other origin
The detalis are:
- be sure to not apply twice (to preserve data correctly)
Well I actually use it on :
ANY variable that I'm going to put into a MySQL Query and which could have been modified by a user, either if it's direct user input (through a form), or a parameter that I've been passing around via GET requests, etc
You get my point... :-)
It's important when you don't know for sure what's included in the string.
This means user inputs.
You might also want to consider moving to prepared statements with PDO.
You should use it on any variable that you are interpolating in a SQL query.
Everything that is not a literal string should be sanitized. It doesn't matter if you got it from a form, a database or anything else, if it's not constant then you should sanitize it.
The quoted sentence in your question is true.
All the other answers are wrong.
Every time you are going to add a quoted string to the SQL query, you have to always escape it.
That's the only case when you have to use mysql_real_escape_string().
PS. I can't believe this question is still alive with all it's answers.
Stackoverflow is a very strange place.

Sanitize $_SERVER['HTTP_USER_AGENT'] & $_SERVER['HTTP_REFERER'] before saving to DB?

I have a feedback form which will take a couple of user inputted fields along with a few fields generated by PHP functions like 'user-agent' and 'referer.'
My question is should these strings be sanitized before being inputted? I realize one could easily alter the user-agent and the referring page, but could it be possible for a visitor to add a SQL injection like string so when PHP pulls this info it potentially breaks my form?
For instance if a user changed their user-agent or referring page to include the string Robert'); DROP TABLE Students;--
The word "sanitize" is pretty ambiguous and and better to be avoided.
Speaking of a database interaction, there is no need to "sanitize" at all. Just use prepared statements.
What is even more important, the data source doesn't matter. It should never be a question, "should we properly handle the data from such and such source?". It's just illogical, if you think of it. Why making such a distinction? Why rely on such a vague judgement? Why not to have an established process that uniformly treats any data despite the source?
Not to mention it's just super simple to use prepared statements:
$stmt = $db->prepare("INSERT INTO log (user_agent, referrer) VALUES (?,?)");
$stmt->execute([$_SERVER['HTTP_USER_AGENT'],$_SERVER['HTTP_REFERER']]);
And it will not only make the code simpler yet secure, but also make it proof against human errors of all sorts.
Simple Answer: validate/sanitize/escape everything (like client-side data, for example) because everything could be modified and evil or contain unexpected characters that could break your query (like Col. Shrapnel explained).
to minimize risk you should also about using prepared statements instead of building SQL-strings on your own (Note: this doesn't mean you can leave out the checks).
First off all - I believe the best practice is to parametr-ise everything in the query including self generated values. For me it does not make the query (almost) bulletproof but it creates much nicer and readable queries.
When you use parameters and assign them later you use more explicit logic in your code and therefore it will function better in the long term.
Longer explanation can be found in the attached link:
How can I prevent SQL injection in PHP?
Always sanitize/filter any input from a browser.
Just assume all users are evil, and you should be fine.
A connection doesn't have to come from a browser - anyone can write their own HTTP requests with a telnet client. There are probably specialized tools for this as well, and they wouldn't be hard to create.

What is the proper way to secure data going in & out of my database?

I'm trying to secure my script a bit after some suggestions in the last question I asked.
Do I need to secure things like $row['page_name'] with the mysql_real_escape_string function? example:
$pagename = mysql_real_escape_string($row['page_name']);
I'm asking mainly because when I do secure every row I get some errors like when trying number_format() it throws number_format() expects parameter 1 to be double, string given while when it is not secured with mysql_real_escape_string it works.
Can someone clear this for me? Do I only need to secure COOKIE's or the row fetches too?
I got the suggestion in this post: HERE (look at the selected answer)
You're doing it backwards. Presumably $row is a row coming out of the database. You don't mysql_real_escape_string on the way out of the database, you use it on data going into the database to prevent SQL injection. It prevents people from submitting data that contains executable SQL code.
Once the data is safely in the database, you're done with mysql_real_escape_string (until you attempt to update that data). User data coming out of the database needs to be run through htmlspecialchars before it hits the page to prevent script injection.
Basically, on the way to the database, just before your insert/update runs, you need to escape potentially executable SQL. On the way to the browser, just before strings leave your app for the browser, you need to escape potentially executable JavaScript and/or interpretable HTML. Escaping should be the last thing you do with a piece of data before it leaves your app for either the browser or database.
This is by no means a complete answer.
Before writing any more code you need to stop and consider exactly what it is you are trying to accomplish.
In other words, what are you gaining by running the mysql_real_escape_string function?
Generally speaking, you escape data submitted by the client. This is to help prevent sql injection. Also, you should go further to actually validate that what the client sent in is acceptable (ie. "Sanity Check"). For example, if you are expecting a numeric entry, don't accept strings and range check the values. If you are expecting string data like a name, don't accept HTML, but again range check to verify length is acceptable. Both of these situations occur when the client submits data, not when you are writing it back out.
Going a little further, your cookies should be encrypted and marked with the httponly flag to tell the browser that it is not for use in client side script. Even with that, you shouldn't trust the data in the cookie at all; so go ahead and run your sanity checks and still escape those values in queries.
I highly recommend that you go to the OWASP website and read through all of the issues to get a better understanding of how attacks work and how to defend against them. Web App security is too important to just start coding without really knowing what's going on.
BTW, kudos to you for learning about this and trying to defend your site. Too many devs don't even think about security at all.
If you use the PDO extension to build clean requests, you can create functions that will do this (secure strings and define their type) :
An exemple where $text is a string of text and $number is an integer :
public function InsertThis($number, $text) {
$pdo = $this->getPdo();
$sth = $pdo->prepare("INSERT INTO my_table (number, text) VALUES (:number, :text");
$sth->bindParam('number',$number,PDO::PARAM_INT);
$sth->bindParam('text',$text);
$sth->execute();
}
http://php.net/manual/en/book.pdo.php
You only need to use mysql_real_escape_string() when inserting/updating a row where the values have come from untrusted sources.
This includes things like:
$_GET
$_POST
$_COOKIE
Anything that comes from the browser
Etc..
You should only use it when putting things into the database, not when you are taking things out, as they should already be safe.
A safer way altogether is to use the PDO class
mysql_real_escape_string does not "secure" anything. It escapes characters that can be used in sql injection attacks. Therefore the only values that you should escape are the ones supplied by your users. There should be no need to escape things that come out of your own database.

How to secure $_REQUEST?

How can I secure $_REQUEST before inserting to mysql database? For example following:
$message = $message = $_REQUEST['message'];
$tags = $_REQUEST['item']['tags'];
Thanks.
Depends on what you mean by "secure", and how you intend to insert the data. $_REQUEST isn't broken or anything; it's just that the data in it can be just about anything, so you'll need to "sanitize" it before you use it.
For example, if 'some_id' should only ever be an int,
$some_id = intval($_REQUEST['some_id']);
will ensure that $some_id is always an int. (Even if it didn't exist in $_REQUEST! In which case it will be 0.)
If you use prepared statements, a lot of the issues with $_REQUEST data go away -- that is, extensions like PDO and mysqli will escape parameters for you (if you use placeholders, like all good prepared statements should!), so all you have to do is make sure the data is valid. (For example, above, it'd have been a good idea to make sure $_REQUEST['some_id'] was set first -- since we didn't, we got a 0 back, which may not be valid.)
If you don't use prepared statements, then you have a little more work ahead of you. You'll need to use mysql_real_escape_string to escape strings as you feed them into the database, like so:
$some_string_sql = mysql_real_escape_string($_REQUEST['some_string']);
$id = intval($_REQUEST['id']);
mysql_query("UPDATE stuff SET some_string = '$some_string_sql' WHERE id = $id");
Note that i did this just for the query! Too many PHP noobs think they can just apply some magic formula to everything in $_REQUEST at the beginning of their script to make everything safe. You kinda can, if you're always just feeding it directly into an SQL query -- but it trashes your data if you're using it for other stuff! For example, if you write the data to a file as well, blindly escaping the data will leave you with a bunch of ugly backslashes in your file. You should never have to *un*escape your data -- it should always be escaped as you need it, for the specific purpose you intend to use it. (htmlentities for arbitrary data being printed to the screen, mysql_real_escape_string for stuff going into an SQL query.)
Also note: If you have magic_quotes_gpc enabled on your site, disable it for the reasons mentioned in the previous paragraph. Properly escaped stuff will break in the presence of magic quotes, because it's already been "escaped" once (half-assedly, hence the quotes) by PHP! Fortunately this misfeature will be removed from PHP 6, if it ever ships. But til then, if you have magic quotes enabled, you'll need to stripslashes(anything from $_REQUEST, $_GET, $_POST, or $_COOKIE) before you can properly escape it. DO NOT rely on the magic quotes -- they're a convenience thing, and not at all designed for security.
You should just not forget escaping your data when injecting them in some SQL queries.
Either use a function to escape the data :
Depending on the API you're working with :
mysql_real_escape_string,
mysqli_real_escape_string,
or PDO::quote
Or you could use Prepared Statements :
Those might seem a bit harder to understand, at first -- but they are worth investing sometime...
With mysqli,
And with PDO.
Then, of course, when using the data from the database to generate some output, the same idea applies : escape the output.
If you are generating some HTML output, you'll typically want to use something like htmlspecialchars.
Or, to allow some specific HTML tags, see HTML Purifier.
If you are generating some other kind of output, you'll have to find how to escape your data specifically for this type of output.
Use either mysql_real_escape_string() or PDO's prepared statements. I recommend the latter, as it also helps keep your queries nice and tidy.
As secure as anything could be in them.
The user can change those values to whatever they want.
So, not secure at all. Always sanitize your inputs.
There is nothing to secure.
Your database input should be just properly formatted.
For the strings it's quoting and escaping.
As long as your input data is limited to strings and you follow formatting rules, no special security required.

I'm learning PHP on my own and I've become aware of the strip_tags() function. Is this the only way to increase security?

I'm new to PHP and I'm following a tutorial here:
Link
It's pretty scary that a user can write php code in an input and basically screw your site, right?
Well, now I'm a bit paranoid and I'd rather learn security best practices right off the bat than try to cram them in once I have some habits in me.
Since I'm brand new to PHP (literally picked it up two days ago), I can learn pretty much anything easily without getting confused.
What other way can I prevent shenanigans on my site? :D
There are several things to keep in mind when developing a PHP application, strip_tags() only helps with one of those. Actually strip_tags(), while effective, might even do more than needed: converting possibly dangerous characters with htmlspecialchars() should even be preferrable, depending on the situation.
Generally it all comes down to two simple rules: filter all input, escape all output. Now you need to understand what exactly constitutes input and output.
Output is easy, everything your application sends to the browser is output, so use htmlspecialchars() or any other escaping function every time you output data you didn't write yourself.
Input is any data not hardcoded in your PHP code: things coming from a form via POST, from a query string via GET, from cookies, all those must be filtered in the most appropriate way depending on your needs. Even data coming from a database should be considered potentially dangerous; especially on shared server you never know if the database was compromised elsewhere in a way that could affect your app too.
There are different ways to filter data: white lists to allow only selected values, validation based on expcted input format and so on. One thing I never suggest is try fixing the data you get from users: have them play by your rules, if you don't get what you expect, reject the request instead of trying to clean it up.
Special attention, if you deal with a database, must be paid to SQL injections: that kind of attack relies on you not properly constructing query strings you send to the database, so that the attacker can forge them trying to execute malicious instruction. You should always use an escaping function such as mysql_real_escape_string() or, better, use prepared statements with the mysqli extension or using PDO.
There's more to say on this topic, but these points should get you started.
HTH
EDIT: to clarify, by "filtering input" I mean decide what's good and what's bad, not modify input data in any way. As I said I'd never modify user data unless it's output to the browser.
strip_tags is not the best thing to use really, it doesn't protect in all cases.
HTML Purify:
http://htmlpurifier.org/
Is a real good option for processing incoming data, however it itself still will not cater for all use cases - but it's definitely a good starting point.
I have to say that the tutorial you mentioned is a little misleading about security:
It is important to note that you never want to directly work with the $_GET & $_POST values. Always send their value to a local variable, & work with it there. There are several security implications involved with the values when you directly access (or
output) $_GET & $_POST.
This is nonsense. Copying a value to a local variable is no more safe than using the $_GET or $_POST variables directly.
In fact, there's nothing inherently unsafe about any data. What matters is what you do with it. There are perfectly legitimate reasons why you might have a $_POST variable that contains ; rm -rf /. This is fine for outputting on an HTML page or storing in a database, for example.
The only time it's unsafe is when you're using a command like system or exec. And that's the time you need to worry about what variables you're using. In this case, you'd probably want to use something like a whitelist, or at least run your values through escapeshellarg.
Similarly with sending queries to databases, sending HTML to browsers, and so on. Escape the data right before you send it somewhere else, using the appropriate escaping method for the destination.
strip_tags removes every piece of html. more sophisticated solutions are based on whitelisting (i.e. allowing specific html tags). a good whitelisting library is htmlpurifyer http://htmlpurifier.org/
and of course on the database side of things use functions like mysql_real_escape_string or pg_escape_string
Well, probably I'm wrong, but... In all literature, I've read, people say It's much better to use htmlspellchars.
Also, rather necessary to cast input data. (for int for example, if you are sure it's user id).
Well, beforehand, when you'll start using database - use mysql_real_escape_string instead of mysql_escape_string to prevent SQL injections (in some old books it's written mysql_escape_string still).

Categories