This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 7 years ago.
i make PHP site
With USER / Pass Login
But USer can Skip This Page BY Use
'=' 'or'
‘ or 1=1
Like this
Code Here In File Login_Check.php
`
include("includeszzz/host_conf.php");
include("includeszzz/mysql.lib.php");
$obj=new connect;
$obj1=new connect;
$username=$_GET["username"];
$password=$_GET["password"];
//echo $username;
//echo $password;
$sql="select username from admin where username='$username'";
$obj->query($sql);
$U_num=$obj->num_rows();
//echo $U_num;
if($U_num!=0) {
$sql1="select password from admin where username='$username' and password='$password'";
$obj1->query($sql1);
$P_num=$obj1->num_rows();
if($P_num!=0) {
session_start();
$_SESSION["zizo"]="$username";
//header("location: welcome.php");
echo "1";
} else {
echo "Invalid Password Please Try Again";
}
} else {
echo "Invalid Username Please Try Again";
}
`
You want to avoid using user data in queries without any type of sanitation.
http://php.net/manual/en/security.database.sql-injection.php
"Example #5 A more secure way to compose a query..."
<?php
settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
// please note %d in the format string, using %s would be meaningless
$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;",
$offset);
?>
If the database layer doesn't support binding variables then quote
each non numeric user supplied value that is passed to the database
with the database-specific string escape function (e.g.
mysql_real_escape_string(), sqlite_escape_string(), etc.). Generic
functions like addslashes() are useful only in a very specific
environment (e.g. MySQL in a single-byte character set with disabled
NO_BACKSLASH_ESCAPES) so it is better to avoid them.
Do not print out any database specific information, especially about
the schema, by fair means or foul. See also Error Reporting and Error
Handling and Logging Functions.
You may use stored procedures and previously defined cursors to
abstract data access so that users do not directly access tables or
views, but this solution has another impacts.
Additionally, you can make use of Binding Parameters:
http://php.net/manual/en/pdo.prepared-statements.php
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
// insert another row with different values
$name = 'two';
$value = 2;
$stmt->execute();
?>
Related
This question already has answers here:
What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must be of type mysqli_result and such
(1 answer)
Reference - What does this error mean in PHP?
(38 answers)
Closed 2 years ago.
I have created a login page however I'm having a hard time authenticating the user. I am able to establish a connection however my sanitation is not working. I'm not sure if its the select statement or HTML related. I've played around with different SELECT statements and troubleshooted the code further up but that doesn't seem to be the problem.
<?php
// Now I check if the data from the login form was submitted, isset() will check if the data exists.
if (!isset($_POST['username'], $_POST['user_password'])) {
echo 'error2';
// Could not get the data that should have been sent.
exit('Please fill both the username and password fields!');
}
// Prepare our SQL, preparing the SQL statement will prevent SQL injection.
if ($stmt = $con->prepare("SELECT id, username, user_password FROM user_info WHERE username = ?")) {
// Bind parameters (s = string, i = int, b = blob, etc), in our case the username is a string so we use "s"
$stmt->bind_param('s', $_POST['username']);
$stmt->execute();
// Store the result so we can check if the account exists in the database.
$stmt->store_result();
if ($stmt->num_rows > 0) {
$stmt->bind_result($id, $user_password);
$stmt->fetch();
// Account exists, now we verify the password.
// Note: remember to use password_hash in your registration file to store the hashed passwords.
if (password_verify($_POST['user_password'], $user_password)) {
// Verification success! User has loggedin!
// Create sessions so we know the user is logged in, they basically act like cookies but remember the data on the server.
session_regenerate_id();
$_SESSION['loggedin'] = true;
$_SESSION['name'] = $_POST['username'];
$_SESSION['id'] = $id;
echo 'Welcome ' . $_SESSION['name'] . '!';
} else {
echo 'Incorrect password!';
}
} else {
echo 'Incorrect username!';
}
$stmt->close();
} else {
echo 'error3';
}
You're selecting 3 columns in SELECT id, username, user_password but you're only binding two variables in $stmt->bind_result($id, $user_password);. This mismatch will cause an error.
There's no need to select username since that's the column you're matching in the WHERE clause. Change the select list to SELECT id, user_password to match the variables you're binding.
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Can I mix MySQL APIs in PHP?
(4 answers)
Closed 3 years ago.
I am very new to mysqli earlier i am writing queries in mysql but mysqli is more advanced so, i am first time using it.
Below is my php code.
function clean($str) {
$str = #trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return mysql_real_escape_string($str);
}
$email = clean($_POST['email']);
$password = clean($_POST['password']);
//$password =md5($password);
if(empty($res['errors'])) {
$result = $mysqli->query("SELECT uid FROM users where email='$email' and password = '$password'");
if($result->num_rows == 1){
$res['success'] = true;
}
else{
array_push($res['errors'], 'Invalid login details');
$res['success'] = false;
}
}else{
$res['success'] = false;
}
echo json_encode($res);
}
clean function is not working as expected because sql queries return false if i enter username and password correct.
So, it seems like this is not valid in mysqli case.
I checked this link PHP MySQLI Prevent SQL Injection and got to know that we have to prepare query.
I can see there is an example but i am not able to understand how to prepare/bind if i have to use two or more form data.
Thanks for your time.
Updated code
$result = $mysqli->prepare("SELECT uid FROM users where email=:email and password = :password");
$result->execute([
':email' => $email,
':password' => $password]);
//$result->execute();
if($result->num_rows == 1){
//if(mysqli_num_rows($result) === 1) {
$res['success'] = true;
}
else{
array_push($res['errors'], 'Invalid login details');
$res['success'] = false;
}
As already stated in comments, you need to be consistent with your API choice. You can't mix APIs in PHP.
You started out with mysqli_*, so I'll continue with that. You had some mysql_* and PDO in there, and it might not be a bad idea to use PDO over mysqli_* - but if your server supports mysqli_*, there is nothing wrong with using that. See Choosing an API and decide for yourself (just stay away from mysql_*, it's outdated).
Using mysqli_*, you connect to the database like this (you didn't show your connection).
$mysqli = new mysqli("host", "username", "password", "database");
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: (".$mysqli->connect_errno.") ".$mysqli->connect_error;
}
$mysqli->set_charset("utf8");
As for preventing SQL injection in it self, all you need is to use prepared statements. You can still clean or sanitize your data if there are some kind of values you don't want sitting in your tables - but that's kind of another discussion.
You also need to know if your passwords are hashed in the database. They really should be, and you should be using password_hash($password, $algorithm) and password_verify($password, $hash) if you're on PHP5.5 and above (if not, look into something like password_compat).
You need to be consistent with your hashes too, you can't insert it with md5 and selecting it with no hash. It all needs to be the same. Because if you are selecting an md5 hash, and comparing it to an unhashed string, they will be different, and the query fails.
I'm showing you an example of using password_verify(), so that means that the password stored in the database will also need to be stored with password_hash() (or your query fails).
if ($stmt = $mysqli->prepare("SELECT uid, password FROM users where email=?")) {
$stmt->bind_param("s", $_POST['email']); // Bind variable to the placeholder
$stmt->execute(); // Execute query
$stmt->bind_result($userID, $password); // Set the selected columns into the variables
$stmt->fetch(); // ...and fetch it
if ($stmt->num_rows) {
if (password_verify($_POST['password'], $password)) {
// Password was correct and matched the email!
} else {
// Password was incorrect...
}
} else {
// Accountname not found
}
}
This is just a basic example, but it will get you started. Never trust user input, use prepared statements.
You can bind more variables like so:
$stmt = $mysqli->prepare("SELECT uid FROM users where email= ? and password = ?");
$stmt->bind_param('ss', $email, $password);
/* execute prepared statement */
$stmt->execute();
As you can see, you can expand on the bind_param() function. You can also add different type of variables:
i corresponding variable has type integer
d corresponding variable has type double
s corresponding variable has type string
b corresponding variable is a blob and will be sent in packets
From: http://php.net/manual/en/mysqli-stmt.bind-param.php
First of all, I suggest you learn PDO instead of MySQLi, just because it supports more drivers.
Second, you use mysql_real_escape_string, as you might see, that is a MySQL function, not a MySQLi function.
So where you have:
$result = $mysqli->query("SELECT uid FROM users where email='$email' and password = '$password'");
You should do something like:
<?php
$stmt = $dbConnection->prepare("SELECT uid FROM users where email = :email AND password = :password");
try{
$stmt->execute([
':email' => $email,
':password' => $password
]);
}
catch(Exception $e){
echo $e->getMessage(); //Remove when putting online
}
if($stmt->num_rows){
$res['success'] = true;
}
?>
You're presently mixing MySQL APIs/functions with mysql_real_escape_string(), then num_rows and then a PDO binding method where email=:email and password = :password which seems to have been taken from another answer given for your question.
Those different functions do NOT intermix.
You must use the same one from connection to querying.
Consult: Can I mix MySQL APIs in PHP?
It looks like you're wanting to setup a login script. I suggest you use the following and pulled from one of ircmaxell's answers:
Pulled from https://stackoverflow.com/a/29778421/
Just use a library. Seriously. They exist for a reason.
PHP 5.5+: use password_hash()
PHP 5.3.7+: use password-compat (a compatibility pack for above)
All others: use phpass
Don't do it yourself. If you're creating your own salt, YOU'RE DOING IT WRONG. You should be using a library that handles that for you.
$dbh = new PDO(...);
$username = $_POST["username"];
$email = $_POST["email"];
$password = $_POST["password"];
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $dbh->prepare("insert into users set username=?, email=?, password=?");
$stmt->execute([$username, $email, $hash]);
And on login:
$sql = "SELECT * FROM users WHERE username = ?";
$stmt = $dbh->prepare($sql);
$result = $stmt->execute([$_POST['username']]);
$users = $result->fetchAll();
if (isset($users[0]) {
if (password_verify($_POST['password'], $users[0]->password) {
// valid login
} else {
// invalid password
}
} else {
// invalid username
}
It's safer and uses a safe password hashing method, rather than what you seem to want to use is MD5 $password =md5($password); and is no longer considered safe to use now.
References:
PDO connection http://php.net/manual/en/pdo.connections.php
PDO error handling http://php.net/manual/en/pdo.error-handling.php
To check if a user exists, you can see one of my answers https://stackoverflow.com/a/22253579/1415724
http://php.net/manual/en/mysqli.error.php
http://php.net/manual/en/function.error-reporting.php
Sidenote: If you do go that route, remember to read the manuals and that your password column is long enough to hold the hash. Minimum length is 60, but they recommend 255.
It is also unclear if your HTML form does have name attributes for the POST arrays, so make sure the form is using a POST method.
http://php.net/manual/en/tutorial.forms.php
I believe I have given you enough information to get started.
What you must NOT do, is to use the above with your present code and simply patching it. You need to start over.
Add error reporting to the top of your file(s) which will help find errors.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// rest of your code
Sidenote: Displaying errors should only be done in staging, and never production.
I'd like to make an if statement that checks if the username, already exists in the MYSQL database. I tried some different stuff, but i cant make it work. Every time I test it in my browser I get a notice
Notice: Undefined index: username in etc.
I am confused if it has anything to do with the $result variable or the $check variable or neither.
Here is the HTML form and the PHP script.
https://gist.github.com/anonymous/9704354
Thank you and have a nice weekend!
There are a few things that are wrong in your code.
First, never place variables directly in SQL queries, thats how SQL injections happen. Start using PDO or another library for your MYSQL.
The reason you are getting an undefined notice is because of this line.
$result = mysql_query("SELECT * FROM users WHERE username = '$_POST[create_user]'");
It should be this without fixing the huge SQL Injection flaw
$result = mysql_query("SELECT * FROM users WHERE username = '{$_POST['create_user']}'");
Also you should add a "LIMIT 1" to the end of the select query to speed things up. No need looking for more than one user.
You can verify the user by just checking for row_count instead of checking the text values. Since MySQL is not case sensitive for some fields, username "AAAaaa" will be equal to "aaaAAA". If you check row count instead, you will be sure that no usernames are in the database of that text. Or if you want to check using PHP, make sure you pass the usernames through strtolower()
When you start using PDO, the following example will help you.
$dbh = new PDO() // Set the proper variables http://us2.php.net/pdo
if(empty($_POST['create_user'])) {
echo 'Username is Empty. Always check if POST and Get data is set';
die();
}
$query = "SELECT * FROM `users` WHERE `username` = ? LIMIT 1;"
$data = array($_POST['create_user']);
$sth = $dbh->prepare($query);
if(!$sth->execute($data)) {
echo 'Handle SQL Error';
die();
}
if($sth->rowCount() == 0) {
echo 'Unused Username';
}else{
echo 'Used Username';
}
This is what i've found
the $_POST['username'] should be like $_POST['create_user']
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 9 years ago.
I have problem with my login form sql injection is working on it so how to stop it.
I am using mysql_real_escape_string but nothing changed
if(isset($_POST['submit-login'])) {
$user = $_POST['username'];
$pass = $_POST['password'];
$username = mysql_real_escape_string($user);
$password = mysql_real_escape_string($pass);
$usertool = new Usertool();
if($usertool->login($username, $password)){
//successful login, redirect them to a page
header("Location: index.php");
}else{
$error = "Incorrect username or password. Please try again.";
}
}
Here is usertool
class usertool {
public function login($username, $password) {
$hashedPassword = md5($password);
$result = mysql_query("SELECT * FROM tbl_user WHERE uname = '$username' OR eemail = '$username' AND password = '$hashedPassword'");
if (mysql_num_rows($result) == 1) {
$_SESSION["user"] = serialize(new User(mysql_fetch_assoc($result)));
$_SESSION["login_time"] = time();
$_SESSION["logged_in"] = 1;
return true;
} else {
return false;
}
}
it is not a classic SQL injection in your case but rather wrong SQL logic.
You need to add braces to your query:
SELECT * FROM tbl_user
WHERE (uname = '$username' OR eemail = '$username')
AND password = '$hashedPassword'"
In your original query the whole statement evaluates to true if entered username or email matches, and password not even being checked
And regarding SQL injections in general, to make your queries safe, you have to format your query parts according to these rules
Formatting have to be complete. mysql_real_escape_string does incomplete formatting alone: you ought to add apostrophes around whatever data you escaped using this function.
Formatting have to be adequate, means you can't format a number or an identifier with string formatting. EVery SQL literal require it's own distinct formatting.
Formatting have to be done as close to the query execution as possible.
Following these rules you'll be pretty safe from injection. And using prepared statements is the easiest way to follow them.
One don't need neither mysqli not PDO to use native prepared statements though - you can create your own variant. But nevertheless, you have to move mysql_real_escape_string as closer to the query execution as possible and always add apostrophes around the result.
I am using mysql_num_rows to check if one row is returned for my user login and if count == 1 then log user in, I get an error though below my code is after that. Any suggestions?
Warning: mysql_num_rows(): supplied
argument is not a valid MySQL result
resource in
/home/web42001spring09/rcoughlin/public_html/process-login.php
on line 13
<?php
// include database info
include("config.php");
if(isset($_POST["submit"])){
// get data from form
$username = $_POST["user"];
$password = $_POST["pass"];
$query = "SELECT username,password,id FROM login WHERE username=".$username." AND password=".$password." LIMIT 1";
$result = mysql_query($query);
$count = mysql_num_rows($result);
// if 1 then login them in set cookie and redirect
if($count==1){
setcookie("password", "".$password."", time()+3600);
setcookie("username", "".$username."", time()+3600);
header("Location:admin.php");
}else{
echo "Wrong Username or password combination";
}
}else{
echo "Must be submitted via form.";
}
Not sure why the code is drawing that issue? I have used this method before.
You're not quoting your strings in the query, so your SQL statement is invalid.
$query = "SELECT username,password,id FROM login WHERE username='" . mysql_escape_string($username) . "' AND password = '" . mysql_escape_string($password) . "' LIMIT 1";
$result = mysql_query($query) or die(mysql_error());
You need to add quotes AND use mysql_escape_string or mysql_real_escape_string to prevent SQL injection attacks.
Firstly, check for errors...
The "supplied argument is not a valid MySQL result resource" because there was an error in your SQL, but you haven't made life easy for yourself by ignoring the failed query. Use mysql_error to get the error message.
Secondly, properly escape strings in SQL...
Once you see the error, you'll see you missed some quotes in your query, but you must also escape the strings you put in a query, otherwise you're vulnerable to SQL injection attacks...
$query = "SELECT username,password,id FROM login ".
"WHERE username='".mysql_real_escape_string($username)."' ".
"AND password='".mysql_real_escape_string($password)."' LIMIT 1";
$result = mysql_query($query);
if ($result)
{
$count = mysql_num_rows($result);
// if 1 then login them in set cookie and redirect
if($count==1){
setcookie("password", "".$password."", time()+3600);
setcookie("username", "".$username."", time()+3600);
header("Location:admin.php");
}else{
echo "Wrong Username or password combination";
}
}
else
{
echo "Error:".mysql_error()."<br>;
}
Always use mysql_real_escape_string when building a query, or use a wrapper class library which does it for you with parameterised queries, like PDO or ADODb
Finally, a word on those cookies...
Also, logging someone in by giving them a cookie with the username and password isn't a terribly good way to implement a login. Aside from transmitting the password in the clear with every request, it's highly vulnerable to a cookie theft attempt. Given your naive approach to SQL security, it's likely you'll also be leaving yourself vulnerable to XSS attacks making it easy for someone to collect those cookies :)
Looks like you might want to do 2 things:
Sanitise your input - passing user-submitted data straight into a database query is a recipe for disaster (see mysql_real_escape_string(string $unescaped_string)).
Put quotes around literals in database queries (i.e. username ='".$username."')
The error message you're getting is due to the fact that the MySQL result object ($result) is not valid. Try calling mysql_error() to see what error message MySQL returns.
Try:
$row = mysql_fetch_row($result);
if ($row) { // success
Assuming you'd probably want to fetch some columns along with the authentication check (e.g. real name, last login etc.)
Do never store user authentication data in a cookie!
Because both password and login are strings, you need to change the SQL:
$query="SELECT username,password,id FROM login WHERE username='".$username."' AND password='".$password."' LIMIT 1"
The query is invalid (the $result == false)
Line:
$query = "SELECT username,password,id FROM login WHERE username=".$username." AND password=".$password." LIMIT 1";
Should be replaced by:
$query = "SELECT username,password,id FROM login WHERE username='".mysql_escape_string($username)."' AND password='".mysql_escape_string$password)."' LIMIT 1";
The PHP mysql_query() function doesn't give errors by default.
Using a function that shows sql errors allow you to spot these errors easily.
function my_query($sql) {
$result = mysql_query($sql);
if ($result === false) {
trigger_error('['.mysql_errno().'] '.mysql_error(), E_USER_WARNING);
}
return $result;
}
Right now the username and password are injected directly in the sql string.
What you want is password = "secret", now the query contains password = secret
Mysql error "unknown column sercet"
PS:
Using a "LIMIT 1" here is a sign that there are several users (ids) using the same username password combination. (Not recommended)