3

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

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

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

提前致谢

4

3 回答 3

10

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

要加密图像,您最好的选择可能是使用对称算法的mcrypt 。有几个关于如何做到这一点的教程。请参阅使用 PHP 加密 AES-256 文件的最佳方法是什么?.

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

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

所以工作流程是:

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

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

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

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

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

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

这很尴尬,但不幸的是,所有其他解决方案都依赖于在本地以明文形式提供的密码,其中安全妥协将使系统完全开放。

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

多用户/密码场景

您在一个表中有资源 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对其进行解密(但不能使用其他资源,因为它们具有不同的随机 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 的密钥加密,该密钥没有更改,仍然是管理员在创建帐户时随机生成的。

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

于 2012-09-23T20:45:15.193 回答
4

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

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

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

加密的命令是:

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 编码或类似的操作,您提供给它们的内容它们会返回给您。

如果您迁移服务器,请参阅windows 上的 openssl aes-256 加密文件无法在 linux 上解密,以了解可能的警告。

于 2012-09-23T20:07:11.663 回答
0

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

于 2012-09-23T21:15:28.760 回答