MySQL 8 SHA2 vs. Dovecot SHA256-CRYPT - mysql

update: It appears that what I'm naively trying to do here, of manually appending the salt to the password, will not work because of the way the crypt algorithm works (see Unix crypt using SHA-256 and SHA-512), so this is now really not a Stack Overflow question, but a purely Server Fault question on MySQL 8 functions. Leaving this here, in case anyone else has this problem. You can see the question on Server Fault here.
There's a long backstory here, but the short story is, I can't seem to get MySQL 8 and Dovecot to generate the same SHA256 hashes, given the same salt and password. I suspect either a trivial error, or some string encoding problem (or possibly both).
NB I asked this same question on Server Fault, as it seemed more appropriate for there, but it's not getting any love, and I see several similar questions here, so ...
Dovecot:
$doveadm pw -s SHA256-CRYPT -p apassword
{SHA256-CRYPT}$5$h1JEsg1tmnTGS9Ub$Saoi1jr/uddYVD.n5p0hz70H9slnubpG7MQCkzpAiu4
Then, I grab that salt (h1JEsg1tmnTGS9Ub), and try and get the same output from MySQL 8:
SELECT CONCAT('$5$', 'h1JEsg1tmnTGS9Ub', '$', TO_BASE64(UNHEX(SHA2(CONCAT('apassword', 'h1JEsg1tmnTGS9Ub'), 256)))) WHERE true
$5$h1JEsg1tmnTGS9Ub$Vm9gPbWHuXt/zslurPQ7Nx0JLp1CphlBQbnL9R86XbM=
As I mentioned, there seem to be several similar quesitons here, but either they're with MySQL 5.x using the ENCRYPT function, which has been removed in 8.0.3, or people seem to have decided to drop the salt and just use SHA512 unsalted. It seems to me that this should be easy, and yet ...
Anyone have any ideas on how to get MySQL 8 to generate the same hash as doveadm, with same password and salt?
FWIW, I've tried the MySQL with and without TO_BASE64 and with and without UNHEX (I believe in all combinations).
Thanks!

Related

Hashed password must be sanitized?

It's just a curiosity. If you encrypt a password (using sha1 or other methods) before inserting it in a query, it must be anyway sanitized? Or the hash's result is always safe?
This simple code are safe?
$salt = "123xcv";
$password = $_POST['password'];
$password = sha1($password+$salt);
$query = "select * from user where password='$password'";
Unless you validated the input somehow you shouldn't assume that it will always return a safe output because functions such as SHA1 can return error values if given unexpected input. For example:
echo '<?php echo sha1(''); ?>' | php
Warning: sha1() expects at least 1 parameter, 0 given in - on line 1
And this output obviously violates the assumption that "it's always a hex string". Other hashing functions in other languages can present yet another behaviour.
Apart from that, the above password hashing code scheme ($password = sha1($password+$salt);) is very weak (see why) and I would strongly recommend not using it even in an example as someone is eventually guaranteed to find it on StackOverflow and use in production.
Also, as already noted above, building SQL queries by concatenating strings is also a bad practice and can lead to security issues in future: today the only parameter in the query will be the password, tomorrow someone decides to add some other option and I bet they won't rewrite the query but just use the template that is already there...
This sql injection question question is asked out of a common delusion.
In fact, there is no such thing like "sanitization" at all, nor any function to perform such non-existent task. As well as there is no "safe" or "unsafe" data. Every data is "safe", as long as you're following simple rules.
Not to mention that a programmer have a lot more important things to keep in mind, other than if some particular piece of data is "safe" in some particular context.
What you really need, is to avoid raw SQL for such silly queries at all, using an ORM to run SQL for you. While in such rare cases when you really need to run a complex query, you have to use placeholders to substitute every variable in your query.
From the documentation:
The value is returned as a string of 40 hex digits, or NULL if the argument was NULL.
Assuming you have a large enough varchar column, you have no sanitization to do.
This being said, it's always cleaner to use prepared statements, there's no reason to just concat strings to build queries.

Replacing SHA1 with BCRYPT [duplicate]

