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

4
例如,如果您拥有一个允许会员之间发送私人图片的在线社区,例如数字笔友或约会网站,那么如何在Web服务器上保护这些图像以及向经过身份验证的用户显示它们的最佳做法是什么?
以下是我迄今为止所做的:
1.将图像存储在公共根目录之外。 2.通过一次性代码检索图像,而不是实际的图像位置。 3.随机散列图像名称和文件夹名称,使其不易猜测。 4.PHP脚本在显示图像之前对用户进行身份验证。
存储图像在根目录之外似乎是存储图像的最佳方法之一,以使它们难以访问,但是如果服务器直接被黑客攻击怎么办?
是否有一种方法可以对图像文件进行哈希和加盐,以便只有在哈希和加盐匹配时才能显示它们,即使黑客拥有该文件也不行?是否可能通过PHP或SQL返回此内容? 我正在考虑将图像编码为base64,并使用从每个用户生成的随机密码生成的盐来加密base64(是否可能?) 还是有更好的方法吗?

2
您可以使用二进制数据类型将它们存储在MySQL中,然后使用 image.php?id=123 这样的东西,在其中应用一些逻辑,如检查请求图像的用户以及他们是否拥有所需的访问权限。 - Craig van Tonder
嗨,我想说数据库也会被攻击……所以我会把它从数据库中移除。至于更安全的方法,我认为你可以使用pgp密钥,这样只有发送者和接收者才能解码文件[示例](https://dev59.com/vHRB5IYBdhLWcg3wiHll#597200)。然而,问题在于你要把密钥存放在哪里?(注意,你也可以用密码保护密钥) - urban
我在思考,也许可以生成一个密钥,只有在发送方和接收方的身份验证匹配时才能生成,而且它只能使用一次,然后在渲染图像后更改。实际上,我并没有将其构建到网站中,我只是试图了解其他人可能如何处理这个问题,例如将医疗记录或其他高度机密的文件存储在可以被外部查看的Web服务器上。 - Ash
@Craig van Tonder: 你可以在MySQL中存储许多东西。但是,由于它是关系型数据库,建议数据是关系型的。图像的原始二进制字节不是。 - HoldOffHunger
@urban 如果你要被黑客攻击,那么无论如何你都会被攻击,所以我的建议与网络安全无关 ;) - Craig van Tonder
@HoldOffHunger 这是真的...也许有更好的数据库引擎适用于这种情况,但仍值得考虑。 - Craig van Tonder
2个回答

5
为基本保护,您所描述的措施可能足够了,甚至过多。如果文件夹在www根目录之外,随机化文件夹名称不会为安全性增加太多,但会增加复杂性。
基于您的情况应进行风险评估,可以选择更多措施。当然,如果您发现用10000美元的成本可以降低100美元的违规风险,您可能不想这样做。因此,请先算好成本。
我能看到你的解决方案存在两个主要威胁。一种是访问控制逻辑中的漏洞,允许用户下载他本不应该访问的图片。另一种是攻击者获得访问您的Web服务器并下载图片(因为您的Web服务器需要访问图像文件,这不一定需要root/admin访问权限,从而增加了风险)。
一个想法是在服务器上加密图像。但是,通常密钥管理是加密的问题,现在正是如此。使用应用程序可以访问的密钥进行加密没有什么意义,因为在成功的应用程序级攻击(以及在服务器/操作系统级别攻击的情况下),攻击者也可以访问该密钥,因为运行Web服务器和/或应用程序的用户必须访问该密钥。
从理论上讲,您可以为所有用户生成公共/私有密钥对。当有人上传图像时,您将为该图像生成对称密钥,使用该密钥加密图像,然后使用每个意图接收者的公钥加密对称密钥,并将加密的密钥(和元数据)与图像一起存储。最好使用来自用户密码的密钥派生函数(例如PBKDF2)加密用户的私钥。一个影响是,只有当用户登录时才能获取他的私钥,因为您不会存储他的密码,所以那是您拥有它的唯一时机。这意味着您至少要在服务器内存中存储用户解密的私钥,但这并不安全(任何其他存储方式都更糟)。尽管如此,这仍然可以提供对离线攻击者的保护,它还将限制攻击范围,仅限于在服务器受到攻击但在您意识到之前登录的受害用户。另一个缺点是该解决方案的复杂性--加密很难,没有经验很容易出错。这也将缓解访问控制漏洞带来的威胁,因为非预期的图像无法使用已登录用户的私钥解密。
一种完全不同的方法是将您的应用程序分成几个组件:一个类似于SSO的登陆服务、您的Web服务器和后端图像服务。当您的用户登录身份验证提供者(AP)时,他在这种情况下会收到由AP签名的带有声明的令牌。在与Web应用程序交互时,他将使用此令牌进行身份验证。这种解决方案与以前的区别在于,当用户请求图像时,Web应用程序将向图像服务传递他的令牌,而图像服务则可以在一方面将图像安全地存储在不直接可从Internet访问的盒子上,并且在另一方面,它可以授权是否要返回图像(它可以根据您选择的实现方式使用AP或自己验证令牌)。在这种情况下,即使攻击者破坏了Web应用程序,他仍无法生成(签署)来自AP的有效令牌,以获取对图像服务上图像的访问权,并且可能更难破坏图像服务。当然,在Web服务器遭到攻击的情况下,攻击者仍然能够观察到流经的任何图像,这意味着在服务器受到攻击时登录的任何用户仍将把他的图像输送给攻击者。这种解决方案的增加复杂性甚至比以前的还要糟糕,这意味着很容易做错,并且开发和维护成本也很高。

请注意,这些解决方案都无法保护图像免受服务器管理员的攻击,这可能是您的应用程序是否需要的要求。

我希望这个答案能够阐明实现显著更安全的难点。尽管如此,实现仍然是关键,详细信息(实际代码级漏洞)可能是最重要的。


非常有趣! - Hammerbot

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不可能产生任何影响。如果图像位于Web服务器目录之外,则无论文件夹名称和图像名称是否易于猜测都没有关系。

您的代码将如下所示(用于执行1和2),假设环境是您的Web服务器根目录(即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),也无法起到帮助作用。除了这种冗余之外,其余部分似乎都很完美。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接