如何用NodeJS进行数据加密的初级指南

552 阅读9分钟

用NodeJS进行数据加密的新手指南

没有加密,Web开发就无法生存。

随着网络应用不断获得属于人们、组织甚至政府的大量敏感数据,数据安全的威胁也达到了前所未有的高度。从编程的早期开始,程序员就使用密码学和加密技术来保护这些敏感数据不受恶意攻击。特别是在引入互联网和万维网之后,密码学技术在保证数据安全方面发挥了关键作用。

在网络开发中,密码学经常被用来保障数据在网络上传输或存储在数据库中的安全。大部分的加密操作都是在网络后端执行的。这就是为什么,作为一个Node开发者,你应该了解如何加密和解密数据,以确保系统处理的数据安全。

这篇文章将介绍在Web开发中用于保护数据安全的基本加密技术,并看看如何用Node.js实现它们。Node提供了一个名为crypto的内置模块来轻松实现这些任务。

作为第一步,我们必须了解到底什么是密码学(和加密)以及它是如何工作的。


什么是密码学?

密码学不是一个东西。它是一个完整的研究领域,涉及到保持数据安全的技术。为了实现这一目标,它主要是将一组初始数据转换为任何没有正确证书的人既不能理解也不能转换回其初始形式的东西。一些加密技术可以保证外部人员没有改变这些数据。

加密过程中有三个重要成分:明文、密文和一个算法。加密算法将明文数据转换为密文,即初始数据的加扰和不可识别的形式。该算法使用数学计算进行这种转换。

通常情况下,加密算法在将明文转换为密码文本时使用一种叫做密钥的东西。只有当你带着正确的密钥时,才有可能将密码文本转换回明文。因此,那些有权限查看明文的人必须将这把钥匙储存在最高安全级别,不要让它落入外人手中。


什么是加密技术?

虽然加密和密码学这些术语有时可以互换使用,但它们并不是一回事。

加密是使用一种算法将明文转换为密文的过程。它只是密码学的一个方面。加密的反面,即把密码文本转换回明文的过程,被称为解密。

在密码学中,我们可以找到许多用于转换明文的加密算法。


密码学的类型

密码学有三种基本类型:对称密钥密码学、非对称密钥密码学和散列。让我们看看每一种在数据安全方面的重要性。

对称密钥加密法

在上一节中,我们讨论了加密算法如何在将明文转换为密文时使用密钥,反之亦然。在对称密钥加密法中,用于将明文转换为密码文本的密钥和用于将密码文本转换为明文的密钥是相同的。这种类型的密码学实施起来很简单,而且比其对应的非对称密钥密码学要快。

但对称密钥加密法有一个主要的安全问题。当对通过网络传输的数据进行加密时,这种方法要求发送方和接收方都拥有用于加密的密钥。这就造成了一个加密密钥可能被第三方破坏的情况。

当发送方和接收方试图通过网络交换加密密钥时,第三方就有机会窃取密钥。特别是当上述网络是互联网时,交换密钥的风险很高。

非对称密钥加密法

非对称密钥加密法的出现是为了克服对称密钥加密法的安全问题。它使用一对钥匙,而不是一把,称为公钥和私钥。公钥只用于加密数据。私钥仅用于解密数据。你不能用公钥来解密用它加密的数据,反之亦然。

这种配对钥匙系统的特点是,即使公钥在接收方或发送方以外的其他各方之间共享,也不会损害系统的安全性。由于公钥在解密中是无用的,偷窃公钥不会有机会读取加密的和私人的用户数据。

散列

散列与上述两类密码学不同。

对称和非对称密码学促进了明文到密文以及密文到明文的转换。然而,在散列中,你只有一个选择:将明文转换为密码文。一旦明文被 "散列",你就不能把它转换回来以检查其原始内容。

你可以做的是检查另一个明文是否产生了相同的哈希值,看看两个明文是否相等。这是可能的,因为散列算法保证每个独特的明文产生一个独特的密码文本。

散列在存储密码时经常使用。应用程序从不在其数据库中存储明文密码。相反,他们存储密码的散列。当验证一个用户时,我们必须检查用户提供的密码所产生的哈希值是否等于存储在数据库中的密码。如果提供的密码的哈希值等于存储的哈希值,那么系统就可以验证该用户。

与对称和非对称密码学不同,散列在散列过程中不使用密钥。


用Node.js加密

Node.js有内置模块crypto,它提供了进行加密操作的函数。它包括一套对OpenSSL的哈希、HMAC、密码、解密、签名和验证函数的封装。

