In the face of the network world, password security is always a matter of great concern to all companies and users. After all, people consume online accounts for both entertainment and shopping, so we usually encrypt users’ passwords. When encrypting, you often hear the word “salt.” What does that mean?

The user’s password is usually hashed, and without salt, even a two-layer MD5 can be cracked using a rainbow table. A rainbow table is a Hash of various character combinations collected on the web. Adding salt is artificially combining a group of random characters with the user’s original password to form a new character, thus increasing the difficulty of deciphering. Just like cooking, it tastes better with salt.

Next, let’s use code to demonstrate a safer way to add salt.

First, let’s build a simple user table. There are only four fields in this table, which is used here only as a test.

CREATE TABLE `zyblog_test_user` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `username` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'Username',
    `password` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'password',
    `salt` char(4) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'salt'.PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
Copy the code

Then define two methods, one for generating the salt and one for generating the Hash password after the salt is added.

/** * randomly generates a four-digit string of salt *. You can also use a 6-digit or longer salt */ as required
function generateSalt()
{
    // Generate a random four-digit character
    $chars = array_merge(range('A'.'Z'), range('a'.'z'), range('0'.'9'));
    for ($i = 0; $i < 4; $i{+ +)$str. =$chars[mt_rand(0, count($chars) - 1)];
    }
    return $str;
}

/** * Password generation * uses a two-layer hash, add salt to the second layer * sha1, then add salt and then md5 */
function generateHashPassword($password.$salt)
{
    return md5(sha1($password).$salt);
}
Copy the code

The generateSalt() method is very simple and simply generates a random four-character string, which we generate in case plus numbers. This is the legendary “salt”.

We can then use the generateHashPassword() method to salt the user’s old password. Here, we Hash the original password using SHA1 () at the first layer, and then use this Hash value to splice salt string before md5() encryption. The resulting Hash value is hard to find in the rainbow table. Even if found, it is only the content of the upper sha1() concatenated salt string, after all, the user’s original password has a layer of encryption.

All that’s left is for us to do the login and registration tests.

$pdo = new PDO('mysql:host=localhost; dbname=blog_test; charset=utf8mb4'.'root'.' ');

$username = 'ZyBlog1';
$password = '123456';

/ / register
function register($username.$password)
{
    global $pdo;

    // First check whether the user is registered
    $pre = $pdo->prepare("SELECT COUNT(id) FROM zyblog_test_user WHERE username = :username");
    $pre->bindParam(':username'.$username);
    $pre->execute();
    $result = $pre->fetchColumn();

    // If the user name exists, the user cannot be registered
    if ($result > 0) {
        echo 'Username registered! ', PHP_EOL;
        return 0;
    }

    / / generates a salt
    $salt = generateSalt();
    // Hash the password with salt
    $password = generateHashPassword($password.$salt);

    // Insert a new user
    $pre = $pdo->prepare("insert into zyblog_test_user(username, password, salt) values(? ,? ,?) ");

    $pre->bindValue(1.$username);
    $pre->bindValue(2.$password);
    $pre->bindValue(3.$salt);

    $pre->execute();

    return $pdo->lastInsertId();
}

$userId = register($username.$password);
if ($userId > 0) {
    echo 'Registration successful! User ID: ' . $userId, PHP_EOL;
}

// Successful registration! The user ID is 1

// Query data in the database
$sth = $pdo->prepare("SELECT * FROM zyblog_test_user");
$sth->execute();

$result = $sth->fetchAll(PDO::FETCH_ASSOC);
print_r($result);

// Array
/ / (
// [0] => Array
/ / (
// [id] => 1
// [username] => ZyBlog1
// [password] => bbff8283d0f90625015256b742b0e694
// [salt] => xOkb
/ /)

// )

// Verify at login
function login($username.$password)
{
    global $pdo;
    // Start table lookup by user name
    $pre = $pdo->prepare("SELECT * FROM zyblog_test_user WHERE username = :username");
    $pre->bindParam(':username'.$username);
    $pre->execute();
    $result = $pre->fetch(PDO::FETCH_ASSOC);

    // The user name exists and the user information is obtained
    if ($result) {
        // Generate hash passwords based on the salt field in the user table
        $password = generateHashPassword($password.$result['salt']);

        // Compare the hash password to verify the login
        if ($password= =$result['password']) {
            return true; }}return false;
}

$isLogin = login($username.$password);
if ($isLogin) {
    echo 'Login successful! ', PHP_EOL;
} else {
    echo 'Login failed, wrong username or password! ', PHP_EOL;
}

// Login successful!
Copy the code

The code is relatively simple, at the time of registration, we directly encrypt the user password into the library. The main concern is that when we log in, we first find out the corresponding user information according to the user name. Then the original password submitted by the user login is encrypted and compared with the original password in the database for verification. The successful password verification can determine the successful login of the user.

It is also important to note that our salt string is also stored in the database. After all, when we log in, we still need to combine the user’s original password with the salt string before encrypting the password to match.

This encrypted code is actually very difficult to break through the rainbow table. In the account breach of CSDN a few years ago, it was discovered that the largest website in the world for Chinese programmers stored passwords in clear text, which provided attackers with a large number of users’ common passwords in clear text. Because everyone likes to use the same user name and password for different sites, so it’s no use no matter how other add salt, after all, the original password is right, to such a site user text passwords in the database, you can through the password to the user did in other sites use the same account name and password to register the account. So in daily life, some of our important website accounts and passwords try to use different content. If you can’t remember them, you can use some notepad software with encryption ability to save them, which will be more secure. We programmers, on the other hand, should always encrypt passwords and important information, which is a basic professional norm.

Test code:

Github.com/zhangyue050…