📜  节点JS |使用 Crypto 模块进行密码散列

📅  最后修改于: 2021-10-21 05:33:56             🧑  作者: Mango

在具有用户身份验证功能的实际应用程序中,将用户密码作为原始字符串存储在数据库中是不切实际的,但将密码散列然后将它们存储到数据库中是一种很好的做法。

Node JS 的加密模块帮助开发人员散列用户密码。

例子:

Original Password : portalforgeeks
Hashed Password : bbf13ae4db87d475ca0ee5f97e397248a23509fc10c82f
1e3cf110b352c3ca6cc057955ace9d541573929cd7a74a
280a02e8cb549136b43df7704caaa555b38a

使用 Crypto 模块进行密码散列

为了演示 Crypto 模块的使用,我们可以创建一个简单的登录和注册 API 并使用 Postman 对其进行测试。
我们将使用两个函数:

  1. cryto.randomBytes(“length”) :生成给定“长度”的加密强数据。
  2. crypto.pbkdf2Sync(“password”, “salt”, “iterations”, “length”, “digest”) :用“salt”散列“password”,迭代次数等于给定的“iterations”(更多的迭代意味着更安全的密钥) 并使用“摘要”中给出的算法并生成长度等于给定“长度”的密钥。

项目依赖:

  • 节点 JS:用于后端服务器。
  • 用于创建服务器的 express 模块。
  • 用于 MongoDB 连接和查询的 mongoose 模块。
  • 用于散列的加密模块。
  • 用于解析 json 数据的 body-parser。

执行操作的步骤

  1. 首先创建如下目录结构:
    hashApp
    --model
    ----user.js
    --route
    ----user.js
    --server.js
    
  2. 创建定义用户架构的模型/user.js 文件
    // Importing modules
    const mongoose = require('mongoose');
    var crypto = require('crypto');
      
    // Creating user schema
    const UserSchema = mongoose.Schema({
        name : {
            type : String,
            required : true
        },
        email : {
            type : String,
            required : true
        },
        hash : String,
        salt : String
    });
      
    // Method to set salt and hash the password for a user
    // setPassword method first creates a salt unique for every user
    // then it hashes the salt with user password and creates a hash
    // this hash is stored in the database as user password
    UserSchema.methods.setPassword = function(password) {
         
     // Creating a unique salt for a particular user
        this.salt = crypto.randomBytes(16).toString('hex');
      
        // Hashing user's salt and password with 1000 iterations,
        64 length and sha512 digest
        this.hash = crypto.pbkdf2Sync(password, this.salt, 
        1000, 64, `sha512`).toString(`hex`);
    };
      
    // Method to check the entered password is correct or not
    // valid password method checks whether the user
    // password is correct or not
    // It takes the user password from the request 
    // and salt from user database entry
    // It then hashes user password and salt
    // then checks if this generated hash is equal
    // to user's hash in the database or not
    // If the user's hash is equal to generated hash 
    // then the password is correct otherwise not
    UserSchema.methods.validPassword = function(password) {
        var .hash = crypto.pbkdf2Sync(password, 
        this.salt, 1000, 64, `sha512`).toString(`hex`);
        return this.hash === hash;
    };
      
    // Exporting module to allow it to be imported in other files
    const User = module.exports = mongoose.model('User', UserSchema);
    
  3. 创建路由/user.js 文件:
    // Importing modules
    const express = require('express');
    const router = express.Router();
      
    // Importing User Schema
    const User = require('../model/user');
      
    // User login api
    router.post('/login', (req, res) => {
      
        // Find user with requested email
        User.findOne({ email : req.body.email }, function(err, user) {
            if (user === null) {
                return res.status(400).send({
                    message : "User not found."
                });
            }
            else {
                if (user.validPassword(req.body.password)) {
                    return res.status(201).send({
                        message : "User Logged In",
                    })
                }
                else {
                    return res.status(400).send({
                        message : "Wrong Password"
                    });
                }
            }
        });
    });
      
    // User signup api
    router.post('/signup', (req, res, next) => {
         
     // Creating empty user object
        let newUser = new User();
      
        // Initialize newUser object with request data
        newUser.name = req.body.name,
      
        newUser.email = req.body.email
      
                        // Call setPassword function to hash password
                        newUser.setPassword(req.body.password);
      
        // Save newUser object to database
        newUser.save((err, User) => {
            if (err) {
                return res.status(400).send({
                    message : "Failed to add user."
                });
            }
            else {
                return res.status(201).send({
                    message : "User added successfully."
                });
            }
        });
    });
      
    // Export module to allow it to be imported in other files
    module.exports = router;
    
  4. 创建 server.js 文件:
    // Importing modules
    var express = require('express');
    var mongoose = require('mongoose');
    var bodyparser = require('body-parser');
      
    // Initialize express app
    var app = express();
      
    // Mongodb connection url
    var MONGODB_URI = "mongodb://localhost:27017/hashAppDb";
      
    // Connect to MongoDB
    mongoose.connect(MONGODB_URI);
    mongoose.connection.on('connected', () => {
        console.log('Connected to MongoDB @ 27017');
    });
      
    // Using bodyparser to parse json data
    app.use(bodyparser.json());
      
    // Importing routes
    const user = require('./route/user');
      
    // Use user route when url matches /api/user/
    app.use('/api/user', user);
      
    // Creating server
    const port = 3000;
    app.listen(port, () => {
        console.log("Server running at port: " + port);
    });
    
  5. 使用命令 node server.js 从 hashApp 目录运行 server.js 文件
  6. 打开 Postman 并创建一个 post 请求到 localhost:3000/api/user/signup 如下:

    您将得到如下响应:

    用户数据存储在数据库中,如下所示:

    {
        "_id": {
            "$oid": "5ab71ef2afb6db0148052f6f"
        },
        "name": "geeksforgeeks",
        "email": "geek@geeksforgeeks.org",
        "salt": "ddee18ef6a6804fbb919b25f790005e3",
        "hash": "bbf13ae4db87d475ca0ee5f97e397248a23509fc10c82f1e3cf110
         b352c3ca6cc057955ace9d541573929cd7a74a280a02e8cb549136b43df7704caaa555b38a",
        "__v": 0
    }
    
  7. 从 Postman 创建一个 post 请求到 localhost:3000/api/user/login 如下:

    您将得到如下响应:

应用:

  • 实际应用需要散列密码。
  • 加密模块使散列易于实现。
  • 散列密码可确保用户的隐私。

参考:

  • https://nodejs.org/api/crypto.html
  • https://nodejs.org/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_digest_callback