如果发件人可以撒谎,为什么还要检查上传文件的 content-type?

Why bother inspecting an uploaded file's content-type if the sender can lie about what it is?

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

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

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

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. 有没有办法获取负载的真实文件类型?

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

有几点需要考虑:

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

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

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

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

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