MySQL PASSWORD() function and SpringSecurity ShaPasswordEncoder - mysql

I've got a mysql database that stores passwords using MySQL's PASSWORD() function. From what I can gather from this URL (and verifying it myself to make sure it applies to my version of MySQL)
http://www.palominodb.com/blog/2011/12/04/hashing-algorithm-mysql-password
The hashing function for mysql is a double SHA1 hash with the first result converted from binary to hex before hashing it again.
SELECT PASSWORD("this_is_a_random_string") as 'pass';
pass: *12E76A751EFA43A177049262A2EE36DA327D8E50
SELECT concat('*', UPPER(SHA1(UNHEX(SHA1("this_is_a_random_string"))))) as 'pass';
pass: *12E76A751EFA43A177049262A2EE36DA327D8E50
So what I'd like to do is use SpringSecurity's ShaPasswordEncoder to allow Spring to work with these hashes.
Other than subclassing my own PasswordEncoder and using ShaPasswordEncoder to build up the processing steps shown in the SQL above, does ShaPasswordEncoder itself have a standard way of setting itself up to work with MySQL's PASSWORD function?

http://dev.mysql.com/doc/refman/5.6/en/encryption-functions.html#function_password
The PASSWORD() function is used by the authentication system in MySQL Server; you should not use it in your own applications.

Related

MySQL AES_DECRYPT in NodeJS, placeholder for encryption key?

