【问题标题】:Encryption / Security on a WebAppWebApp 上的加密/安全性
【发布时间】:2013-09-17 01:19:39
【问题描述】:

我们有一个 Web 应用程序,它是用 Java 编写的,并将数据存储到 PostgreSQL 数据库中。

我们想加密我们数据库中的一些字段,以及一些上传的文档。但是,这些都需要双向加密(即,我们需要能够解密它们),并且解密需要相当快。

但是,我们无法提出一种“安全”的方法来实际加密/解密数据。因为这是一个网络应用程序,并且没有客户端,所以所有的加密密钥都将存储在网络服务器(明文或我们的实际代码)或数据库服务器上。

关于如何真正做到至少适度...安全的任何其他想法?

【问题讨论】:

    标签: java encryption


    【解决方案1】:

    不,没有。如果您的业务层必须访问原始(未加密)数据,那么任何可以破解您的业务层的人(即查看存储在您的应用程序代码中的一些关键字或您的应用程序可读的文件)也可以访问数据。另见related question

    使用应用程序可读的解码密钥实现一些加密只能为您提供轻微的保护,使其免受临时数据间谍以及某些用户角色或案例的影响(例如:可以读取数据库但不能读取 web 应用程序的 DBA;或偷了数据库的转储等)。但仅此而已。

    【讨论】:

    • 请参阅我的答案,了解如何是的,有办法。
    • @Borealid:是的,有一些方法......对于大多数情况来说是不切实际的。例如,“每次应用程序启动时手动提供密码”对于 Web 应用程序来说几乎是不切实际的。
    • 如果您将密码留在应用程序源(或配置文件)中,那么攻击者仍然需要物理获取令牌才能危害您。安全性和可用性之间总是需要权衡取舍。
    【解决方案2】:

    您实际上可以使这更安全。

    如果您使用带有 PKCS11 接口的智能令牌,在令牌上生成一个密钥对,然后在每次应用程序启动时使用手动提供的密码保护对密钥对的安全访问,那么您以后可以随时删除通过删除令牌来读取数据的能力。如果需要容错,请使用一对令牌进行双重加密。

    这里的重要原则是私钥对应用程序可用,但对应用程序可读。因此,查看应用程序源代码一无所获。

    此解决方案不会阻止在您的应用程序运行时访问您的应用程序的人读取您的数据。但无论如何你都无法阻止——他们可以在加密之前从内存中读取你的数据。

    如果正确实施,这将安全地保护您免受所有形式的离线攻击。黑客无法在物理上破解一个好的硬件令牌。不知道密码就无法提取密钥。无法猜出密码,因为令牌对暴力攻击具有硬件限制。因此,恢复数据的唯一方法是窃取令牌密码,或者暴力破解数据加密密钥(可能是 2048 位 RSA 证书)。

    【讨论】:

      【解决方案3】:

      AES 是一个完善的对称加密标准,JDK 中内置了对它的支持,因此我建议您使用它。

      现在,您非常正确地认为密钥需要以您的应用程序可以访问的方式存储。但是,您可以将密钥“拆分”到不同的物理位置,而不是将密钥存储在您的代码或文件中,以使内部人员更难破解您的加密。例如:

      1. 在开发时,生成一个新的 键并将其“硬编码”到您的 程序。将此键称为 A。

      2. 在安装时,生成一个 第二把钥匙。调用这个键 B。现在 用密钥 A 加密密钥 B 并存储 它的加密版本在 文件系统。使文件可读 仅对在其下的用户 服务器运行。

      3. 对于您加密的每个值(例如, 每个信用卡号),生成一个 第三把钥匙。调用此密钥 C. 使用密钥 C 对值进行加密。然后加密 密钥 C 与密钥 B 并存储 它里面的加密版本 数据库。 (您可以使用单独的 同一个表中的字段。)

      要解密,您将从数据库中读取加密的密钥 C,并从文件系统中读取加密的密钥 B。使用 Key A 解密 Key B,使用 Key B 解密 Key C,然后使用 Key C 解密该值。

      这一切能给你带来什么?这个想法是将部分秘密传播到几个不同的地点,最好由不同的人群控制。任何想要破解加密值的人都需要访问所有三个项目:程序代码、文件和数据库。您可以更进一步,向链中添加更多密钥,但您明白了。

      【讨论】:

      • @Rob H:这是隐蔽的安全性,因为破坏应用程序会危及密钥 C 并绕过整个链。
      • 不确定您所说的“损害应用程序”是什么意思。如果您的意思是查看源代码,那不是真的,因为您无法仅使用源代码来解密 Key C。
      • @Rob H:控制应用程序或访问其内存,通过代码注入、对正在运行的服务器的 root 访问、冷启动攻击、侧信道泄露等。 Key C在应用程序运行时被解密,因此容易受到攻击。
      • 嗯,当然,但大多数威胁存在于任何方法中,包括您在自己的答案中提出的方法。 ;-) 我的方法可以防御无权访问正在运行的 Web 服务器但可能有权访问源代码或数据库(或两者兼有)的流氓开发人员或 DBA。至于冷启动攻击,您可以将密钥 B 放在一个加密文件系统中,该文件系统在启动时手动解锁或使用硬件令牌。但很明显,没有什么可以完全保护对正在运行的服务器和数据库具有完全访问权限的人。
      • @Rob H:不同之处在于,在我提出的解决方案中,能够被动读取内存不会危及整个数据库。相反,它只会破坏攻击者正在观察时主动解密的密钥。这就是必须告诉十几个在错误时间登录的用户遭到入侵与必须重新发布整个系统中的每个密码之间的区别。
      【解决方案4】:

      相当老的问题,但为了记录,我将我想出的解决方案描述为我自己的解决方案,这对我来说看起来很安全。

      在管理员用户创建其帐户期间,我生成随机加密密钥。然后使用管理员密码在 AES 中对该密钥进行加密并存储在数据库中。管理员密码也受到保护(通过散列或任何弹簧密码编码器)。在这个阶段,没有人可以访问真正的加密密钥。

      当管理员登录时,他给出了明文密码,与加密的用户密码进行比较。如果正确,则用于解密加密密码,忘记了。然后将加密密码保存在会话中。这是此机制的唯一漏洞——如果有人侵入服务器并进行内存转储,则可以访问密码,但仅限于当前登录的用户,并且永远不会只有应用程序或数据库。我目前正在考虑为此添加另一个级别的安全性(例如,通过例如用户登录时间来加密内存中的密码)。但是,无论如何,即使您要求用户在每个请求中输入密码,您也不能保证它何时被 GC 从内存中踢出,并且您需要在某个时候将其放入内存中。

      因此,用户会话知道加密密码,然后用于加密和解密。当管理员创建新用户时,他可以在此期间访问未加密的密码 - 当他为新用户输入新密码时,会创建另一个加密密码副本并保存在数据库中,由该用户密码加密,等等。

      除了有人入侵正在运行的服务器并转储内存之外,您是否发现此机制的任何其他漏洞?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-05
        • 1970-01-01
        相关资源
        最近更新 更多