I'm working on a web app and I came across this code snippit
$email=$_POST['email'];
$pass=$_POST['pass'];
$pass=md5($pass);
$query=mysql_real_escape_string($email,$link);
//echo $query."<br>";
$sql=mysql_query("SELECT pass FROM users WHERE email='".$email."'",$link);
if($row=mysql_fetch_array($sql))
{
I think the programmer intended $query=mysql_real_escape_string($email,$link); to be $email=mysql_real_escape_string($email,$link);
Do I have the right idea here?
Yes, you're absolutely right - just correct that part, like you said, by changing it to
$email = mysql_real_escape_string($email, $link);
, and that will protect against SQL injection there.
On a side note, I suggest you use hash("sha512", xxx) instead of md5 because MD5 is becoming obsolete. If your column size doesn't allow for that though and you don't have the ability to change it, it's still OK.
Yes, $email is set, but then not filtered, it's used directly in the query. As you pointed out, it looks like an error as the filtered value is not being used in the query.
to prevent from blind SQL , wrap your POST data with tow more filters:
$email = mysql_real_escape_string(strip_tags(stripslashes($email)), $link)
Related
Hello I need help finding a way to protect from sql injection on my current project, Im making bash tutorial site but ive run into a problem. I put most my content in database and depending on what link the user clicks it will pull different data onto the page.
This is how im doing it
apt-get <br>
And on bash_cmds.php
<?php
require_once("connections/connect.php");
$dbcon = new connection();
$bash = $_REQUEST['id'];
$query2 = "SELECT * FROM bash_cmds WHERE id = $bash ";
$results = $dbcon->dbconnect()->query($query2);
if($results){
while($row = $results->fetch(PDO::FETCH_ASSOC)){
$bash_cmd = $row['bash_command'];
$how = $row['how_to'];
}
} else { return false; }
?>
<?php echo $bash_cmd ?>
<br />
<table>
<tr><td><?php echo $how ?> </td></tr>
</table>
However this leaves me vulnerable to sql injection, I ran sqlmap and was able to pull all databases and tables. Can someone please help I would appreciate it a lot the infomation would be invaluable.
There are a couple of ways to do this. I believe the best way is to use some database abstraction layer (there's a good one built into PHP called PDO) and use its prepared statements API. You can read more about PDO here, and you can see the particular function which binds a value to a ? placeholder here.
Alternatively, you could use the mysqli_real_escape_string API function, which should escape any SQL inside your $bash variable.
Of course, in this particular case, simply ensuring the ID is an integer with (int) or intval() would be good enough, but the danger of using this approach in general is that it's easy to forget to do this one time, which is all it takes for your application to be vulnerable. If you use something like PDO, it's more "safe by default," one might say - it's more difficult to accidentally write vulnerable code.
You could bind the values to a prepared statement.
But for something simple as a numeric variable a cast to an integer would be good enough:
$bash = (int) $_REQUEST['id'];
Using this, only a number would get stored into $bash. Even if someone enters ?id=--%20DROP%20TABLE%20xy;, as this will get casted to 1;
I've found one of the easiest ways to protect against injection is to use prepared statements.
You can do this in PHP via PDO, as CmdrMoozy suggested.
Prepared statements are more secure because the placeholders ? can only represent values, and not variables (ie: will never be interpreted as a table name, server variable, column name, etc. It {currently} can't even represent a list of values). This immediately makes any modification to the logic of the query immutable, leaving only possible unwanted values as injection possibilities (looking for an id of 'notanid'), which in most cases isn't a concern (they'd just get a blank/wrong/error page, their fault for trying to hack your site).
Addendum:
These restrictions are what is in place when the prepared statements are done on the server. When prepared statements are simulated by a library instead of actually being server side the same may not be true, but often many of these are emulated.
i am trying to get data from input box and pass it to the database to show appropriate records and results but need help not able to get result
<html>
<body>
</body>
</html>
<?php>
$prod_name = $_POST["name_of_the_product"];
echo [$prod_name];
$db_host = "localhost";
$db_username = "acwj_price";
$db_pass = "";
$db_name = "acwj_price";
mysql_connect("$db_host","$db_username","$db_pass") or die ("Please Try Again");
mysql_select_db("wikiacwj_price") or die ("no data");
$sql = mysql_query("SELECT * FROM price_comparsion where product_name="prod_name"");
//write the results
while ($row = mysql_fetch_array($sql)) {
echo $row['product_name'];}
?>
</body>
</html>
Warning: CARGO CULT PROGRAMMING DETECTED!. You've got syntax errors galore, you've got SQL injection holes, you've got useless error handling, blah blah blah. In other words, the code is a mess.
1) echo [$prod_name]; what are the [] for here? This is a flat out syntax error
2) mysql_connect("$db_host" etc... - why the "" around variables? You'r creating a new empty string, embedding another string inside that - a total waste of cpu cycles.
3) or die ("Please Try Again"); - of what use is it to tell your site's user to try again? If your code can't log into mysql, how is the user supposed to fix this? Hammering on reload won't make an invalid mysql login magically start working again. If you're the only user of the code, at least have a useful error message output, explaining why the script is dying, e.g. or die(mysql_error()).
4) ... where product_name="prod_name""). You've got another horrendous syntax error here - you cannot embed quotes within a string that is built with the same type of quotes you're trying to embed.
4a) Should that be ... product_name='$prod_name'", perhaps, so you're actually embedding the form value that was passed in?
4b) $prod_name is now your SQL injection source, and you should have AT MINIMUIM $prod_name = mysql_real_escape_string($_POST['name_of_product']), and have it somewhere AFTER you connect to the DB, since m_r_e_s() only works when you have an active DB connection.
We need more context to give you a solid answer, however reviewing your code I've found the following things that are causing problems:
echo [$prod_name]; is incorrect - should be echo $prod_name;
Also, the mysql_connect is incorrect - should be: mysql_connect($db_host,$db_username,$db_pass) or die ("Please Try Again");
(you should not have quotes around the variables)
And the sql statement is incorrect - should be:
$sql = mysql_query("SELECT * FROM price_comparsion where product_name='" . mysql_real_escape_string($prod_name) . "'");
(corrected the quoting, changed to pass in the variable, and added mysql_real_escape_string as minimum sql error prevention)
Note: This does NOT reflect best practices with SQL - there's all sorts of SQL Injection attack vulnerabilities in the original code - this code is only revised to work. If you will be writing code like this, you should should read about SQL Injection prevention. There's plenty of good information on StackOverflow - here's just one example: SQL Injection, Quotes and PHP
[UPDATED] with new code "sql_real_escape_string()"
[UPDATED] if anyone wants to look at the site its at Test site
[UPDATED] with the while code showing any results via echo
Hello All,
I have looked at many posts on this matter, but simply cannot understand why the following code doesn't work:
$username = $_POST['username'];
// get the record of the user, by looking up username in the database.
$query = sprintf("SELECT UserName, Password FROM userlogin WHERE UserName='%s'", mysql_real_escape_string($username));
$result = mysqli_query($dbc, $query) or
die ("Error Querying Database for: " . $query .
"<br />Error Details: " . mysql_error() . "<br/>" . $result);
while ($row = mysqli_fetch_assoc($result))
{
Echo($row['UserName']);
}
The Code seems to be correct... the database is working perfectly (for input purposes) and the connection is a shared connection applied with require_once('databaseconnection.php'); that is working for the registration side of things.
like normal I'm sure this is something simple that I have overlooked but cannot for the life of me see it!
I do not get any error messages from the myssql_error() its simply blank.
any help would be much appreciated.
Regards
Check the username you try to query as it might be empty. Do you really use a post-request to run that script? How do you verify that it does not work? What do you do with $data after the query?
If just nothing seems to happen it is likely your query did not match any record. Check for whitespace and case of the username you are looking for.
Mind those warnings:
Use a prepared statement or at least sql-escape any user-input before using it in sql.
Don't use die in serious code only for debugging.
The $data will contain a result object. You need to iterate over it using something like mysqli_fetch_assoc($data).
Also, you can interpolate variables directly into double quoted strings - i.e. UserName='".$username."'" could be written more cleanly as UserName='$username' rather than breaking out of the string.
Also, please sanitize your input - all input is evil - using mysqli_real_escape_string() function. You've got a SQL injection exploit waiting to happen here.
Bear in mind that it's a very good idea to validate all data to be inserted into a database.
Very often you have problems with query itself, not implementation. Try it in phpMyAdmin first and see if there are any problems.
Check server logs.
BY THE WAY: Never put variables from POST to query! That's definitely a SQL injection'
You might have some issue with the query.
Have you Tried to echo the $query and run that directly with mysql client or workbench?
This piece of code seems ok. That is, if $dbc contains an actual database connection. But the choice of naming that variable $data while the function actually returns a result object or a boolean, indicates that you may process the data wrong.
If that is not the problem, we'll definately have to see more code.
Try printing $data variable instead of printing only query. Check, whether you are able to get any error messages. If you could see any data then you should use mysql fetch function to iterate things. Try it.
So I'm a slightly seasoned php developer and have been 'doin the damn thing' since 2007; however, I am still relatively n00bish when it comes to securing my applications. In the way that I don't really know everything I know I could and should.
I have picked up Securing PHP Web Applications and am reading my way through it testing things out along the way. I have some questions for the general SO group that relate to database querying (mainly under mysql):
When creating apps that put data to a database is mysql_real_escape_string and general checking (is_numeric etc) on input data enough? What about other types of attacks different from sql injection.
Could someone explain stored procedures and prepared statements with a bit more info than - you make them and make calls to them. I would like to know how they work, what validation goes on behind the scenes.
I work in a php4 bound environment and php5 is not an option for the time being. Has anyone else been in this position before, what did you do to secure your applications while all the cool kids are using that sweet new mysqli interface?
What are some general good practices people have found to be advantageous, emphasis on creating an infrastructure capable of withstanding upgrades and possible migrations (like moving php4 to php5).
Note: have had a search around couldn't find anything similar to this that hit the php-mysql security.
Javier's answer which has the owasp link is a good start.
There are a few more things you can do more:
Regarding SQL injection attacks, you can write a function that will remove common SQL statements from the input like " DROP " or "DELETE * WHERE", like this:
*$sqlarray = array( " DROP ","or 1=1","union select","SELECT * FROM","select host","create table","FROM users","users WHERE");*
Then write the function that will check your input against this array. Make sure any of the stuff inside the $sqlarray won't be common input from your users. (Don't forget to use strtolower on this, thanks lou).
I'm not sure if memcache works with PHP 4 but you can put in place some spam protection with memcache by only allowing a certain remote IP access to the process.php page X amount of times in Y time period.
Privileges is important. If you only need insert privileges (say, order processing), then you should log into the database on the order process page with a user that only has insert and maybe select privileges. This means that even if a SQL injection got through, they could only perform INSERT / SELECT queries and not delete or restructuring.
Put important php processing files in a directory such as /include. Then disallow all IPs access to that /include directory.
Put a salted MD5 with the user's agent + remoteip + your salt in the user's session, and make it verify on every page load that the correct MD5 is in their cookie.
Disallow certain headers (http://www.owasp.org/index.php/Testing_for_HTTP_Methods_and_XST) . Disallow PUT(If you dont need file uploads)/TRACE/CONNECT/DELETE headers.
My recommendations:
ditch mysqli in favor of PDO (with mysql driver)
use PDO paremeterized prepared statements
You can then do something like:
$pdo_obj = new PDO( 'mysql:server=localhost; dbname=mydatabase',
$dbusername, $dbpassword );
$sql = 'SELECT column FROM table WHERE condition=:condition';
$params = array( ':condition' => 1 );
$statement = $pdo_obj->prepare( $sql,
array( PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY ) );
$statement->execute( $params );
$result = $statement->fetchAll( PDO::FETCH_ASSOC );
PROs:
No more manual escaping since PDO does it all for you!
It's relatively easy to switch database backends all of a sudden.
CONs:
i cannot think of any.
I don't usually work with PHP so I can't provide advice specifically targeted to your requirements, but I suggest that you take a look at the OWASP page, particularly the top 10 vulnerabilities report: http://www.owasp.org/index.php/Top_10_2007
In that page, for each vulnerability you get a list of the things you can do to avoid the problem in different platforms (.Net, Java, PHP, etc.)
Regarding the prepared statements, they work by letting the database engine know how many parameters and of what types to expect during a particular query, using this information the engine can understand what characters are part of the actual parameter and not something that should be parsed as SQL like an ' (apostrophe) as part of the data instead of a ' as a string delimiter. Sorry I can not provide more info targeted at PHP, but hope this helps.
AFAIK, PHP/mySQL doesn't usually have parameterized queries.
Using sprintf() with mysql_real_escape_string() should work pretty well. If you use appropriate format strings for sprintf() (e.g. "%d" for integers) you should be pretty safe.
I may be wrong, but shouldn't it be enough to use mysql_real_escape_string on user provided data?
unless when they are numbers, in which case you should make sure they are in fact numbers instead by using for example ctype_digit or is_numeric or sprintf (using %d or %u to force input into a number).
Also, having a serarate mysql user for your php scripts that can only SELECT, INSERT, UPDATE and DELETE is probably a good idea...
Example from php.net
Example #3 A "Best Practice" query
Using mysql_real_escape_string() around each variable prevents SQL Injection. This example demonstrates the "best practice" method for querying a database, independent of the Magic Quotes setting.
The query will now execute correctly, and SQL Injection attacks will not work.
<?php
if (isset($_POST['product_name']) && isset($_POST['product_description']) && isset($_POST['user_id'])) {
// Connect
$link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password');
if(!is_resource($link)) {
echo "Failed to connect to the server\n";
// ... log the error properly
} else {
// Reverse magic_quotes_gpc/magic_quotes_sybase effects on those vars if ON.
if(get_magic_quotes_gpc()) {
$product_name = stripslashes($_POST['product_name']);
$product_description = stripslashes($_POST['product_description']);
} else {
$product_name = $_POST['product_name'];
$product_description = $_POST['product_description'];
}
// Make a safe query
$query = sprintf("INSERT INTO products (`name`, `description`, `user_id`) VALUES ('%s', '%s', %d)",
mysql_real_escape_string($product_name, $link),
mysql_real_escape_string($product_description, $link),
$_POST['user_id']);
mysql_query($query, $link);
if (mysql_affected_rows($link) > 0) {
echo "Product inserted\n";
}
}
} else {
echo "Fill the form properly\n";
}
Use stored procedures for any activity that involves wrinting to the DB, and use bind parameters for all selects.
Okay I have two variables in PHP
$username;
$password;
which are initialized to the data retrieved from $_POST variable :)
I have this SQL query
$sql = "SELECT * FROM users WHERE username = '" . $username . "' AND password = '" . $password . "')";
But this doesn't works and returns me nothing :(
Can you instruct me into the right direction. Please?
The query has a closing parenthesis on the end for no reason, it won't work.
What's wrong with it?
Everything, unfortunately. In particular it's open to SQL injection attacks.
If that's a verbatim cut&paste, then the reason it's not actually working is a trailing closing bracket. Presumably you're not checking for errors when you call this?
Using the base MySQL API it should be:
$sth = $db->prepare("SELECT COUNT(*) FROM users WHERE username = ? AND password = ?");
$sth->execute($username, $password);
list($count) = $sth->fetchrow();
$authorized = ($count > 0);
or similar (code untested, E&OE, etc...)
eeek! sql injection for one!
EDIT: What's your favorite "programmer" cartoon?
Why is there a stray ) at the end of your query? It shouldn't be there.
Oh, and thirded on SQL injection. BAD.
First of all, never, ever do it like this. Please read about SQL injection and don't write any SQL until you have understood what it says. Sorry, but this is really essential.
That said, your query contains a closing bracket. That looks like a syntax error. Do you get an error executing it?
There's an extra parenthesis on the right hand side of the query.
Also, if you do not sanitize your code properly you're going to be vulnerable to SQL injection. You should really be using parameterized queries, but in lieu of that at least use mysql_real_escape_string() on $username and $password.
Also, as a bit of ghost debugging, it's very possible that your passwords are MD5 hashed in the database, since you should never store them in plain text.
Try:
$username = mysql_real_escape_string($_POST["username"]);
$password = md5($_POST["password"]);
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
You seem to have an excess closing parenthesis at the end of your query string.
[Edit] - for those screaming SQL injection attacks: we don't know what the user has done with their variables before using them in the query. How about benefit of doubt? ;-)
In addition to all the other problems noted. The Password in the Users table is stored encrypted. Unless you've run the Password through the MySQL password encryptor, you will never see any data from this query as the passwords won't match.