MySQL SELECT: is it possible to use part of the result in the SELECT? - mysql

(Massively edited because the responses were focusing on the wrong thing, which means I didn't formulate the question properly.)
I have a MySQL table with id, username and password fields. The password is encrypted. Part of the encryption uses the id of the record, specifically (in PHP):
md5 (md5('id') . $formPasswordCleaned)
To a validate a login form, I do the following (pseudo-code):
query database for the email address from login form
if num_rows > 0, $row = fetch_array
use $row['id'] to encrypt the password provided in the login form.
compare encrypted password with the one found in $row 4.
But, what I'd really like to do is one single SELECT command, that looks for a match on both email address and the encrypted password. But, since the password was encrypted using the row's id.....
Question: is it possible to write a SELECT statement that uses part of the forthcoming result as some of the arguments? Something like: SELECT * from users where email=$email and password=md5(md5($futureResult['id]).$password)
I realise it's self-referential, but I know just the basics of database usage and so I don't know what to search for (google or here) to find out if it's possible or how to do it, if it is indeed possible.

Related

How to use password() in sql?

I am trying to verify user login my matching the input password to the password input by user
My insert query:
insert into login (Emp_id, Emp_Fname, Emp_Lname, Username, Password) values (5, 'TestFName', 'TestLName', 'Test', password('april'));
it stores the password as this value :
*72B46CDA233C759A88BEF81F59F66D78B26B2848
select * from login where password = '*72B46CDA233C759A88BEF81F59F66D78B26B2848'; -- this line shows me the result
select password('april'); -- this returns *72B46CDA233C759A88BEF81F59F66D78B26B2848
select * from login where password = 'password(april)'; -- this returns an empty set
Is there any alternative to this line of code?
I think you need to use:
select * from login where password = password('april');
So, don't quote the whole password function, just the argument to the function.
One cannot safely store passwords with pure SQL commands, instead a dedicated password-hash function of the development language should be used. In PHP this would be the functions password_hash() and password_verify() for the verification of the password.
Even more, MySql's password() function was never intended to be used with user passwords and is deprecated (will be removed in future versions). Have a look at the second note box in the documentation.
The reason why you cannot left the hashing to the SQL command is, that salted password hashes cannot be searched for in the database. The searching has to be done by user name only and afterwards one can verify the found password hash with the user input. A more in-depth explanation you can find in this answer.
https://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html#function_password says:
This function is deprecated as of MySQL 5.7.6 and will be removed in a future MySQL release.
PASSWORD() is used by the authentication system in MySQL Server; you should not use it in your own applications.
That wasn't an idle warning. https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_password says:
This function was removed in MySQL 8.0.11.
So don't use PASSWORD() — unless you plan to never upgrade to MySQL 8.0.
Besides that, you have some problems in your code.
insert into login (Emp_id, Emp_Fname, Emp_Lname, Username, Password)
values (5, 'TestFName', 'TestLName', 'Test', password('april'));
I wouldn't use password (or any other hashing function) in this way, because you still have the plaintext password in your SQL statement. This ends up getting logged in query logs and statement-based binary logs, so it's a security weakness. That is, anyone who can get access to your logs can inspect the passwords.
Instead, hash the password in your app, and then put the result of that hash into your SQL statement.
Which hashing function you use depends on the language you use to write your application code. #martinstoeckli mentions a couple of functions that are used by PHP developers, but those won't be the same for other programming languages. You don't mention which language you use.
Likewise, when you search for a login that has that password, it works if you search for a specific hash string, but this doesn't work:
select * from login where password = 'password(april)'; -- this returns an empty set
The reason is that you're searching for the string 'password(april)'. Putting an expression in quotes means to use that literal string — it won't execute the function and use the result of it.
Again, you don't want to calculate the hash using SQL anyway. That puts the plaintext password into query logs and is not good for security.
You want to produce the hash string in your app, and then use the hash string in searches, like your first example. But not using the PASSWORD() function — using some application code function.
select * from login where password = '*72B46CDA233C759A88BEF81F59F66D78B26B2848';
(The hash string above is based on your example. It's a hash produced by MySQL's PASSWORD() function, only as strong as a SHA1 hash, which is known to be unsuitable for passwords.)
Actually, my preferred method is not to search for a password at all. Search for the login, and return the password hash string that is stored in the database.
select password from login where user = 'billkarwin'
Then in the application code, compare the hash string you fetched from the database against the re-calculation of the hash string based on the user's input when they're trying to log in.

Look up my current userID with mySql

This scripts selects an account form my MySQL database with the userID 1:
$_SESSION['user_id'] = 1;
If my MySQL account has id 1 then it will change that account.
I wonder how you can change the = 1; so it automatically looks up which account you are on at the moment? Right now it only works with the account with userID 1.
MySQL database name for my userid is "userID".
Usually you would say something like
SELECT * FROM user_profiles WHERE user_id=1 in MySQL.
Also, I would recommend that you use PDO and properly escape the user input using
htmlspecialchars($_SESSION['user_id'])
in your PHP file since the user_id input most likely can be manipulated by the user.
You are using Session so it can not change the userID unless you destroy that session by using this PHP function:
session_destroy();
And if you want to know your current userID:
echo $_SESSION['user_id'];

Test whether or not log-in system is protected against sql injection

So for a school project I have to make a site with a log-in system. It has a username and password field, and a submit button. It compares the username and password with those in a MySQL database. If the combination is in the database, the user may proceed, else they are redirected to the log-in page. I use prepared PDO statements for my database connection.
Now my teacher wants me to test the safety by performing sql attacks on the log-in system. Unfortunately I have no idea what to put in these boxes, and what would be the outcome. For example, I have tried putting values in both username and password fields that will return true, like this:
1==1, 1===1, 0 is null
But I do not know whether or not I have succeeded and if attackers may access or truncate my database by these sort of statements.
Html code:
<form method="post" action="includes/login.php">
<input type="text" name="gebruikersnaam" >
<input type="password" name="wachtwoord" >
<input type="submit" value="login">
</form>
Php authentication:
$myusername=$_POST['gebruikersnaam'];
$mypassword=$_POST['wachtwoord'];
$sql="SELECT * FROM leerling WHERE leerlingnummer='$myusername' and wachtwoord='$mypassword'";
$sql2="SELECT * FROM lop WHERE gebruikersnaam='$myusername' and wachtwoord='$mypassword'";
$statement2=$conn->prepare($sql2);
$statement2->execute();
$count2=$statement2->rowcount();
if($count2==1){proceed}
$statement = $conn->prepare($sql);
$statement->execute();
$count= $statement->rowcount();
if($count==1){proceed}
else {deny access}
Imagine this query:
SELECT id FROM users WHERE email=? AND password=? LIMIT 1
Now imagine the values would be foo#bar.hello and an empty string for password:
SELECT id FROM users WHERE email='foo#bar.hello' AND password='' LIMIT 1
This would not be harmful if these credentials are not in your database. Now lets give different input:
For email we fill in an empty string, and for password we insert ' OR 1=1 (Note the first apostrophe)
Your teacher wants you to find out whether this means your SQL server will execute the following query:
SELECT id FROM users WHERE email='' AND password='' OR 1=1 LIMIT 1
SQL is a declarative language with which you declare the expectations you have for your result. If your server would interpret our input as stated above, the first users id would be considered correct, simply because one is equal to one.
As it is, it is susceptible to SQL injection
The thing to look at when trying to inject is can I close the statement I'm in right now and add more to the end.
so if you enter username = 123456' -- the SQL statement becomes SELECT * FROM leerling WHERE leerlingnummer='123456' --' and wachtwoord='unimortant'
the -- starts a comment so all it does is select whatever student number is entered ignoring the password.
PDO has good alternatives to prevent this from happening called Prepared Statements. You declare your SQL queries and only enter where user infromation is going to be entered by using a ? or :lable and then bind user input to those points. The page does a way better job at explaining it. This way all user data is clearly seperated from the rest of the command and will be treated as a litteral string rather than a command. Stopping SQL injection.
$sql="SELECT * FROM users WHERE username = '{$_REQUEST['username']}' AND password = '{$_REQUEST['password']}";
Write query in such format will avoid sql injection.
$sql = 'SELECT * FROM users WHERE username = ? AND password = ?';
$query = $db->prepare($sql);
$query->bindParam(1, $_REQUEST['username']);
$query->bindParam(2, $_REQUEST['password']);
Or pass the parameter to mysql_real_escape_string function and then pass to queries.
$username=mysql_real_escape_string($_REQUEST['username']);
$password=mysql_real_escape_string($_REQUEST['password']);

SELECTing in a WHERE clause, inside a SELECT statement

I'm not exactly sure on the correct technical wording, so excuse my title, but here's the problem. I have a MySQL database, and in the user table I have *user_name*, a *password_salt*, and an md5 password containing the password then salt. In a program, users connect and I get one query to send to validate a user.
When a user connects I need a way of selecting their user_name, and comparing the given password to the stored password, which requires retrieving the salt somewhere in the WHERE statement (I guess).
This is my hypothetical "example":
SELECT user_name
FROM users
WHERE user_name='$nick' AND
password = md5(CONCAT('$md5pass', md5((select password_salt FROM users where user_name='$nick'))))
LIMIT 1
Resolution Update: Got it working, thanks for the suggestions, a normal select sufficed, the problem was that the sql-auth api wasn't receiving the password unless the port was specified.
Actually you can freely use any column from table declared in "FROM" clause not only in "SELECT" clause, but also in "WHERE" clause, so I don't see a need to subquery here. Let it be simply:
SELECT user_name
FROM users
WHERE user_name='$nick' AND
password = md5(CONCAT('$md5pass', md5(password_salt)))
LIMIT 1
This way a row is selected only if it matches both:
- user name is correct
- the password in row matches given password
I am not sure though if I used md5() functions correctly. I copied your example.
SELECT user_name
FROM users
WHERE user_name='$nick' AND
password = md5(CONCAT('$md5pass', password_salt))
LIMIT 1
Try this instead:
SELECT user_name
FROM users
WHERE user_name='$nick' AND
password = md5(CONCAT('$md5pass', md5(password_salt)))
LIMIT 1

mysql: encrypting and decrypting data

Does mysql provide a mechanism for storing and retrieving encrypted data? I don't mean passwords, I mean real strings.
I'd like to encrypt a string, store in mysql and then retrieve the decrypted string at a later date.
So, I know there is the AES_Encrypt and decrypt functions. But they ask for a key. (which is fine) but I wondering if you call those functions and use your user password as the key. Or something else that is super-simple.
Also, is there a simple wrapper for the AES_Encrypt & decrypt functions in Rails? Or do you need to build the query manually?
You can just concat the encrypt functions:
select aes_encrypt('MyData',Password('MyPassword'))
and back again..
select Aes_decrypt( aes_encrypt('MyData',Password('MyPassword'))
, Password('MyPassword'))
If I understand you, then all you need is a method to generate an AES key from your (or other) user password?
Shouldn't you be asking 'Is there an easy method to generate an AES-key from 5-20char string'?
As you point out, the other tools are already in place in mysql: http://dev.mysql.com/doc/refman/5.0/en/encryption-functions.html
Also you might find some ideas in this post here on SO.
$pass = $_POST['pass'];
$sql = "INSERT INTO testperson (name,password,contact) VALUES('$name',md5('$pass'),$cont)";
Just write md5 before the input you want to encrypt, like password.