If I turn off magic_quotes in an environment where I did not wrote the code, how can I check if any problems may occur? For what do I have to check? Which functions may not work any more?
When magic_quotes turned on, Magic Quotes automatically performs an addslashes() on all form data submitted. It means that a [\] is placed before every ['], ["], [], or null in the data, so That's nice will be converted to That\'s nice automatically. This all happens before your coding even sees that data, so if you're just passing a string to the next page (not to database) it will print with slashes even though you may not want them at all.
Unfortunately, I don't think there's an easy answer. You'll want to check for any place where you're working directly with user input. If the code is simple enough, you can search for uses of $_GET and $_POST, but without at least a scanning code review, you're unlikely to find everything that way.
One thing I've had break a lot when I turn it off is sql insert/update queries someone had written that contained request parameters they had not properly escaped.
Magic quotes affects incoming data strings. Any place you use $_GET or $_POST or variables of that nature can be affected.
Basically, any place you accept data from the user.
Note: More importantly, you should look through all of your SQL queries and make sure that any input strings are escaped! Otherwise your code will be vulnerable to SQL injection.
Related
Right now I am using htmlspecialchars(mysql_escape_string($value)), but is there a way to sanitize it with one statement rather than a nested statement?
Well there's no one function that handles both of them.
You can use prepared statements and html puffier class, maybe then the "look and feel" will be little bit better :)
mysql_real_escape_string has actually fallen out of favor lately.
It is now preferred to use PDO or mysqli. They both come with PHP by default. They use something called parameterized queries to access the database, rather than having you write the SQL command yourself. This means that you don't need to worry about escaping anymore, since the query and the variables are passed into the function separately.
You can learn more about PDO here:
http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
On a related note, it is conventional to store user-supplied input into the database "as it was written", rather than using htmlspecialchars. You should then use htmlspecialchars to escape the data wherever the it appears on the site. This is a convention recommended by OWASP.
This is because you need to escape different things depending on context. This string:
' <script src="http://example.org/malice.js"></script> ]}\\\\--
...will need to be treated differently if it is used as a parameter in JSON (the quotes and backslashes and ] and } need to be escaped), HTML (the quotes and <s need to be escaped), or written as a URL (almost everything needs to be escaped). If you need to spend time instructing your JavaScript to un-encode the HTML, then your code is going to be confusing quickly.
This approach also makes fixing bugs simpler: if your site has a bug where content isn't escaped properly on a single page, then you can update the page and everything is fixed. If your site has a bug where the data is getting stored in the database incorrectly, then you need to fix everything in the database (which will take much longer and harm more users).
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.
http://php.about.com/od/finishedphp1/ss/php_login_code_4.htm
I am really confused about three particular lines of code in this tutorial to create a login page and databse, on the page I have listed above.
if (!get_magic_quotes_gpc()) {
$_POST['email'] = addslashes($_POST['email']);
}
Why is she fiddling with the $_POST['email'] value, when it isn't even in an input box?
EDIT:
I still cannot find an input box for email, I have even copied and pasted the entire site. I still can't find one box that says email.
First, it doesn't matter where the content comes from on the page. Any user-submitted content (i.e. anything in the $_GET, $_POST or $_COOKIE superglobals) should be treated as unsafe. Don't presume that the only way a user can submit evil content is by typing it into a textbox.
Second, this code is, IMO, dumb. It basically says "if magic quotes are off, do what they'd have done if they were on, by adding slashes to avoid SQL injection". It's the lazy way to make your code work. The proper way is to build your code so that magic quotes are unnecessary, by using parametrized queries (e.g. using PDO or mySqli).
Basically, from that line of code, you can tell enough to know that you shouldn't trust the rest of it.
When a form is submitted (via POST), you can access the data server-side with the special variable $_POST. Each item of your form will be indexed in that array, give its DOM name.
So the point here, is to check the server configuration, and if the behavior to automatically add slashes to the input (to avoid SQL injection), then this action is performed by the developper. This is to avoid double addslashes which leads to crappy output.
See: super globals, sql injection at owasp, and magic quotes.
email is probably set by a form on another page that links to this page. As for writing directly to _POST, I don't think there is anything wrong with it per se, but I think it is weird and I don't like to do it. In fact, I would do the opposite and strip slashes if magic quotes is enabled and handle the escaping of it later (rather than with mysql_real_escape_string). Before handling a _POST, value I would do something like $email = $_POST['email']... etc. and just keep _POST as the raw _POST data the whole time.
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).
What is most efficient method to making sure that get/post parameters won't provide any security vulnerability.
I am familior of htmlentities for javascript code injection prevention
and addslashes to prevent sql injection.
so.. for now i'm using them both on each get/post parameter.
are there any other functions i can use to prevent these vulnerabilities better or are there any other security issues that i should worry about related to my php code ?
htmlentities (or htmlspecialchars) and addslashes (or mysql_real_escape_string or other database-appropriate escaping function; addslashes is invariably the wrong thing) are nothing to do with GET/POST parameters. They are outgoing-escaping functions whose input might come from parameters, but might equally come from somewhere else, such as a static string or a string fetched from the database.
for now i'm using them both on each get/post parameter.
No, that doesn't work. It's a common mistake, and one perpetuated by a lot of the totally dreadful PHP tutorial material out there. Trying to split off the problem of string escaping into one little loop instead of being spread all over the code sounds nice, but string escaping doesn't work like that in reality. You need to apply the right form of escaping, and only the right form of escaping, at each time you put a string inside another string. You cannot do that in advance.
Don't try to ‘sanitise’ or ‘filter’ all the incoming parameters to encode or remove characters like \ or <. This will result in your application filling up with rubbish like \\\\\\\\\\\\\\\\\\\\\\\\\\ and &amp;amp;amp;amp;amp;. Instead, you should only encode them — along with any other varaibles that don't come from GET/POST — at the last minute when spitting them into a different context of text, like htmlspecialchars for HTML or mysql_real_escape_string for MySQL string literals. You are usually better off with parameterised queries though, which avoids the SQL escaping issues.
That's not to say you shouldn't check your incoming data for conformance to your application's requirements. If you've got a field you expect to get an integer for, be sure to intval it before using it. If you've got a plain single-line text string which you don't expect to contain newlines, be sure to filter the \n character from the string, along with all other control characters [\x00-\x1F\x7F]. But these are application requirements, not something you can necessarily run across all your input.
GET and POST variables are no more dangerous than any other variables. You should handle injection vulnerabilities at the usage point, not at the input point. See my answer here:
What’s the best method for sanitizing user input with PHP?
You can use Data Filtering as a data firewall.
http://www.php.net/filter
GET/POST are public so the main security concern is to not pass sensitive information (i.e. keys and values that give away your directory structure or db schema). Also remember that anyone can manipulate or create their own HTTP requests so be sure to validate data before inserting it into a database. Other than that they don't pose any threats on their own since they have no effects until you do something with them.
If you are looking for a simple and fast solution, that prevents general security vulnerabilities, I could name the following functions.
htmlentities() , strip_tags() and addSlashes() if get_magic_quotes_gpc() returns FALSE
On the other hand, if you'd like to tighten up your security , check the Data Filtering, mentioned by Kristoffer BOhmann
There are already many good answers, as a rule of thumb you should:
turn off magic_quotes_gpc
validate get/post parameters
html encode parameters before display
use the escape function of the database in queries
This is just the minimum that will prevent the most common vulnerabilities.
This is an example of how to use Addslashes Or Mysql_real_escape_string(): http://zacklive.com/addslashes-or-mysql-real-escape-string-stop-sql-injection/906/