首页 > 解决方案 > Nodejs Crypto加密字符串存储在MySQL中后无法正确解密

问题描述

我有一个简单的 nodejs 应用程序,它存储来自外部服务的令牌,在数据库受损的情况下将它们存储为纯字符串是不安全的,所以我需要对它们进行加密。

将以下 github 要点复制并粘贴到我的应用程序simple-nodejs-iv-encrypt-decrypt.js

我能够成功加密和解密我的字符串,但是一旦将加密的字符串保存到MySQL它就不再解密为匹配的字符串

我的 MySQL 列已格式化encryptedToken VARCHAR(255)

// before storing to database
{ 
  encryptedToken: 'OKWLlYEsCtddWQOL8ezQBI+whtU30gVs67nGiRLxxca10Y4AELjMZN3afVzuys17leE9U9Ski+fByaEXFTXnefDUdyR4PUwJBi6poY1RHOY=',
  decryptedToken: 'Z4XkR0vkrbAO6LzmaYGYa0dnaaxvlkIme27L-GlPB7l6M4gkikz1S_vTfJyCUJMx' 
}

// after storing to database
{
  encryptedToken: 'OKWLlYEsCtddWQOL8ezQBI+whtU30gVs67nGiRLxxca10Y4AELjMZN3afVzuys17leE9U9Ski+fByaEXFTXnefDUdyR4PUwJBi6poY1RHOY=',
  decryptedToken: ':D�\b�O3Qlס��,,\u0017aYGYa0dnaaxvlkIme27L-GlPB7l6M4gkikz1S_vTfJyCUJMx'
}

使用的算法是aes256,编码是base64

标签: mysqlnode.js

解决方案


我相信这是因为您每次都使用不同的 IV(初始化向量)。

每次调用时,encryptionHelper 函数 getKeyAndIV 都会创建一个随机 IV,因此解密将不是确定性的。

如果您确保每次都使用相同的 IV,则解密的令牌也应该相同。

我已经这样测试了:

SQL

create table tokens (encryptedToken varchar(255))

Javascript/Node.js

const encryptionHelper = require("./simple-nodejs-iv-encrypt-decrypt.js")

// This could be anything
const token = "abcdefghijklmonp";

// We're using fixed values here. In reality you could use a different IV for each row, it's ok to store this in the database.
const key = Buffer.from("MTIzNDU2Nzg5MGFiY2RlZmdoaWprbG1ub3BxcnN0dXY=", "base64");
const iv =  Buffer.from("26vFZGhH66xFszo59pEaWA==", "base64");

const encryptedToken =  encryptionHelper.encryptText(encryptionHelper.CIPHERS.AES_256, key, iv, token, "base64");

// con should be initialized with a connection to the relevant db.
con.query("insert into tokens (encryptedToken) values (?)", [encryptedToken ], (error, results) => {
    if (error) {
        console.error("Insert query failed: ", error);
    } else {
        console.log("Token insert successful!");
    }

});

con.query("select * from tokens", (error, results) => {
    if (error) {
        console.error("Select query failed: ", error);
        return;
    }

    console.log("Tokens (encrypted):", results.map(r => r.encryptedToken));
    console.log("Tokens (decrypted):", results.map(r => encryptionHelper.decryptText(encryptionHelper.CIPHERS.AES_256, key, iv, r.encryptedToken, "base64").toString("base64")));
});

// Let's just ensure con is closed
setTimeout(() => {
    con.end()
}, 100);

推荐阅读