这个操作并不简单;您不仅需要加密数据,还需要防止服务器被盗或闯入;如果需要更改密钥,您还需要考虑会发生什么。
要加密图像,最好的选择可能是 mcrypt 和 对称 算法。有几个关于如何做到这一点的教程。见What is the best way to encrypt files in AES-256 with PHP?。
您需要做的是提供图像并即时解密,而不是将其存储在明文中。
现在的问题是在哪里保存密码。最好的整体解决方案是为每个用户提供一个秘密加密密钥,在用户登记时随机生成;并且密钥本身使用用户密码非对称加密。您可以使用 phpseclib 在 RSA 中执行此操作。相同的加密密钥也以管理密码不对称存储。
所以工作流程是:
- 用户登录(并提供密码)
- 系统将密码哈希与存储的哈希进行比较并授予访问权限(您将使用诸如 bcrypt 之类的东西:参见 Is there a bruteforce-proof hashing algorithm?)
- 系统还会解码加密字符串并将其存储在临时会话中(会话持久性可能是一个需要解决的问题!)
- 他现在可以访问该用户的所有图像
要加密图像:
- 如果用户上传图像,则在上传时,会话中的加密密钥可用。用它 :-)
- 如果图像以其他方式上传,则在数据库中设置“已加密/仍待加密”标志,并尽快(管理员登录/用户登录)执行所有待处理的加密操作。
然后将图像存储为加密文件(“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 的密钥进行加密,该密钥没有更改,仍然是管理员在创建帐户时随机生成的。
下一次登录,用户提供密码并解锁系统。