I have some code like this which is open to SQL injection. We got hacked and now we fixed it. I just want to know what the inputs (username and password) must be in order to hack this code. I mean even if you input
username = something' OR 'x'='x
Then you can retrieve the password of the first user in the table regardless of the username. However, inside the if we check whether this password is correct. I am assuming the password was very easy (as easy as 123456) and the hacker made a brute-force from a dictionary. However I am wondering if there is another way to hack this code using some injection other than brute-forcing the password.
<?php
$username=$_POST['username'];
$password=$_POST['password'];
$result=runQuery("SELECT password FROM tbl_users WHERE username='".$username."''");
$row=mysql_fetch_array($result);
if($row['password']==$password){
-- do sth... create a cookie etc..
}
else{
--go to another page...
}
?>
Use variable binding in PDO library.
If hacker pass value:
$username = "' OR * OR '"
then query will be:
SELECT password FROM tbl_users WHERE username='' OR * OR ''; - this will be select any user.
But hacker can:
$username = "'; DELETE * FROM tbl_users WHERE username = * OR '";
SELECT password FROM tbl_users WHERE username = ''; DELETE * FROM tbl_users WHERE username = * OR '';
Or can made UPDATE to change any password.
Safety? mysql_real_escape_string or preg_match("/^[a-zA-Z0-9]{3,15}$/", $username), for example.
Using boolean blind or time blind injection hacker can retrieve all the database structure.
Example:
username = 'admin' and if(1=1, sleep(10), 5222) #
This query gonna take 10 second to return and confirm that your condition is true or false. Using the information_schema and SQL condition test you can retrieve all databases information.
Related
I wrote a SQL query for checking name in php, but it does not work.
I have no assumptions how to fix it, but I assume it's just mistake in syntax.
$username = $_POST["username"];
$nameCheckQuery = "SELECT username FROM users WHERE username '" . $username . "';";
$nameCheck = mysqli_query($db, $nameCheckQuery) or die("2: Name check query failed");
I receive error log on query.
The reason it's failing is likely due to you missing a = after username.
This code is open to SQL injection and you should use prepared statements.
The most basic of a prepared statement looks something like this:
$stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
$username = $_POST['username'];
$stmt->bind_param('s', $username);
$result = $stmt->execute();
The main problem of your query is that you forget to insert = next to WHERE username.
You have to write:
$nameCheckQuery = "SELECT username FROM users WHERE username ='" . $username . "';";
Right now it works but......
The query you are using is not preventing a SQL INJECTION attack (one of the most used attack against database).
Please take a look at the ways you can connect to the database:
use PDO (it works with 12 database type);
use MSQLI (it works only with MYSQL database and you are using it);
In other word, if you are planning that you will move your application in another database type please consider to use PDO, instead.
Using PDO preventing SQL injection you have to prepare the SQL statement like this:
$stmt = $pdo->prepare("SELECT username FROM users WHERE username = ?");
$stmt->execute([$_POST['username']]);
$arr = $stmt->fetch();
For Starter, please use this escape string:
$username = $mysqli->real_escape_string($_POST["username"]);
Simply do it like this and don't get confused with quotes.
You can still print php variables inside single quote like this.
$nameCheckQuery = "SELECT username FROM users WHERE username = '$username'";
or to edit your code, this is how you can achieve it.
$nameCheckQuery = "SELECT username FROM users WHERE username ='" . $username."'";
Just to answer your question, it is Vulnerable to Sql Injection.
Reasons why Sql Injection occurs:
SQL Injection occurs when an attacker is able to send their own instructions to your database and the database executes those instructions. This occurs when a PHP developer has taken input from a website visitor and passed it to the database without checking to see if it contains anything malicious or bothering to clean out any malicious code.
SQL Injection can allow an attacker to access all of your website data. They can also create new data in your database which may include links to malicious or spam websites. An attacker may also be able to use SQL Injection to create a new administrative level user account which they can then use to sign-into your website and gain full access.
SQLi is a serious vulnerability because it is easy to exploit and often grants full access immediately.
This is how you can achieve it, which provides detailed functionality.
https://stackoverflow.com/a/60496/6662773
I'm using ORM layer in databases all the time, so I don't mind about SQL injections, but a friend gave me this task and I still have no idea how to solve it.
I know the PHP script just checks if the return of the query is != null (username matching to entered username & password is found).
The query itself in PHP looks like:
$sql = "SELECT name FROM users WHERE name='".$name. "' AND password='".$password. "'";
What's the best way to archieve a return of this query != null OR retrieving valid login data (username & password). The password is stored plain in database. I know storing plain is bad and I know using PDO is good, but I have no idea how to solve this funny task he gave me, maybe because I use PDO all the time.
Say we have these two input variables:
$name = "iam";
$password = "aninjection";
Which results in this query:
$sql = "SELECT name FROM users WHERE name='iam' AND password='aninjection'";
And let's say now we add this to the $password variable:
$password = "aninjection' OR 1='1";
Which results in:
$sql = "SELECT name FROM users WHERE name='iam' AND password='aninjection' OR 1='1'";
This query will now result in true and show every name from the user table.
This is of course a basic example. We could also do more harm by dropping entire tables.
If you wanted to retrieve passwords you would inject
$name = "whatever";
$password = "' OR '1'='1' UNION ALL SELECT password from users;--";
This would then make the query
SELECT name FROM users WHERE name='whatever' AND password='' OR '1'='1' UNION ALL SELECT password from users;--'
See this answer for how an attacker would start to work this out from injecting into the query.
I need help with my login-script - it seems to be broken. If I enter no password I still get logged in correctly. Also if I don't enter anything. But if I enter the wrong username AND password it says my login credentials were wrong.
<?php
$verbindung = mysql_connect("localhost", "root" , "")
or die("Verbindung zur Datenbank konnte nicht hergestellt werden");
mysql_select_db("v1nce_website") or die ("Datenbank konnte nicht ausgewählt werden");
$username = $_POST["username"];
$password = $_POST["password"];
$abfrage = "SELECT username, password FROM logins WHERE username='$username' LIMIT 1";
$ergebnis = mysql_query($abfrage);
$row = mysql_fetch_object($ergebnis);
if($row->password == $password)
{
$_SESSION["username"] = $username;
echo "<p>Login erfolgreich.</p>";
}
else
{
echo "<p>Benutzername oder Passwort waren falsch. Login</p>";
}
?>
Any help would be appreciated.
There's a lot of things going on in this script that are worrisome:
Let's start with the actual problem you are here for. If your query won't find a matching row, $row will equal false. And since therefore, $row is not an object, $row->password will evaluate to NULL. And so, if $password is an empty string $row->password == $password will evaluate to true, because NULL == "" is truthy.
You would have been notified of this, had you turned on the displaying of errors, for instance with ini_set( 'display_errors', true );, in combination with a sufficient error reporting level, error_reporting( E_ALL ); for instance.
When you enter a wrong username and a wrong password, $row->password will again be NULL, but since you entered a non-empty string for a password, this time $row->password == $password will evaluate to false.
So, to mitigate this problem you need to make certain that you first check that there is actually a matching row, before you start comparing the passwords, for instance by evaluating mysql_num_rows( $ergebnis ) first.
Your script is vulnerable to SQL injection. This means that users of your script could potentially do harm when they enter SQL hacks as values for $_POST[ 'username' ]. For instance if I were to enter ' OR 1 = 1 -- your SQL query would result in the following (formatted for display purposes):
SELECT username, password
FROM logins
WHERE username='' OR 1 = 1 --' LIMIT 1
... always resulting in at least one row if the table is non-empty, because WHERE username='' OR 1 = 1 always evaluates to true (-- in SQL signifies a comment, so ' LIMIT 1 won't even be evaluated anymore).
To mitigate this problem, in your current setup, you need to sanitize your input values first with mysql_real_escape_string(), before passing them into the SQL query, like this:
$username = mysql_real_escape_string( $_POST["username"] );
But as others have advised already as well, you'd be wiser to start using a MySQL compliant library that offers prepared statements with parametrized queries, such as PDO or MySQLi, since the mysql_* library is in the process of being deprecated, because it offers poor means of defending against SQL injection.
Your passwords are stored verbatim (as plain text) in the database. This offers a variety of potential risks of accounts (and possibly user-related accounts) being compromised. Anyone who has access to the database (be it direct, authorized, access, or when the database is compromised) can view the passwords in clear text, and could therefore use these to either log in to your site, or use it as a potential login for other sites and/or services. After all, it is not uncommon for people to use the same combination of username and password for a variety of other sites and services.
To mitigate this problem you'd be wise to hash (one-way encrypt) the passwords before storing them in the database, and then, when the user wants to log in, compare the stored hashed value with the hash (using the same hashing function again) of the user entered password. Using a unique salt per user password as an extra security measure is also strongly advised, as this protects against what is known as rainbow table attacks.
For a more thorough explanation of what the preferred hashing algorithm to use is, and why, see this answer by user Andrew Moore to this question.
$abfrage = "SELECT username, password FROM logins WHERE username='$username' LIMIT 1";
$ergebnis = mysql_query($abfrage);
if(mysql_num_rows($ergebnis) > 0) // you can check for one
{
$row = mysql_fetch_object($ergebnis);
//rest code goes inside here
// redirect to any page or do whatever you like
}
I assume you're doing the login that way to protect against SQL injections, however, mysql_real_escape_string() will quickly fix that problem. I would do something like this:
$login = mysql_query("SELECT id FROM users WHERE username='" . mysql_real_escape_string($username) . "' AND password='" . mysql_real_escape_string($password) . "' LIMIT 1");
if ( mysql_num_rows($login) > 0 ) {
$user = mysql_fetch_array($login);
$_SESSION['userID'] = $user['id'];
echo 'Login successful!';
} else { // login failed
echo 'Login failed.';
}
Notice that I'm storing the user's ID in the session instead of their username. This is usually a better idea because it's much easier to manage user activity based on a unique auto_increment index value rather than a textual username. Most sites don't, but this method would allow you to let multiple users have the same username if you wished to do so. But if you do this, make sure you're logging them in based on their email address rather than their username, because you don't want someone getting logged in as someone else because they share the same username.
Also, you should be encrypting passwords. MD5 is a simple solution and can be implemented like so:
$password = md5($_POST['password']);
If you md5 the password input, you don't need to worry about slashes, either. Hope that helps.
Maybe the password is not gotten properly from the database. use print_r($row) to make sure everything is good there.
Also use sha1 encription with salt to increase security. Also do:
$username = mysql_real_escape_string($_POST["username"]);
$password = mysql_real_escape_string($_POST["password"]);
to avoid injection.
Hope this helps.
My question is pretty specific, but I think it will help in my overall understanding of security and SQL injection. I am running a local webpage with a simple form for the purpose seeing how SQL injection works first hand, by doing it to my own database and webpage. I keep changing the way my php file validates a user so I can see the differences. I am a beginner and the php file is very simple on purpose. My current php code is:
<?php
$username = $_POST['username'];
$password = $_POST['password'];
$conn = mysql_connect('localhost', 'root', 'password');
mysql_select_db(test1);
$query = "SELECT username, password FROM users WHERE username = '$username'";
$result = mysql_query($query) or die("Query failed: " . mysql_error());
$arr = mysql_fetch_array($result);
if($arr['username'] == $username && $arr['password'] == $password && strlen($username) > 0){
header('Location:index.php');
}else{
header('Location:login.html');
}
?>
I have no idea if this is a good or bad way of validating. I just want to know an example of how to inject it because I can't figure this one out. MySQL_query() only allows 1 statement so I can't chain together statements, and I don't know what else to do to it. I have changed the file so I can do
' or 1=1; -- types of injection, but obviously that one will not work here. So just curious. Thanks.
The following passed to username would return all the rows:
' or '1'='1
In general its simply not a good idea to pass unvalidated input to a SQL query.
Send this as username:
a' and(select 1 from(select count(*),concat((select concat_ws(0x3a,version(),database())),floor(rand(0)*2))x from information_schema.tables group by x)a) union select 1,'
I'm not sure but I think it's not possible to get redirected to index.php, but the above example will show you something interesting.
Such security holes should never be left non sanitized because a malicious user can get even the mysql's root user password if SELECT command is permitted to mysql table and so on.
By the way, you should never display mysql_error()s to end-users.
Consider the following query :
SELECT username, password FROM users WHERE username = 'anything' AND 0 =1
UNION ALL
SELECT '\'anything\' AND 0 =1
UNION ALL
SELECT \'user\',\'password\'','password'
If $_POST['password'] equals word 'password', your validation will fail and let unauthorized user to access protected page.
You are not doing any validation on your post parameters before you execute your statement. This is bad! And SQL injection is easily possible.
For example:
SELECT username, password FROM users WHERE username = '$username' AND (SELECT 1 FROM ([Almost any SQL statement you want...]))
I.E.
$username = "' AND (SELECT 1 FROM ([Almost any SQL statement you want...])); --"
Make sure you validate your parameters before using them in a SQL statement.
I am trying to create a login script that pulls information by verifying that the username is part of a group. In other words i am using two "ands" to verify info. Am i doing this correctly?
PHP:
$check = mysql_query("SELECT username ,password FROM customers WHERE username = '".$_POST['user_name']."' and group_name='".$group_name."'")or die(mysql_error());
Brandon Horsley and Matt Gibson already mentioned it as comments - think about SQL injection. Next thing is that I strongly don't recommend to use die(mysql_error()). Otherwise an experienced user might be able to "read something" out of that.
The easiest way is to use mysql_real_escape_string() (http://de.php.net/mysql_real_escape_string) - so you could adapt your code just like that (I assume that $group_name is also a value that can be manipulated by user):
<?php
// ...
$check = mysql_query("SELECT username, password FROM customers WHERE username = '". mysql_real_escape_string($_POST['user_name']) ."' and group_name = '". mysql_real_escape_string($group_name) ."'") or die('error);
// ...
?>