加密存储的图像

时间:2012-09-23 19:15:35

标签: php

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

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

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

提前致谢

3 个答案:

答案 0 :(得分:9)

这项行动并非无足轻重;您不仅需要对数据进行加密,还需要使其安全,防止在服务器上被盗或闯入;如果需要更改密钥,还需要考虑会发生什么。

要加密图片,您最好的选择可能是使用对称算法 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. 现在可以访问用户的所有图片
  5. 加密图片:   - 如果用户上传图像,则在上载时加密密钥在会话中可用。用它 :-)   - 如果图像是以其他方式上传的,那么"已加密/仍然需要加密" flag在数据库中设置,并且尽快(管理员登录/用户登录)执行所有挂起的加密操作。

    然后将图像存储为加密文件(" 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的加密密钥。那就是:

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

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

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

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

    忘记密码方案

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

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

    它现在生成一个随机密钥并在PasswordRecovery表中完成记录,其中UserKey使用该随机密钥加密。另一栏中有“Squeamish Ossifrage"用相同的随机密钥加密。他向用户123发送安全电子邮件,提供随机密钥。

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

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

答案 1 :(得分:4)

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

我必须这样做,因为我的申请涉及特殊类型的数据(家庭暴力),我国的法律要求加密存储。所以我理解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了解可能的警告。

答案 2 :(得分:0)

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