在Web服务器上存储私有映像的最佳实践

时间:2016-10-22 09:06:36

标签: php image security hash server

例如,如果您有一个在线社区,允许在成员之间发送私人图像,如数字笔友或约会网站。

在网络服务器上保护这些图像的最佳做法是什么,以及向经过身份验证的用户显示这些图像的最佳做法?

这是我到目前为止所做的:

  1. 将图片存储在公共根目录之外。
  2. 通过一次性代码而非实际图像位置检索图像。
  3. 随机化的散列图像名称和文件夹名称,不容易猜到。
  4. 用于在显示图像之前对用户进行身份验证的PHP脚本。
  5. 在root之外似乎是存储图像以使其难以访问的最佳方式之一,但是如果服务器本身被直接入侵呢?

    有没有办法对图像文件进行散列和加盐,这样只有当哈希和盐匹配时才能显示它,即使黑客有文件? 这可以通过PHP或SQL返回吗? 我正在考虑将图像编码为base64,并使用从每个用户随机生成的密码生成的盐盐碱化base64(这可能吗?) 或者有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

对于基本保护,你所描述的东西可能就足够了,甚至可能太多了,如果文件夹在www root之外,随机化文件夹名称不会增加安全性,但会增加复杂性。

根据您应针对您的方案进行的风险评估,您可以选择执行更多操作。当然,如果您发现可以以10000美元的成本降低100美元违规的风险,您可能不希望这样做。所以先做数学。 :)

我可以看到您的解决方案面临两个主要威胁,一个是访问控制逻辑中的一个错误,它允许用户下载他本不应该访问的图像。另一种是攻击者可以访问您的Web服务器并下载图像(因为您的Web服务器需要访问图像文件,这不一定是root / admin访问权限,这会增加风险)。

人们可以想到的一个想法是加密服务器上的图像。但是,通过加密,密钥管理通常是问题,现在就是这种情况。使用您的应用程序无论如何都可以访问的密钥加密没有多大意义,因为攻击者也可以在应用程序级攻击成功的情况下访问该密钥(并且在服务器/操作系统级别攻击的情况下也是如此,因为用户正在运行您的Web服务器和/或应用程序必须能够访问密钥。

理论上,您可以为所有用户生成公钥/私钥对。当有人上传图像时,您将为图像生成对称密钥,使用该密钥加密图像,然后使用每个预期收件人的公钥加密对称密钥,并将加密密钥(和元数据)与图像一起存储。用户的私钥也应该加密,最好使用从用户密码派生的密钥,并使用适当的密钥派生函数,如PBKDF2。一个含义是,您只能在用户登录时获取用户的私钥,因为您没有存储他的密码,所以这是您唯一的时间。这意味着您必须至少将用户的解密私钥存储在服务器内存中,而不是真正安全(并且任何其他存储更糟糕)。这仍然可以提供针对脱机攻击者的保护(例如,某些人可以访问备份),并且还会限制攻击范围给受害者用户在服务器受到攻击时登录(意味着在受到攻击之后,但在您意识到这一点之前) 。另一个缺点是这个解决方案的复杂性 - 加密很难,没有经验就很容易搞砸了。这还可以缓解访问控制漏洞带来的威胁,因为无法使用登录用户的私钥解密意外图像。

完全不同的方法是将您的应用程序分成几个组件:登录服务(类似于SSO),Web服务器和后端映像服务。当您的用户登录到身份验证提供程序(AP)时,在这种情况下,他将收到带有由AP签名的声明的令牌。在与Web应用程序通信时,他将使用此令牌进行身份验证。该解决方案与以前的解决方案的不同之处在于,当用户请求图像时,Web应用程序会将其令牌传递给图像服务,并且图像服务一方面可以将图像安全地存储在不能直接从因特网访问的盒子上,并且另一方面,它可以授权接收到的令牌是否要返回图像(它可以通过AP或自身验证令牌,具体取决于您选择的实现)。在这种情况下,即使攻击者破坏了Web应用程序,他仍然无法从AP生成(签名)有效令牌以访问映像服务上的映像,并且可能更难以妥协图像服务。当然,如果Web服务器出现漏洞,攻击者仍然可以观察到任何流经的图像,这意味着在服务器遭到入侵时登录的任何用户仍然会将图像丢失给攻击者。这个解决方案增加的复杂性甚至比前一个更糟糕,这意味着它也很容易出错,而且开发和维护也很昂贵。

请注意,这些解决方案都不能保护服务器管理员的图像,这可能是也可能不是您应用的要求。

我希望这个答案能够说明使其比目前的解决方案更加安全所带来的困难。说了这么多,实现是关键,细节(实际的代码级别漏洞)可能最重要。

答案 1 :(得分:0)

您已将这些列为某些安全协议:

"1. Store Images outside of public root.

2. Retrieve images via one time code instead of the actual image location.

...

4. PHP script to authenticate user before displaying the image."

这应该够了,但是你提到了......

"3.  Randomised hashed image names and folder names that are not easy to guess."

如果你实际上正确地做了前两个,1和2,那么3实际上不可能有任何效果。如果图像在webserver目录之外,那么文件夹名称和图像名称是否易于猜测并不重要。

您的代码看起来像(做1和2),假设环境是您的网络服务器的根目录(即example.com/index.php)......

$file_location = '../../images/' . $some_id_that_is_authenticated_and_cleansed_for_slashes . '.jpg';

readfile($file_location);  // grabs file and shows it to user

如果您正在执行上述操作,则3是多余的。如果您的网站被黑客攻击(Apache安全性被绕过),那么散列名称等将无济于事,如果您的网站没有执行上述操作,它将无济于事(因为用户可以直接访问URL)。除了这种冗余,其余的似乎都很完美。