This question already has answers here:
How do you use bcrypt for hashing passwords in PHP? [duplicate]
(11 answers)
Closed 9 years ago.
I have been looking into replacing SHA1 as the encryption of passwords with possibly bcrypt or something similar, and I cant seem to find a step-by-step, easy to follow tutorial for implementing this.
I did a quick tutorial on youtube which produced the following code:
$username = 'myusername';
$password = 'pa55w0rd';
$str = substr($username, 0, 6);
$salt = '$2a$12$rU8E3fsI9rsKh3V2'.$str.'$';
$pass = crypt($password, $salt);
echo $salt . '<br>' . $pass;
and when I run the code in the browser, this get output:
$2a$12$rU8E3fsI9rsKh3V2myuser$
$2a$12$rU8E3fsI9rsKh3V2myuseeMSOT1BADLFs/ncqHx5aG2q953uqp.Tu
QUESTION 1:
Am I correct in assuming that both strings are generated for a user, and that both strings are required to be stored in, for example, the users table as columns "salt" and "pass"?
QUESTION 2:
Why does it look like part of the username is visible within the salt and the pass? Is this normal, or is there some additional step I need to take to eliminate this from happening?
QUESTION 3:
Is this approach to hashing passwords more secure than md5 and sha1, or is there a better approach that I should be using?
Any suggestions appreciated..
I'd recommend using PHP's new password_hash and password_verify functions.
As you probably don't have PHP >= 5.5.0, there's a PHP implementation that adds support for the upcoming functions to older versions of PHP.
More info: https://gist.github.com/nikic/3707231
No, The salt is stored as part of the hashed password. Note that hashing is done against rainbow attacks (pre-prepared hash dictionary) or similar.
In order to check for valid password, the crypt function can take the hashed password itself as the salt, for it know how to split the salt from the hash.]
See: Comparing passwords with crypt() in PHP
No, that's fine, see above.
SHA1 Is better and stronger than MD5, Although it is preferable to use SHA-2.

Mysql attack prevention

i am currently developing a API for a service and was wondering if this could be classed as safe enough to prevent injection and/or other malicious attacks to the databases.
$username = mysql_real_escape_string(ereg_replace("[^A-Za-z0-9]", "", $_REQUEST['username']));
$password = mysql_real_escape_string(ereg_replace("[^A-Za-z0-9]", "", $_REQUEST['password']));
What this is doing is stripping out everything but letters and numbers and then running the mysql_real_escape_string command to run a fine comb in case something managed to get though.
Skip the deprecated ereg_replace() function and just use mysql_real_escape_string().
Also, why would you want to limit the user's password to a subset of chars. This just makes breaking in much easier.
Just your regex would be enough, without any further cleaning.
However, you should consider creating some sort of layer between your forms and the database to do this cleaning automatically.
Nathaniel,
Should be fine your usernames (maybe add '_' to the RE) but you've got a real problem with passwords, haven't you? Any half decent authentication actively encourages a user to choose a password which contain symbol(s), as well as letters, UPPERCASE LETTERS, and numbers.
So I guess I'd just stick to using mysql_real_escape_string - Escapes special characters in a string for use in an SQL statement ... after CAREFULLY reading the documentation, of course.
Cheers mate. Keith.

Perl UTF8 CGI and DBI ... what's the correct workflow?

