首页 > 解决方案 > 如果发件人可以撒谎,为什么还要检查上传文件的内容类型呢?

问题描述

我正在编写一个隐藏在 Azure API 管理工具后面的 API。除非 APIM 验证请求者的访问令牌以及 Azure 订阅,否则无法访问它。在 API 中,我们想与请求者确认我们只接受 zip 文件。

if (request.PayloadFile.ContentType != "application/zip")
{
    throw new BadRequestException("Unable to accept payload content type");
}

不是试图减轻不良行为者的过程。目的是简单地验证开发人员正在发送预期的数据类型。话虽如此,我制作了一个发送非 zip 格式文件的小型客户端,我只是在请求中设置了 content-type 标头:

var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(filePath));
fileContent.Headers.Remove("Content-Type");
fileContent.Headers.Add("Content-Type", "application/zip");
fileAsFormData.Add(fileContent, "payLoad", fileName: Path.GetFileName(filePath));

API 很乐意接受这一点。所以我的问题是双重的:

  1. 为什么我们还要费心检查ContentType它是否可以被欺骗?
  2. 有没有办法获得有效载荷的真实文件类型?

标签: c#apirest.net-5file-type

解决方案


Content-Type 是客户端向服务器指示您希望发送的内容的一种方式。当然,您可能会对此恶意“撒谎”,但这会违背您作为客户的利益。服务器可能会实施适当的逻辑来解析文件内容,具体取决于 Content-Type 标头。

有几件事情需要考虑:

  1. 仅当客户端发送有效数据时,服务器才能正常工作:即:希望服务器正常运行的客户端不应谎报上传文件的真实 Content-Type。
  2. 与使用其他方法指定文件类型相比,服务器检查 Content-Type 标头更容易。
  3. 服务器还应该验证数据并降低可能滥用 API 的风险。例如,在您的情况下,您应该在解压缩内容周围添加 try-catch,如果解压缩不成功,则以错误响应。

对于您的另一个问题,是否可以检查真正的 Content-Types,答案通常是:不能。有一些文件类型,其中文件本身包含某种“魔术字符串”,可用作该 Content-Type 的签名。

您可以检查其中一些常见的文件签名:https ://en.wikipedia.org/wiki/List_of_file_signatures

请注意,恶意用户也可能能够修改文件签名。可以有额外的安全措施来防御欺骗文件内容,例如:校验和,但没有 100% 的安全性,除非在服务器和受信任的客户端之间共享一些私有秘密,这些秘密可用于安全地签署内容。

这里真正的问题是:为什么有人会恶意欺骗 Content-Types?还是文件内容?需要什么级别的安全措施来避免相关风险?


推荐阅读