【问题标题】:Encrypting a stored image [closed]加密存储的图像[关闭]
【发布时间】:2012-09-23 19:15:34
【问题描述】:

我正在准备一个需要以加密格式存储图像的项目。图片大小在 0.5mb 到 5mb 之间,必须保持原始质量。

我正在考虑使用 base64 对它们进行编码,但是我需要使用一些东西来加密它们(SHA1?)并将它们作为文件保存在服务器上。

有人可以给我建议吗?我可以将加密图像存储在哪种文件中?

提前致谢

【问题讨论】:

  • 为什么需要加密它们?为什么不将它们按原样保存在服务器上?
  • 因为它们是牙科 X 光片,被归类为医疗记录
  • 加密是hard。你需要了解更多。
  • 您应该考虑加密它们还是安全地存储它们
  • 安全存储不需要加密。

标签: php


【解决方案1】:

这个操作并不简单;您不仅需要加密数据,还需要防止服务器被盗或闯入;如果需要更改密钥,您还需要考虑会发生什么。

要加密图像,最好的选择可能是 mcrypt 和 对称 算法。有几个关于如何做到这一点的教程。见What is the best way to encrypt files in AES-256 with PHP?。

您需要做的是提供图像并即时解密,而不是将其存储在明文中。

现在的问题是在哪里保存密码。最好的整体解决方案是为每个用户提供一个秘密加密密钥,在用户登记时随机生成;并且密钥本身使用用户密码非对称加密。您可以使用 phpseclib 在 RSA 中执行此操作。相同的加密密钥也以管理密码不对称存储。

所以工作流程是:

  1. 用户登录(并提供密码)
  2. 系统将密码哈希与存储的哈希进行比较并授予访问权限(您将使用诸如 bcrypt 之类的东西:参见 Is there a bruteforce-proof hashing algorithm?)
  3. 系统还会解码加密字符串并将其存储在临时会话中(会话持久性可能是一个需要解决的问题!)
  4. 他现在可以访问该用户的所有图像

要加密图像: - 如果用户上传图像,则在上传时,会话中的加密密钥可用。用它 :-) - 如果图像以其他方式上传,则在数据库中设置“已加密/仍待加密”标志,并尽快(管理员登录/用户登录)执行所有待处理的加密操作。

然后将图像存储为加密文件(“001823040.bin”)。除了在数据库中,没有参考,它属于哪个用户;并且不知道用户(因此是加密密钥),图像是不可恢复的。

要提供图像,您只需将标题设置为图像类型,然后开始解码文件并将其以明文形式输出到用户的浏览器。

从攻击者的角度来看,只有图像是没有用的,因为它们是加密的。用户数据库是无用的,因为加密密钥本身是加密的。窃取或暴力破解一个用户的密码只能访问该用户的加密密钥,这与所有其他人不同,然后仍然是查找属于该用户的哪些图像的任务。

如果您需要更改用户的密码,您仍然可以使用管理密码恢复加密密钥,并使用用户的新密码进行非对称加密。 这不能自动完成,因为这意味着将现在最重要的管理员密码以明文形式存储在系统中;所以所有忘记密码的用户都排成一排,早上管理员收到“有75人等待密码恢复”的通知,提供密码,然后全部解锁。

这很尴尬,但不幸的是,所有其他解决方案都依赖于在本地以明文形式提供的密码,在这种情况下,安全漏洞会使系统完全打开。

(您有时可以通过设置 second 来解决此限制,该服务器很小,非常有限 - 因此不那么容易受到攻击 - 服务器充当加密托管服务;但要复杂得多维护)。

多用户/密码场景

您在一个表中有资源 A,几个 用户 U1、U2、... Un 有权访问该资源。这意味着用户 U1 必须能够访问资源 A 的解密密钥。

您可以通过存储 UserAccessToResource 表来做到这一点:

user_id         -- the user ID
resource_id     -- the resource ID
encryption      -- resource decryption key, encrypted with the user's encryption **key**

要授予用户 U1 和资源 A 的访问权限,您必须自己有权访问资源 A,和 U1 的加密密钥。那就是:

  • 管理员访问用户表并恢复 UserKeyEncryptedWithAdminKey。
  • 作为管理员,他可以解密 UserKey。
  • 以与他访问 ResourceTable[A].ResourceKeyEncryptedWithAdminKey 相同的方式
  • 他使用 UserKey 加密 ResourceKey 并存储到 UserAccessToResource 中

用户 U5 过来并可以快速验证 (5, 42, ??) 是否存在于 UserAccessToResource 表中,因此他知道他可以访问该资源。检索行,并解密 ResourceKey。他现在可以访问 Resource[42] 并使用 ResourceKey 解密 it(但不能使用其他资源,因为它们具有不同的随机 ResourceKey)。