I am having the pleasure of rebuilding a perl based web framework to UTF8 support. I took the following steps
for the main script:
use open IO => ":utf8",":std";
use utf8;
for the DBI Adapter:
$self->{dbh}->{'mysql_enable_utf8'} = 1;'
and in my request parser for POST and GET, based on CGI:
foreach (#val) { $_ = decode("UTF-8",$_); }
This, as far as I can tell, works just fine on my local Ubuntu with Perl 5.10.1, but on the webserver which runs 5.10, decoding POST or GET will mess up the text.
I must admit, I am very confused by the whole UTF8 thing. I need to
Read Templates
Get data from mySQL
Process POST and GET
insert into mySQL
write Templates
Is there anything I'm forgetting here? What could cause the inconstant behaviour? Does every module I use in the main script need to specifically use utf8 or is it enough if the main script does that?
Thanks for any hints,
thomas
use utf8; is, as several people have said, a no-op as far as your i/o problems are concerned: all it says is 'treat my source code as utf8 encoded'.
MySQL/DBI approach is bang on the money.
For CGI, update to a recent CGI and set $CGI::PARAM_UTF8=1 and it'll do the decode() for you. (As a general tip, BTW, decode_utf8() is considerably faster!)
As for the other problem, you may want to compare your Apache server configs to see if AddDefaultCharset is set to some non-helpful value.
Also, see my talk at last year's London Perl Workshop for a more detailed look at Perl and Unicode.
The solution here is the ordering.
$dbh->{mysql_enable_utf8} = 1;
$dbh->connect ...
$dbh->do('SET NAMES \'utf8\';') || die;
Enjoy :)
Thomas,
With the risk of extra negative points, I don't know if this is still needed, but in the past I needed to make sure my DBI behaved properly with utf8 by doing:
my $dbh = DBI->connect(...);
$dbh->{mysql_enable_utf8} = 1;
$dbh->do("set names 'utf8';");
Maybe it can be of help
First of all my condolances about your latin->utf8 job. I did that for a large application a few years back and the wrinkles it got me still haven't worn off.
What I recommend you to do is turn everything into UTF8 and not try to do decoding and stuff. That will definitely screw up somewhere. storing utf8 data in a latin table is a recipe for disaster. I remember at one point having double and tripple encoded utf8 strings in my database and no way to tell how to get back the original string.
The steps you should take:
Create a secondary database structure with UTF8 collated table instead of latin
extract everything out of your primary database and insert into the new database (hoping you haven't stored any utf8 strings in there yet)
make sure the Mime headers your application sends the browser specifies the encoding is in utf8, all data you get back from these pages automatically take the encoding of the page itself
cross your fingers and take a vacation...
You shouldn't have to change much in your application since the DBI utf8 handling is fairly good at this time.
Good luck!
Rob
Have a look at this. It is fairly general but it will get your lexicon straight and though many examples are in python, per is also there. BTW, if you try to stuff latin-1 (or other) encoded stuff without decoding/reencoding, disaster will ensue.
For more help, post specifics.
Cheers
You'll find a complete (and tested) guide here.
It misses nothing out; Perl, DBI and MySQL. All utf8'd.
I had similar pain but got it all done in the end.

Connecting to a remote MySQL server from a Delphi program through SSL

I don't have a good knowledge of SSL principles, but just want the encryption to work for me.
I have a DB and a user with "REQUIRE X509" specified.
The necessary certificates have been created as described in MySQL docs, and work well - i can connect to the server from Windows command line.
The problem arises, when i try to do the same from my program using MySQL Client API (without SSL, the program also works fine).
The unit used is: http://www.audio-data.de/mysql.html.
These are my action paths:
1) if i just add mysql_ssl_set() call (with proper params) before mysql_real_connect(), the last one gives generic SSL Connection Error.
2) the MySQL docs in en/mysql-ssl-set.html say, that the function always returns 0. But when i checked that, it appeared that the result is the number 11150848. Then i wrote it like that:
showmessage(inttostr(mysql_ssl_set(mys, '.\certs\client-key.pem', '.\certs\client-cert.pem', '.\certs\ca-cert.pem', nil)));
...and repeated the line 8 times.
Each time it returned a slightly greater number - 11158528, 11158784, 11159040, ... and two zeroes for the last two calls.
After which mysql_real_connect() was finally successful! The program even managed to execute some queries, return proper results for them (i know the data), but then it crashed with an Access Violation: write of address ... at some place.
The crash point varied between runs and slight changes to code.
It looks much like a version incompatibility issue. I tried libraries from both MySQL 5.0 and 5.1 Windows installations (the server is 5.1 and runs under Linux remotely; however, 5.0 mysql-client programs do not have troubles when SSL-connecting to it), but with no success.
Is anybody familiar with the issue? Thanks a lot for the help & sorry for the mistakes in the question.
As I see the mysql_ssl_set declaration is incorrect. It is declared:
function mysql_ssl_set(_mysql: PMYSQL; key, cert, ca, capath: PAnsiChar): longint; stdcall;
But the mysql.h contains:
my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key,
const char *cert, const char *ca,
const char *capath, const char *cipher);
That explains the garbage in return value, AV's and so on.