I'm familiar with using mysql_real_escape_string() and the PHP FILTER_SANITIZE function to prevent sql injections.
However, I'm curious as to how I would determine within a PHP script whether or not user input was a likely sql injection attempt? That would be useful for tracking potentially malicious IPs.
If the output of mysql_real_escape_string is different to the input, then the input contained unsafe characters. You could infer that the user might have been attempting an attack, especially if the field in question is one where you'd normally expect a low number of unsafe characters (e.g. a zip code).
But it might also be because their name happened to be Robert'); DROP TABLE Students; --.
So in general, there is no way to do this that's even close to reliable.
Simple answer is you cannot. Just write code that assumes that the serve is going to receive a pounding then you cannot go wrong.
This is a very hard problem to solve, automatically detecting which SQL queries are attacks (or simple mistakes).
There are companies who make products that attempt to do this, like GreenSQL and DB Networks ADF-4200, by applying heuristic tests to see if queries look "suspicious."
But even they rely more on whitelisting the queries that your application runs. The heuristics are known to have both false positives and false negatives. And there are whole categories of queries that neither whitelisting nor heuristics can catch, like calls to stored procedures.
Someone mentioned mod_security too, but this requires a lot of configuration, and then you're back to hand-coding rules for whitelisting your application's legitimate queries.
Just follow good practices like parameterizing and whitelisting, so that user input (or any untrusted content) is never evaluated as code.
Actually there is no certain way !
but it is possible to guess attacks !
simply check for most common usefull sql injection structures
for example scan this words (in case insensitive) in your inputs :
union
select
drop
--
;
if you know how to stop sql injection , you shouldn't be worried and you can run the query safely. but as I understood you want to detect injections , so i prefer you just log suspicious inputs and then decide manually ! in most cases logged queries are real injections.
Test for '--' and ';' strings ... maybe also OR, AND, (, etc. But you can never be 100% sure it WAS an attack.
I would say it's safer to assume that ALL user input is an attack when you write your code and make your program secure enough to mitigate the attack rather than trying to retroactively fix something that may or may not have been an attack.
You can try the following:
If there are no characters to be escaped in the input string, then
it's not an attack attempt.
Put the user input in the query without quoting.
Try to check the query syntax without running it (e.g. make mysql do it for you somehow (?)).
If there is no syntax error, then it was an attack attempt.
But this way you can only detect potentially successful attack attempts, not those which give parse error.
You may search for certain keys (union,delete,drop, ...) and so on. Search for --, \n (new lines) if you are sure that original query would never ever have it. Create a query that always returns some value - if with user malicious input it doesn't that may indicate an attack.
But because users tend to ALWAYS make mistakes or attack servers (number, i will write letters to check how much mess it will make...) all user inputs should be filtered before used.
(joke deleted)
EDIT: You can try the following:
If there are no characters to be escaped in the input string, then
it's not an attack attempt.
Put the user input in the query without quoting.
Try to check the query syntax without running it (e.g. make mysql do it for you somehow (?)).
If there is no syntax error, then it was an attack attempt.
But this way you can only detect potentially successful attack attempts, not those which give parse error.
Related
I understand that you should NEVER trust user input from a form, mainly due to the chance of SQL injection.
However, does this also apply to a form where the only input is from a dropdown(s) (see below)?
I'm saving the $_POST['size'] to a Session which is then used throughout the site to query the various databases (with a mysqli Select query) and any SQL injection would definitely harm (possibly drop) them.
There is no area for typed user input to query the databases, only dropdown(s).
<form action="welcome.php" method="post">
<select name="size">
<option value="All">Select Size</option>
<option value="Large">Large</option>
<option value="Medium">Medium</option>
<option value="Small">Small</option>
</select>
<input type="submit">
</form>
Yes you need to protect against this.
Let me show you why, using Firefox's developer console:
If you don't cleanse this data, your database will be destroyed. (This might not be a totally valid SQL statement, but I hope I've gotten my point across.)
Just because you've limited what options are available in your dropdown does not mean you've limited the data I can send your server.
If you tried to restrict this further using behaviour on your page, my options include disabling that behaviour, or just writing a custom HTTP request to your server which imitates this form submission anyway. There's a tool called curl used for exactly that, and I think the command to submit this SQL injection anyway would look something like this:
curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--" http://www.example.com/profile/save
(This might not be a totally valid curl command, but again, I hope I've gotten my point across.)
So, I'll reiterate:
NEVER trust user input. ALWAYS protect yourself.
Don't assume any user input is ever safe. It's potentially unsafe even if it arrives through some means other than a form. None of it is ever trustworthy enough to forgo protecting yourself from SQL injection.
You could do something as simple as the following example to make sure the posted size is what you expect.
$possibleOptions = array('All', 'Large', 'Medium', 'Small');
if(in_array($_POST['size'], $possibleOptions)) {
// Expected
} else {
// Not Expected
}
Then use mysqli_* if you are using a version of php >= 5.3.0 which you should be, to save your result. If used correctly this will help with sql injection.
As this question was tagged with sql-injection, here is an answer regarding this particular kind of attack:
As you've been told in the comments, you have to use prepared statements for the every single query involving any variable data, with no exceptions.
Regardless of any HTML stuff!
It is essential to understand that SQL queries have to be formatted properly regardless of any external factors, be it HTML input or anything else.
Although you can use white-listing suggested in other answers for the input validation purpose, it shouldn't affect any SQL-related actions - they have to remain the same, no matter if you validated HTML input or not. It means you still have to use prepared statements when adding any variables into the query.
Here you may find a thorough explanation, why prepared statements is a must and how to properly use them and where they aren't applicable and what to do in such case: The Hitchhiker's Guide to SQL Injection protection
Also, this question was tagged with mysqli. Mostly by accident, I presume, but anyway, I have to warn you that raw mysqli is not an adequate substitution for the old mysq_* functions. Simply because if used in the old style, it will add no security at all. While it's support for the prepared statements is painful and troublesome, to the point that average PHP user is just unable to endeavor them at all. Thus, if no ORM or some sort of abstraction library is option, then PDO is your only choice.
Yes.
Anyone can spoof anything for the values that actually get sent --
SO, for validating dropdown menus, you can just check to make sure that the value that you're working with was in the dropdown - something like this would be the best(most sanely paranoid) way:
if(in_array($_POST['ddMenu'], $dropDownValues){
$valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)];
} else {
die("effin h4x0rs! Keep off my LAMP!!");
}
One way of protecting against users changing your drop downs using the console is to only use integer values in them. Then you can validate that the POST value contains an integer, and use an array to convert that to text when needed. E.g:
<?php
// No, you don't need to specify the numbers in the array but as we're using them I always find having them visually there helpful.
$sizes = array(0 => 'All', 1 => 'Large', 2 => 'Medium', 3 => 'Small');
$size = filter_input(INPUT_POST, "size", FILTER_VALIDATE_INT);
echo '<select name="size">';
foreach($sizes as $i => $s) {
echo '<option value="' . $i . '"' . ($i == $size ? ' selected' : '') . '>' . $s . '</option>';
}
echo '</select>';
Then you can use $size in your query with knowledge that it will only ever contain FALSE or an integer.
The other answers already cover what you need to know. But maybe it helps to clarify some more:
There are TWO THINGS you need to do:
1. Validate form data.
As Jonathan Hobbs' answer shows very clearly, the choice of html element for the form input does not do any reliable filtering for you.
Validation is usually done in a way that does not alter the data, but that shows the form again, with the fields marked as "Please correct this".
Most frameworks and CMSes have form builders that help you with this task. And not just that, they also help against CSRF (or "XSRF"), which is another form of attack.
2. Sanitize/Escape variables in SQL statements..
.. or let prepared statements do the job for you.
If you build a (My)SQL statement with any variables, user-provided or not, you need to escape and quote these variables.
Generally, any such variable you insert into a MySQL statement should be either a string, or something that PHP can be reliably turn into a string that MySQL can digest. Such as, numbers.
For strings, you then need to choose one of several methods to escape the string, that means, replace any characters that would have side effects in MySQL.
In old-school MySQL + PHP, mysql_real_escape_string() does the job. The problem is that it is far too easy to forget, so you should absolutely use prepared statements or query builders.
In MySQLi, you can use prepared statements.
Most frameworks and CMSes provide query builders that help you with this task.
If you are dealing with a number, you could omit the escaping and the quotes (this is why the prepared statements allow to specify a type).
It is important to point out that you escape the variables for the SQL statement, and NOT for the database itself. The database will store the original string, but the statement needs an escaped version.
What happens if you omit one of these?
If you don't use form validation, but you do sanitize your SQL input, you might see all kinds of bad stuff happening, but you won't see SQL injection! (*)
First, it can take your application into a state you did not plan for. E.g. if you want to calculate the average age of all users, but one user gave "aljkdfaqer" for the age, your calculation will fail.
Secondly, there can be all kinds of other injection attacks you need to consider: E.g. the user input could contain javascript or other stuff.
There can still be problems with the database: E.g. if a field (database table column) is limited to 255 characters, and the string is longer than that. Or if the field only accepts numbers, and you attempt to save a non-numeric string instead. But this is not "injection", it is just "crashing the application".
But, even if you have a free text field where you allow any input with no validation at all, you could still save this to the database just like that, if you properly escape it when it goes to a database statement. The problem comes when you want to use this string somewhere.
(*) or this would be something really exotic.
If you don't escape variables for SQL statements, but you did validate form input, then you can still see bad stuff happening.
First, you risk that when you save data to the database and load it again, it won't be the same data anymore, "lost in translation".
Secondly, it can result in invalid SQL statements, and thus crash your application. E.g. if any variable contains a quote or double quote character, depending which type of quote you use, you will get invalid MySQL statement.
Thirdly, it can still cause SQL injection.
If your user input from forms is already filtered / validated, intentional SQl injection may become less likely, IF your input is reduced to a hardcoded list of options, or if it is restricted to numbers. But any free text input can be used for SQL injection, if you don't properly escape the variables in SQL statements.
And even if you have no form input at all, you could still have strings from all kinds of sources: Read from the filesystem, scraped from the internet, etc. Noone can guarantee that these strings are safe.
Your web browser does not "know" that it is receiving a page from php, all it sees is html. And the http layer knows even less than that. You need to be able to handle nearly any kind of input that can cross the http layer (luckily for most input php will already give an error).
If you are trying to prevent malicious requests from messing up your db, then you need to assume that the guy on the other end knows what he is doing, and that he is not limited to what you can see in your browser under normal circumstances (not to mention what you can fiddle with a browser's developer tools).
So yes, you need to cater for any input from your dropdown, but for most input you can give an error.
The fact that you have restricted the user to only using values from a certain drop-down list is irrelevant. A technical user can capture the http request sent to your server before it leaves their network, alter it using a tool such as a local proxy server, and then continue it on it's way. Using the altered request, they can send parameter values that are not ones that you have specified in the drop down list. Developers have to have the mindset that client restrictions are often meaningless, as anything on a client can be altered. Server validation is required at every single point that client data enters. Attackers rely on the naivety of developers in this sole aspect.
It's best to use a parameterized query in order to ensure against SQL injection. In that case the look of the query would be this:
SELECT * FROM table WHERE size = ?
When you supply a query like the above with text that is unverified for integrity (the input isn't validated on the server) and it contains SQL injection code it will be handled correctly. In other words, the request will result in something like this happening in the database layer:
SELECT * FROM table WHERE size = 'DROP table;'
This will simply select 0 results as it returns which will make the query ineffective in actually causing harm to the database without the need for a whitelist, a verification check or other techniques. Please note that a responsible programmer will do security in layers, and will often validate in addition to parameterizing queries. However, there is very little cause to not parameterize your queries from a performance perspective and the security added by this practice is a good reason to familiarize yourself with parameterized queries.
Whatever is submitted from your form comes to your server as text across the wires. There is nothing stopping anyone from creating a bot to mimic the client or type it in from a terminal if they wanted to. Never assume that because you programmed the client it will act like you think it will. This is really easy to spoof.
Example of what can and will happen when you trust the client.
A hacker can bypass the browser completely, including Javascript form checking, by sending a request using Telnet. Of course, he will look at the code of your html page to get the field names he has to use, but from then on it's 'everything goes' for him. So, you must check all values submitted on the server as if they did not originate from your html page.
I understand that you should NEVER trust user input from a form, mainly due to the chance of SQL injection.
However, does this also apply to a form where the only input is from a dropdown(s) (see below)?
I'm saving the $_POST['size'] to a Session which is then used throughout the site to query the various databases (with a mysqli Select query) and any SQL injection would definitely harm (possibly drop) them.
There is no area for typed user input to query the databases, only dropdown(s).
<form action="welcome.php" method="post">
<select name="size">
<option value="All">Select Size</option>
<option value="Large">Large</option>
<option value="Medium">Medium</option>
<option value="Small">Small</option>
</select>
<input type="submit">
</form>
Yes you need to protect against this.
Let me show you why, using Firefox's developer console:
If you don't cleanse this data, your database will be destroyed. (This might not be a totally valid SQL statement, but I hope I've gotten my point across.)
Just because you've limited what options are available in your dropdown does not mean you've limited the data I can send your server.
If you tried to restrict this further using behaviour on your page, my options include disabling that behaviour, or just writing a custom HTTP request to your server which imitates this form submission anyway. There's a tool called curl used for exactly that, and I think the command to submit this SQL injection anyway would look something like this:
curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--" http://www.example.com/profile/save
(This might not be a totally valid curl command, but again, I hope I've gotten my point across.)
So, I'll reiterate:
NEVER trust user input. ALWAYS protect yourself.
Don't assume any user input is ever safe. It's potentially unsafe even if it arrives through some means other than a form. None of it is ever trustworthy enough to forgo protecting yourself from SQL injection.
You could do something as simple as the following example to make sure the posted size is what you expect.
$possibleOptions = array('All', 'Large', 'Medium', 'Small');
if(in_array($_POST['size'], $possibleOptions)) {
// Expected
} else {
// Not Expected
}
Then use mysqli_* if you are using a version of php >= 5.3.0 which you should be, to save your result. If used correctly this will help with sql injection.
As this question was tagged with sql-injection, here is an answer regarding this particular kind of attack:
As you've been told in the comments, you have to use prepared statements for the every single query involving any variable data, with no exceptions.
Regardless of any HTML stuff!
It is essential to understand that SQL queries have to be formatted properly regardless of any external factors, be it HTML input or anything else.
Although you can use white-listing suggested in other answers for the input validation purpose, it shouldn't affect any SQL-related actions - they have to remain the same, no matter if you validated HTML input or not. It means you still have to use prepared statements when adding any variables into the query.
Here you may find a thorough explanation, why prepared statements is a must and how to properly use them and where they aren't applicable and what to do in such case: The Hitchhiker's Guide to SQL Injection protection
Also, this question was tagged with mysqli. Mostly by accident, I presume, but anyway, I have to warn you that raw mysqli is not an adequate substitution for the old mysq_* functions. Simply because if used in the old style, it will add no security at all. While it's support for the prepared statements is painful and troublesome, to the point that average PHP user is just unable to endeavor them at all. Thus, if no ORM or some sort of abstraction library is option, then PDO is your only choice.
Yes.
Anyone can spoof anything for the values that actually get sent --
SO, for validating dropdown menus, you can just check to make sure that the value that you're working with was in the dropdown - something like this would be the best(most sanely paranoid) way:
if(in_array($_POST['ddMenu'], $dropDownValues){
$valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)];
} else {
die("effin h4x0rs! Keep off my LAMP!!");
}
One way of protecting against users changing your drop downs using the console is to only use integer values in them. Then you can validate that the POST value contains an integer, and use an array to convert that to text when needed. E.g:
<?php
// No, you don't need to specify the numbers in the array but as we're using them I always find having them visually there helpful.
$sizes = array(0 => 'All', 1 => 'Large', 2 => 'Medium', 3 => 'Small');
$size = filter_input(INPUT_POST, "size", FILTER_VALIDATE_INT);
echo '<select name="size">';
foreach($sizes as $i => $s) {
echo '<option value="' . $i . '"' . ($i == $size ? ' selected' : '') . '>' . $s . '</option>';
}
echo '</select>';
Then you can use $size in your query with knowledge that it will only ever contain FALSE or an integer.
The other answers already cover what you need to know. But maybe it helps to clarify some more:
There are TWO THINGS you need to do:
1. Validate form data.
As Jonathan Hobbs' answer shows very clearly, the choice of html element for the form input does not do any reliable filtering for you.
Validation is usually done in a way that does not alter the data, but that shows the form again, with the fields marked as "Please correct this".
Most frameworks and CMSes have form builders that help you with this task. And not just that, they also help against CSRF (or "XSRF"), which is another form of attack.
2. Sanitize/Escape variables in SQL statements..
.. or let prepared statements do the job for you.
If you build a (My)SQL statement with any variables, user-provided or not, you need to escape and quote these variables.
Generally, any such variable you insert into a MySQL statement should be either a string, or something that PHP can be reliably turn into a string that MySQL can digest. Such as, numbers.
For strings, you then need to choose one of several methods to escape the string, that means, replace any characters that would have side effects in MySQL.
In old-school MySQL + PHP, mysql_real_escape_string() does the job. The problem is that it is far too easy to forget, so you should absolutely use prepared statements or query builders.
In MySQLi, you can use prepared statements.
Most frameworks and CMSes provide query builders that help you with this task.
If you are dealing with a number, you could omit the escaping and the quotes (this is why the prepared statements allow to specify a type).
It is important to point out that you escape the variables for the SQL statement, and NOT for the database itself. The database will store the original string, but the statement needs an escaped version.
What happens if you omit one of these?
If you don't use form validation, but you do sanitize your SQL input, you might see all kinds of bad stuff happening, but you won't see SQL injection! (*)
First, it can take your application into a state you did not plan for. E.g. if you want to calculate the average age of all users, but one user gave "aljkdfaqer" for the age, your calculation will fail.
Secondly, there can be all kinds of other injection attacks you need to consider: E.g. the user input could contain javascript or other stuff.
There can still be problems with the database: E.g. if a field (database table column) is limited to 255 characters, and the string is longer than that. Or if the field only accepts numbers, and you attempt to save a non-numeric string instead. But this is not "injection", it is just "crashing the application".
But, even if you have a free text field where you allow any input with no validation at all, you could still save this to the database just like that, if you properly escape it when it goes to a database statement. The problem comes when you want to use this string somewhere.
(*) or this would be something really exotic.
If you don't escape variables for SQL statements, but you did validate form input, then you can still see bad stuff happening.
First, you risk that when you save data to the database and load it again, it won't be the same data anymore, "lost in translation".
Secondly, it can result in invalid SQL statements, and thus crash your application. E.g. if any variable contains a quote or double quote character, depending which type of quote you use, you will get invalid MySQL statement.
Thirdly, it can still cause SQL injection.
If your user input from forms is already filtered / validated, intentional SQl injection may become less likely, IF your input is reduced to a hardcoded list of options, or if it is restricted to numbers. But any free text input can be used for SQL injection, if you don't properly escape the variables in SQL statements.
And even if you have no form input at all, you could still have strings from all kinds of sources: Read from the filesystem, scraped from the internet, etc. Noone can guarantee that these strings are safe.
Your web browser does not "know" that it is receiving a page from php, all it sees is html. And the http layer knows even less than that. You need to be able to handle nearly any kind of input that can cross the http layer (luckily for most input php will already give an error).
If you are trying to prevent malicious requests from messing up your db, then you need to assume that the guy on the other end knows what he is doing, and that he is not limited to what you can see in your browser under normal circumstances (not to mention what you can fiddle with a browser's developer tools).
So yes, you need to cater for any input from your dropdown, but for most input you can give an error.
The fact that you have restricted the user to only using values from a certain drop-down list is irrelevant. A technical user can capture the http request sent to your server before it leaves their network, alter it using a tool such as a local proxy server, and then continue it on it's way. Using the altered request, they can send parameter values that are not ones that you have specified in the drop down list. Developers have to have the mindset that client restrictions are often meaningless, as anything on a client can be altered. Server validation is required at every single point that client data enters. Attackers rely on the naivety of developers in this sole aspect.
It's best to use a parameterized query in order to ensure against SQL injection. In that case the look of the query would be this:
SELECT * FROM table WHERE size = ?
When you supply a query like the above with text that is unverified for integrity (the input isn't validated on the server) and it contains SQL injection code it will be handled correctly. In other words, the request will result in something like this happening in the database layer:
SELECT * FROM table WHERE size = 'DROP table;'
This will simply select 0 results as it returns which will make the query ineffective in actually causing harm to the database without the need for a whitelist, a verification check or other techniques. Please note that a responsible programmer will do security in layers, and will often validate in addition to parameterizing queries. However, there is very little cause to not parameterize your queries from a performance perspective and the security added by this practice is a good reason to familiarize yourself with parameterized queries.
Whatever is submitted from your form comes to your server as text across the wires. There is nothing stopping anyone from creating a bot to mimic the client or type it in from a terminal if they wanted to. Never assume that because you programmed the client it will act like you think it will. This is really easy to spoof.
Example of what can and will happen when you trust the client.
A hacker can bypass the browser completely, including Javascript form checking, by sending a request using Telnet. Of course, he will look at the code of your html page to get the field names he has to use, but from then on it's 'everything goes' for him. So, you must check all values submitted on the server as if they did not originate from your html page.
I am trying to figure out which functions are best to use in different cases when inputting data, as well as outputting data.
When I allow a user to input data into MySQL what is the best way to secure the data to prevent SQL injections and or any other type of injections or hacks someone could attempt?
When I output the data as regular html from the database what is the best way to do this so scripts and such cannot be run?
At the moment I basically only use
mysql_real_escape_string();
before inputting the data to the database, this seems to work fine, but I would like to know if this is all I need to do, or if some other method is better.
And at the moment I use
stripslashes(nl2br(htmlentities()))
(most of the time anyways) for outputting data. I find these work fine for what I usually use them for, however I have run into a problem with htmlentities, I want to be able to have some html tags output respectively, for example:
<ul></ul><li></li><bold></bold>
etc, but I can't.
any help would be great, thanks.
I agree with mikikg that you need to understand SQL injection and XSS vulnerabilities before you can try to secure applications against these types of problems.
However, I disagree with his assertions to use regular expressions to validate user input as a SQL injection preventer. Yes, do validate user input insofar as you can. But don't rely on this to prevent injections, because hackers break these kinds of filters quite often. Also, don't be too strict with your filters -- plenty of websites won't let me log in because there's an apostrophe in my name, and let me tell you, it's a pain in the a** when this happens.
There are two kinds of security problems you mention in your question. The first is a SQL injection. This vulnerability is a "solved problem." That is, if you use parameterized queries, and never pass user supplied data in as anything but a parameter, the database is going to do the "right thing" for you, no matter what happens. For many databases, if you use parameterized queries, there's no chance of injection because the data isn't actually sent embedded in the SQL -- the data is passed unescaped in a length prefixed or similar blob along the wire. This is considerably more performant than database escape functions, and can be safer. (Note: if you use stored procedures that generate dynamic SQL on the database, they might also have injection problems!)
The second problem you mention is the cross site scripting problem. If you want to allow the user to supply HTML without entity escaping it first, this problem is an open research question. Suffice to say that if you allow the user to pass some kinds of HTML, it's entirely likely that your system will suffer an XSS problem at some point to a determined attacker. Now, the state of the art for this problem is to "filter" the data on the server, using libraries like HTMLPurifier. Attackers can and do break these filters on a regular basis; but as of yet nobody has found a better way of protecting the application from these kinds of things. You may be better off only allowing a specific whitelist of HTML tags, and entity encoding anything else.
This is one of the most problematic task today :)
You need to know how SQL injection and other attackers methods works. There are very detailed explanation of each method in https://www.owasp.org/index.php/Main_Page and also whole security framework for PHP.
Using specific security libraries from some framework are also good choice like in CodeIgniter or Zend.
Next, use REGEXP as much as you can and stick pattern rules to specific input format.
Use prepared statements or active records class of your framework.
Always cast your input with (int)$_GET['myvar'] if you really need numeric values.
There are so many other rules and methods to secure your application, but one golden rule is "never trust user's input".
In your php configuration, magic_quotes_gpc should be off. So you won't need stripslashes.
For SQL, take a look at PDO's prepared statements.
And for your custom tags, as there are only three of them, you can do a preg_replace call after the call of htmlentities to convert those back before your insert them into the database.
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.
I've got a chunk of code that validates a user's username and password, which goes something like this:
$sql = "SELECT *
FROM user
WHERE
username='{$_POST['username']}' AND
password=MD5('{SALT}{$_POST['password']}')";
Is this any more/less secure than doing it like this?
$sql = "SELECT *
FROM user
WHERE
username='{$_POST['username']}' AND
password='".md5(SALT.$_POST['password'])."'";
Regardless of where/if escaping is done, is the first method vulnerable to sql injection attacks? Would the answer be the same for other database engines besides MySQL?
You should use prepared statements instead and have a look at this question.
Speaking about injection, both ways are secure, if you properly escape variables.
The first case will be more vulnerable, if you use complete query logging, and so the password will appear as plain text.
Besides, if your system is affected by some virus that works as proxy between your script and database, it'll be able to catch your password.
One last problem that you may encounter (quite rarely, in fact), is when the system is inflicted with a virus, that reads sensible data from memory.
I hope this makes sense.
Oh god, please tell me you're doing some type of mysql_escape_string or mysql_real_escape_string or AT LEAST addslashes or addcslashes to any $_POST variables before you insert them into a raw MySQL statement?
I think the most secure way to do this is to:
a) use filter_var or preg_replace to get rid of extraneous characters from the $_POST['username']
b) SELECT the row by the username from MySQL (also grabbing the digested password)
c) compare the message digested version of the password from the $_POST to that of the retrieved row (assuming you don't leave your password cleartext) in your application code, not in the SQL statement
If you do it this way, there's only 1 possible place for injection (username), and it's pretty impossible when you're doing a preg_replace( '/\W/', '', $_POST['username'] ) which removes anything not A-Za-z0-9_- (or change to your username whitelist of characters).
However, if you're doing rock-solid proper sanitization, it really doesn't matter where you do your comparison. Theoretically, though, I'd allow for the least possible interaction with user input and raw SQL statements (i.e. only SELECTing by username and comparing outside of your DB).
To start off with MD5 is prevent to be an insecure algorithm and should never be used for passwords. You should use a staled sha256 and most databases do not have this function call. But even if the database did I think its a bad idea. Not a very bad idea, but its best to keep as few copies of your password around. Often the database can be on a completely different machine, and if that machine where compromised then the attacker could obtain clear text passwords by looking at the quires. In terms of SQL Injection, there is no difference in security and judging by your queries you should be more worried about SQL injection.
Regardless of where/if escaping is done, is the first method vulnerable to sql injection attacks?
SQL injection will not occur if proper escaping and sanitizing takes place
Would the answer be the same for other database engines besides MySQL?
I think you should look more at the expense taken to perform one action over another. The first method would take less time to execute than the second method, ceteris paribus.