I found similar replies but nothing really straightforward.
How can AES_DECRYPT be used only for the password field in a query using MySQL extension in NodeJS ?
What I have is as follow:
app.post("/verify",function(req,res){
connection.query('SELECT *, FROM `bosses` where u=? and p=?', [req.body.user,req.body.pass], function (error, results, fields) {
if(results.length){
session.loggedin=1;
res.redirect('/zirkus');
}else{
res.redirect('/soccer');
}
});
I assume that I need to modify the query with something like this:
connection.query('SELECT *, FROM `bosses` where u=? and p=AES_DECRYPT (?, 'ENCRYPTIONKEY')', [req.body.user,req.body.pass], function (error, results, fields) {
but somehow I can't get it to work properly. Should I use a placeholder for the encryption key too ?
EDIT
Thanks for the replies and explanation on why this was generally a bad idea :)
Here is a variation: no decryption password is stored in the code:
connection.query('SELECT *, AES_DECRYPT(p, ?) AS `key` FROM bosses WHERE u = ?', [req.body.pass, req.body.user], function (error, results, fields) {
console.log (req.body.pass + req.body.user )
if(results[0].key){
session.loggedin=1;
res.redirect('/zirkus');
}else{
res.redirect('/soccer');
}
});
});
Here the admin user types the decryption password in the form and if the decryption is successful (the key returns true) it allows the user to log in (without using or saving the password) else access is denied.
I assume that in this solution the only downside are the mysql logs right ?
Answer 1: Don't use encryption for storing user passwords. Use hashing.
There's no reason you need to decrypt user passwords, ever. Instead, when the user logs in, you hash their input with the same hashing function and compare the result to the hash string stored in the database.
Try bcrypt: https://www.npmjs.com/package/bcrypt
Also read https://blog.codinghorror.com/youre-probably-storing-passwords-incorrectly/
Answer 2: I never do encryption or hashing in SQL expressions. The reason is that the if you use the query log, it will contain the plaintext of the sensitive content, as it appears in SQL expressions. It will also be visible in the PROCESSLIST.
Instead, if you need to do encryption or hashing of sensitive content, do it in your application code, and then use the result in SQL statements.
Re your edit:
I assume that in this solution the only downside are the mysql logs right ?
No. The problem is that you're storing the password using reversible encryption. There is no reason to reverse a user password. If I visit a website that offers a "password recovery" feature where they can tell me what my password was (no matter how many other security checks they do), then I know they're storing passwords wrong.
If passwords are stored in a reversible encrypted format, this creates the possibility that someone else other than me can reverse the encryption and read my password. That will never happen with hashing, because you can't reverse hashing to get the original content.
If it is because of the logs ... ?
You could disable the query logs, of course. But there's also other places where the query is visible, such as:
the binary log (if you use statement-based binary logs)
the PROCESSLIST
the performance_schema statement tables
the MySQL network protocol. That is, if you don't use TLS to encrypt the connection between the application and the database, someone could intercept packets on the network and see the plaintext query with the plaintext content.
In your edited example, they could view the user's plaintext decryption key in any of the above contexts.
... why MySQL has this function ...?
There are legitimate uses of encryption other than user passwords. Sometimes you do need to decrypt encrypted content. I'm just talking about user passwords. User passwords can be authenticated without decryption, as I described at the top of this answer. It's covered in the blog I linked to, and also as a chapter in my book SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming.
Another use of encryption and corresponding decryption function in SQL is when you develop code as stored procedures. It would be inconvenient to have to return encrypted data to the client application just to decrypt it, and then send it back to your stored procedures for further processing it.
You have to use doubole quotes for the decryption key or escaping ut
connection.query('SELECT *, FROM `bosses` where u=? and p=AES_DECRYPT (?, "ENCRYPTIONKEY)', [req.body.user,req.body.pass], function (error, results, fields) {
if(results.length){
session.loggedin=1;
res.redirect('/zirkus');
}else{
res.redirect('/soccer');
}
});
But as in every language passwords are usually only stored as hashed values, so that they can't be easily reconstructed, even with the logs. so chelkc for example https://coderrocketfuel.com/article/using-bcrypt-to-hash-and-check-passwords-in-node-js

passlib checksum doesn't verifies with SHA2 of MySQL

I am using vernemq to authorize users from database using SHA256 algorithm. I observe that when creating new entry in table using buildin mqsql function SHA2,
INSERT INTO vmq_auth_acl
(mountpoint, client_id, username,
password, publish_acl, subscribe_acl)
SELECT
'', 'newUser2', 'newUser2', SHA2("CJJPL9", 256),
'[{"pattern":"botOut"}] ',
'[{"pattern":"botIn/#"}]';
which generates hash value something like this 54d0e30d0a00d86451a3353a2123fc1f006faaba6b55ef0d168390f26cbab82a and Vernemq server successfully verifies this user when logged in using CJJPL9 password.
But when I add this entry into this table from python code using passlib library sha256_crypt.encrypt("CJJPL9"), which generates hash as follows
$5$rounds=80000$wnsT7Yr92oJoP28r$cKhJImk5mfuSKV9b3mumNzlbstFUplKtQXXMo4G6Ep5. I know, due to salt, the hashs will be different, but there is a clear difference in the formatting of both hashes and as a result, verneMQ server fails to verify the credentials for this user. The formatting of passlib library says that it keeps only 43 characters from 256-bit checksum. I also tried testing by only keeping the checksum part of the passlib hash string, but still no luck.
I want to know what is the difference between encryption of MySQL SAH2("CJJPL9", 256) and sha256_crypt.encrypt("CJJPL9").

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.

Drupal : How can I know if the db is mysql or postgres

I have a complicated query and since I need that my module work on both mysql and postgres, I need to write two version of it.
Unfortunately, I don't know how I can check if the db I use is mysql or postgres, to know which query use. Do you know if a function can return this value?
As #kordirko says, one option is to query the server version: SELECT version(); will work on both MySQL and PostgreSQL, though not most other database engines.
Parsing version strings is always a bit fragile though, and MySQL returns just a version number like 5.5.32 wheras PostgreSQL returns something like PostgreSQL 9.4devel on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8), 64-bit. What do you do if you're connecting to a PostgreSQL-compatible database like EnterpriseDB Postgres Plus, or a MySQL-compatible database?
It's much safer to use the Drupal function for the purpose, DatabaseConnection::databaseType. This avoids a query round-trip to the DB, will work on databases that won't understand/accept SELECT version(), and will avoid the need to parse version strings.
You'll find this bug report useful; it suggests that the correct usage is Database::getConnection()->databaseType().
(I've never even used Drupal, I just searched for this).
As long as the abstract DatabaseConnection class extends PDO class, you can invoking pdo methods in order to know the current database driver.
For instance:
$conn = Database::getConnection();
print $conn->getAttribute($conn::ATTR_DRIVER_NAME); #returns mysql, pgsql...
There is a second way to do it using DatabaseConnection::driver():
print $conn->driver();
or DatabaseConnection::databaseType();
print $conn->databaseType();
Note that DatabaseConnection::driver() and DatabaseConnection::databaseType() are similar functions but not equals!
The return value from DatabaseConnection::driver() method depends on the implementation and other factors.
in the Drupal Database API page:
database.inc abstract public DatabaseConnection::driver()
This is not necessarily the same as the type of the database itself. For instance, there could be two MySQL drivers, mysql and mysql_mock. This function would return different values for each, but both would return "mysql" for databaseType().
In the most cases you just gonna want to use only
$conn->getAttribute($conn::ATTR_DRIVER_NAME)
or $conn->databaseType()
If you want get more specific properties, you should take advantage the PHP ReflectionClass features:
$conn = Database::getConnection();
$ref = new ReflectionClass($conn);
#ref->getProperties, ref->getConstants $ref->isAbstract...
Reference:
PDO::getAttribute
PDO::ATTR_DRIVER_NAME
Drupal Database API
Drupal Base Database API class

How to generate the right password format for Apache2 authentication in use with DBD and MySQL 5.1?

I want to authenticate users for a folder from a MySQL 5.1 database with AuthType Basic.
The passwords are stored in plain text (they are not really passwords, so doesn't matter).
The password format for apache however only allows for SHA1, MD5 on Linux systems as described here.
How could I generate the right format with an SQL query ? Seems like apache format is a binary format with a lenght of 20, but the mysql SHA1 function return 40 long.
My SQL query is something like this:
SELECT CONCAT('{SHA}', BASE64_ENCODE(SHA1(access_key))) FROM user_access_keys INNER JOIN users ON user_access_keys.user_id = users.id WHERE name = %s
where base64_encode is a stored function (Mysql 5.1 doesn't have TO_BASE64 yet). This query returns a 61 byte BLOB which is not the same format that apache uses. How could I generate the same format ?
You can suggest other method for this too. The point is that I want to authenticate users from a MySQL5.1 database using plain text as password.
The document you refer to does not mean to imply non-Linux by "Unix-only", therefore crypt() is available to you. Since you seem unconcerned about security I'd suggest this is the easiest option alongside MySQL's encrypt function. You may want to use a constant seed value in your queries.
SELECT ENCRYPT(access_key, 'SA') FROM user_access_keys INNER JOIN users ON user_access_keys.user_id = users.id WHERE name = %s