使用 CryptoJS 的基于 Web 的秘密管理器

信息安全 加密 解密 秘密分享
2021-09-12 12:49:43

我正在构建一个应用程序,其中一部分将允许企业存储秘密。

我正在考虑使用 CryptoJS ( https://www.npmjs.com/package/crypto-js )。这将加密客户端的所有内容,并在将其保存到我们的数据库之前使用 HTTPS 将其发送到服务器端。我们的服务器永远不会接收到纯文本机密或将其存储在我们的数据库中。

来自 CryptoJS 的文档:

var CryptoJS = require("crypto-js");

// Encrypt
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString();

// Decrypt
var bytes  = CryptoJS.AES.decrypt(ciphertext, 'secret key 123');
var originalText = bytes.toString(CryptoJS.enc.Utf8);

console.log(originalText); // 'my message'

我们会提示用户提供解密密钥(在上面的示例中为“密钥 123”),我们会对其提出一些要求,例如最小字符长度,包括数字、特殊字符等。

从安全的角度来看,考虑到用例,您认为此设置有什么问题吗?

以前的一些人建议研究 HashiCorp 的 Vault,我已经完成了它并将其作为概念证明,但是对于这个用例来说价格太高了(估计每家公司每月的成本约为 150 美元托管 HashiCorp Cloud Vault 的标准计划,我们不想自行托管我们自己的 Vault 服务器)。

2个回答

潜在问题:

  1. 你设想什么样的客户?如果它是基于 Web 的,或者任何其他从服务器中提取代码(脚本等)的东西,那么就不可能使其免受恶意或受损服务器的侵害。攻击者只需发送一个额外的脚本——可能只发送给特定的目标用户——窃取密码、加密密钥、明文机密或其他任何所需的内容。
  2. 用户如何向服务器进行身份验证?如果是通过密码,这是否意味着他们必须记住两个密码才能使用您的应用程序?如果它是相同的密码,您需要确保服务器不可能看到或派生密码。
  3. 您有任何计划以任何方式处理忘记的密码吗?像这样的系统通常很难解决这个问题。
  4. 您是否有让用户更改密码而不需要解密每个项目并使用新密码重新加密的计划?通常的方法是分层系统,其中有一个“主密钥”用于实际加密/解密数据,并且它本身使用密码派生密钥进行加密(这样,只需要重新加密主密钥,不是一切)。
  5. 您是否希望在服务器端对数据进行任何数据处理(例如搜索、分析、任何形式的转换或分析)?像这样的系统是不可能的。
  6. 您想支持与其他用户安全地共享数据吗?可以这样做,但是您需要为此使用公钥(非对称)加密,并且如果您不希望用户需要信任服务器,那么他们需要能够验证对方的公钥。
  7. 您将如何保护加密数据的完整性?加密本身并不能防止篡改数据。
  8. 您是否正在采取任何措施来防止填充预言机?所描述的系统显然不是很容易受到它们的攻击,但是如果您将 CBC 与 PKCS7 一起使用(这是该库的默认设置),则需要考虑它们。

在更普遍的关注层面上:恭敬地,您没有设计这样的系统所需的知识。它既出现在您的设计中未解决的上述主题之类的事情中,也出现在您说您打算做的一些事情中(一些示例:向库传递用户提供的字符串而不是从中派生密钥)你自己,使用默认密码参数,即使有更好的参数[尽管该库不支持一些最好的],需要“数字,特殊字符等”,就好像这不是毫无意义和看似有害的安全剧院,使用第三方 JS 加密库,而不是内置于现代 JS 引擎(包括浏览器)中的加密库)。

如果您的要求是要求用户输入密钥/PIN/密码(您必须对其进行散列以用于 AES 加密),那么每次用户想要访问他的秘密数据并在浏览器中加密和解密时,是的,这可能是良好的设计取决于您的安全要求。

话虽如此,克里斯在他的回答中指向了 SubtleCrypto。导航到该链接顶部有粗体警告。您确定您的用户永远不会忘记密钥/密码/密码,否则,您将永久锁定他们的内容。如果用户需要存储他们的密钥以记住;这又是一个安全问题,具体取决于您的用户安全要求和威胁感知。

更好的设计是使用存储在智能卡或加密 USB 令牌中的密钥,然后将 PKI 与存储在服务器上的公钥和用户智能卡中的私钥一起使用。参考我的答案