如何使用 React MongoDB 和 Express 正确加密和解​​密密码

How to properly encrypt and decrypt passwords using React MongoDB and Express

目前我在本地机器上的开发环境中工作,我使用 MongoDB 以纯文本形式存储密码。我使用 express-jwtjsonwebtoken 来传递用户数据和身份验证。我已经研究了 bcryptjsbcrypt 并且我想实现最适合 React 和 Express 的那个,以便将散列密码从客户端传递到数据库。我找到了服务器端的资源,但没有找到客户端的资源。

那么我的问题是,当密码从客户端传递时,将加密密码正确保存在我的服务器上的方法是什么?如何在客户端加密密码然后验证服务器端?

我看过一些文章说由于 ssl 不需要加密客户端,但其他人说绝对需要加密客户端。什么是正确的方法,我该如何在我的 React 应用程序上实现它?

您没有解密密码。您向用户询问密码,然后对其进行哈希处理并将其与您保存的存储哈希值进行比较。如果它们相同,那么(假设您有安全的哈希算法)未加密的版本也必须相同。

使用 Bcryptjs、Express 和 MongoDB:

  1. 客户端无需加密,您可以使用 post 请求(通常通过表单)将密码以纯文本形式传递给服务器。

  2. 假设您有一个类似于此的 'user' 架构:

       const userSchema = new mongoose.Schema({
        email:{type:String,required:true,unique:true},
        password:{type:String,required:true}
       },{collection:'users'}
       const User= mongoose.model("User",userSchema);
       )
    
  3. 在服务器 register/sign 上,你处理请求的地方你会散列用户的密码,如下所示:

app.post('/signup',async (req,res)=>{
    // geting our data from frontend
    const {email,password:plainTextPassword}=req.body;
    // encrypting our password to store in database
    const password = await bcrypt.hash(plainTextPassword,salt);
    try {
        // storing our user data into database
        const response = await User.create({
            email,
            password
        })
        return res.redirect('/');
    } catch (error) {
        console.log(JSON.stringify(error));
        if(error.code === 11000){
            return res.send({status:'error',error:'email already exists'})
        }
        throw error
    }
})

4.Upon 登录请求(也将是通过客户端表单的 post),您将使用 bcrpyt.compare() 函数比较密码,如果成功,像这样为用户分配一个 JWT,此方法假定令牌将存储在 Cookies 中。

const verifyUserLogin = async (email,password)=>{
    try {
        const user = await User.findOne({email}).lean()
        if(!user){
            return {status:'error',error:'user not found'}
        }
        if(await bcrypt.compare(password,user.password)){
            // creating a JWT token
            token = jwt.sign({id:user._id,username:user.email,type:'user'},JWT_SECRET,{ expiresIn: '2h'})
            return {status:'ok',data:token}
        }
        return {status:'error',error:'invalid password'}
    } catch (error) {
        console.log(error);
        return {status:'error',error:'timed out'}
    }
}

// login 
app.post('/login',async(req,res)=>{
    const {email,password}=req.body;
    // we made a function to verify our user login
    const response = await verifyUserLogin(email,password);
    if(response.status==='ok'){
        // storing our JWT web token as a cookie in our browser
        res.cookie('token',token,{ maxAge: 2 * 60 * 60 * 1000, httpOnly: true });  // maxAge: 2 hours
        res.redirect('/');
    }else{
        res.json(response);
    }
})

  1. 前端我没有讲,因为在react中只包含基本的POST请求表单,不需要在client-side上做任何特殊的方法或处理。 希望对你有帮助。

编辑、散列client-side: 对此存在争议,在某些协议中,甚至需要在 client-side 上散列密码,简而言之,因为 SSL 已经加密了从客户端移动到服务器的所有内容 client-side 上的散列非常漂亮毫无意义,今天没有被广泛接受,即使是@大公司也是如此。最重要的是,增加的安全性可以忽略不计,不值得麻烦和向客户端公开散列逻辑