在本节中,我们将看到如何使用crypto模块实现加密。在我们开始之前,你必须设置好你通常的Node项目环境,并使用npm安装crypto模块。

用Node.js对数据进行加密

我们可以使用crypto模块的Cipher类来加密数据。因此,让我们来实现加密功能:

const crypto = require("crypto");

const algorithm = "aes-192-cbc";

const encrypt = (text) => {
  //generate encryption key using the secret.
  crypto.scrypt(process.env.SECRET, 'salt', 24, (err, key) => {
    if (err) throw err;

    //create an initialization vector
    crypto.randomFill(new Uint8Array(16), (err, iv) => {
      if (err) throw err;

      const cipher = crypto.createCipheriv(algorithm, key, iv);

      let encrypted = '';
      cipher.setEncoding('hex');

      cipher.on('data', (chunk) => encrypted += chunk);
      cipher.on('end', () => console.log(encrypted))
      cipher.on('error', (err) => console.log(err))

      cipher.write(text);
      cipher.end();
    });
  });
}

encrypt('hello World');

当用crypto模块加密时,我们可以选择在每次调用encrypt方法时生成一个新的密钥。使用不同的密钥进行加密,使攻击者更难用暴力破解数据。

然而,为了生成一个密钥,我们对加密和解密都使用一个共同的秘密。如果解密数据的一方无法获得用于生成加密密钥的秘密,那么解密过程就会失败。

我们使用的加密算法是AES(高级加密标准)192比特(24字节)算法。这里的192位表示密钥的长度。你可以看到我们是如何将密钥长度作为24传递给生成密钥的scrypt函数的。

当创建一个新的密码对象时,我们传递一个叫做初始化向量(IV)的参数。它通常被添加到密码文本中而不经过加密过程。它用于避免密码文本中的重复,这样攻击者就无法通过识别加密数据中的模式来破译数据。因此,IV应该始终是不可预测的和唯一的。出于这个原因,这个实现使用随机填充函数生成一个新的IV。

最后,数据加密是使用写函数完成的。每当加密的数据流中出现一个数据块时,密码对象就会触发 "数据 "事件,然后将该数据块追加到加密的字符串中。我们可以通过触发 "end "事件来检测加密何时结束。我们使用另一个事件,"error",来检测在加密文本时抛出的错误。

用Node.js解密数据

为了解密数据,我们使用crypto模块的Decipher类。它的实现类似于数据加密的实现方式。我们使用秘密创建一个新的加密密钥,然后开始用该密钥解密密码:

const decrypt = (encrypted, iv) => {
  //generate encryption key using secret
  crypto.scrypt(process.env.SECRET, 'salt', 24, (err, key) => {
    if (err) throw err;

    //create decipher object
    const decipher = crypto.createDecipheriv(algorithm, key, iv);

    let decrypted = '';
    decipher.on('readable', () => {
      while (null !== (chunk = decipher.read())) {
        decrypted += chunk.toString('utf8');
      }
    });
    decipher.on('end', () => console.log(decrypted));
    decipher.on('error', (err) => console.log(err))

    decipher.write(encrypted, 'hex');
    decipher.end();
  })
}

为了解密密码文本,你需要在加密函数中传递用于加密数据的IV。

用Node.js进行哈希运算

用加密函数实现散列函数是非常简单的。下面是我们创建的哈希函数:

const hash = text => {

  const hash = crypto.createHash('sha256');

  hash.on('readable', () => {

    const data = hash.read();
    if (data) {
      console.log(data.toString('hex'));
    }
  });

  hash.write(text);
  hash.end();
}

sha256是我们在这个实现中使用的哈希算法。使用这种算法,它可以很容易地用写函数创建一个哈希文本。当哈希数据在流中可用时,它就会触发 "可读 "事件,我们就可以检索到哈希字符串。


总结

在今天的文章中,我们讨论了密码学和数据加密的基础知识。我们还在Node.js中用其内置的crypto模块实现了加密操作。由于数据加密对开发网络应用程序至关重要,你可以直接应用我们今天学到的东西,在未来建立更安全可靠的应用程序。如果你想阅读更多关于Node的crypto模块所支持的其他类型的加密操作,请在这里阅读Node的官方文档。

密码学是一个广阔而迷人的研究领域。它提供的数据保护方法比我们在这篇文章中讨论的要多。你对这些方法了解得越多,它们就越有利于你作为一个网络开发者建立更好的应用程序。因此,不要从这篇文章中停止学习加密和密码学技术。做你自己的研究并学习更多。