在所有这些中,前端从未访问(除非编程错误)到 ResourceKey(或 UserKey)的实际值。 API 类似于 DecryptResource(UserId, UserPass, ResourceId) 并返回一个解密的资源。

当然,UserAccessToResource 可以包含任意数量的用户或资源——它是多对多的。对于每一个,都必须存储一个加密密钥(比如 AES 条目的 32 个十六进制字节)。

密码丢失场景

很遗憾,此操作无法自动完成。用户发送请求,但他的密钥无法访问,除非管理员登录。所以他必须等待。

当管理员登录时,系统能够访问 PasswordRecovery 表并找到用户的不完整记录。它访问用户表并检索 UserKeyEncryptedWithAdminKey。

它现在生成一个随机密钥,并使用使用该随机密钥加密的 UserKey 完成 PasswordRecovery 表中的记录。另一列包含使用相同随机密钥加密的“Squeamish Ossifrage”字样。他向用户 123 发送了一封安全电子邮件,提供了随机密钥。

用户 123 向系统提供随机密钥。管理员不再登录,但系统可以检查一旦解密,第二个表字段确实是“Squeamish Ossifrage”。然后假设第一个字段是解密的 UserKey。系统向 User123 请求新密码,并将新的 UserKeyEncryptedWithUserPass 存储到 Users 表中,清除 PasswordRecovery 中的条目。只更新了一条记录。用户 123 拥有的所有资源密钥都使用用户 123 的密钥进行加密,该密钥没有更改,仍然是管理员在创建帐户时随机生成的。

下一次登录,用户提供密码并解锁系统。

【讨论】:

  • 我知道已经有一段时间了,但我真的很喜欢这种方法,因为在攻击者已经破坏了两个文件系统的情况下,用户输入的密码似乎是唯一可以安全加密加密密钥的方法和数据库,只要密码作为哈希存储在数据库中。我有几个关于实施的问题。
  • 我们的应用程序允许多个用户使用具有不同用户名和密码的一个帐户。有没有办法让多个密码同时解密密钥?此外,我们为用户提供了一个忘记密码的链接,以允许用户通过单击我们发送的密码重置电子邮件中的链接来登录他们的帐户。在这种情况下,用户无需提供实际密码即可登录。我想知道如何处理?谢谢!
  • 添加了您所指的两个场景。我希望你会发现这很有用。
  • 我知道我参加聚会有点晚了,但我对这个出色的评论有一些疑问。如果图像是通过其他方式上传的,而不是在用户直接连接时,您会存储未加密的图像,直到拥有它的用户登录?甚至更多,您是否必须存储未加密的图像,直到用户登录,才能创建他可以访问的加密版本,并且您仍然需要存储未加密的图像,直到管理员登录,这样您就可以创建一个也给他加密版本?
  • @AdamBaranyai 管理员有权访问用户加密密钥,该密钥使用管理员加密密钥进行非对称加密。因此,只有在用户或管理员登录之前,您才需要一个纯文本图像。
【解决方案2】:

我必须做一个类似的任务,将上传到我的应用程序中的文件加密存储在服务器中,然后当用户从应用程序中需要该文件时,在发送到浏览器之前解密它们。

我必须这样做,因为我的应用程序处理的是我所在国家/地区的法律要求加密存储的特殊类型的数据(家庭暴力)。所以我理解 OP 的情况,不是他出于技术原因需要对它们进行加密,而是为了遵守法律。

我所做的是在服务器上安装 OpenSSL,以便我可以使用它对文件进行 AES-256 加密,您可以使用 system() 从 php 执行命令。

要加密的命令是:

echo MyPassword | openssl.exe aes-256-cbc -pass stdin -salt -in somefile.pdf -out somefile.pdf

用于解密:

echo MyPassword | openssl.exe aes-256-cbc -pass stdin -d -in somefile.pdf -out decriptedfile.pdf

此命令采用任何原始文件(无论格式如何),并且在解密时会重新创建完全相同的文件,因此无需进行 base64 编码或类似的操作,您提供给它们的内容它们会返回给您。

如果您迁移服务器,请参阅 openssl aes-256 encrypted file on windows cant be decrypted on linux 以了解可能的警告。

【讨论】:

  • 密码存放在哪里?
  • 当时我们有两个选项,在数据库中或在源代码中硬编码,在这两种情况下,密码都需要以纯文本形式存储,如您所见,这两个选项在安全方面同样糟糕,做你有更好的选择吗?
【解决方案3】:

您实际上可以使用此函数执行此操作,例如:http://php.net/manual/en/function.openssl-encrypt.php

【讨论】:

    猜你喜欢
    • 2014-05-28
    • 2021-03-01
    • 2012-08-16
    • 2011-03-02
    • 2020-10-04
    • 2012-12-10
    • 2021-05-14
    • 1970-01-01
    • 2016-06-17
    相关资源
    最近更新 更多