浏览器 Content-Disposition 与下载

最后更新: 2023-08-16 17:13:20 +0800 +0800
tags: Browser | Http | Security | Web
原文以英文撰写。您正在阅读AI翻译版本。

浏览器会根据多个输入决定显示响应、下载响应,还是将其交给 external application from several inputs. Content-Disposition provides a strong preference, but content type, navigation context, sandboxing, browser capabilities, and user settings also affect the result.

inline 与 attachment 处置方式 #

attachment 响应请求下载:

http
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="guide.pdf"
Content-Length: 110352
X-Content-Type-Options: nosniff

inline 响应允许在浏览器内呈现:

http
Content-Type: application/pdf
Content-Disposition: inline; filename="guide.pdf"

inline 不保证显示。 The browser needs a viewer for the media type, and the user can configure some types to download instead. Omitting the header leaves the choice primarily to the media type and navigation context.

提供安全文件名 #

filename 携带兼容 ASCII 的备用名称。 filename* uses the extended parameter encoding defined by RFC 8187, which supersedes RFC 5987, and can represent Unicode:

http
Content-Disposition: attachment;
 filename="report.pdf";
 filename*=UTF-8''r%C3%A9sum%C3%A9.pdf

应发送两个参数,因为旧客户端可能忽略 filename*;当两者都有效时,符合规范的接收方优先使用 filename*。 Treat a server-supplied filename as untrusted input:

  • Remove directory separators and control characters.
  • Reject . and .. as final names.
  • Keep the expected extension consistent with the media type.
  • Impose a reasonable length limit.
  • Never construct a server filesystem path directly from the value.

Browsers sanitize filenames independently, so exact renaming behavior differs between implementations.

Content-Type 与嗅探 #

Content-Type 描述表示形式。 A PDF should be application/pdf, an SVG should be image/svg+xml, and arbitrary binary data should be application/octet-stream.

http
X-Content-Type-Options: nosniff

nosniff makes script and style fetches reject incompatible media types and limits MIME-based reinterpretation in other protected fetch paths. It does not repair an incorrect Content-Type, make arbitrary content safe, or force a download. Serving active content under an incorrect benign type remains a security problem because navigation and embedding rules depend on both the declared type and the request context.

HTML 下载链接 #

download 属性表示链接的下载意图:

html
<a href="/exports/report.csv" download="report.csv">Download report</a>

For HTTP(S) URLs, browsers honor download only for same-origin resources. blob: and data: URLs are also eligible; CORS response headers do not make a cross-origin HTTP URL eligible. A response Content-Disposition filename can affect the suggested name, and attachment remains the reliable server-side mechanism for a cross-origin download. Authorization must remain on the download endpoint because hiding a URL behind a button does not protect it.

Blob URLs support generated client-side files:

js
const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
const url = URL.createObjectURL(blob);

const link = document.createElement("a");
link.href = url;
link.download = "report.csv";
document.body.append(link);
link.click();
link.remove();

setTimeout(() => URL.revokeObjectURL(url), 0);

Revoke object URLs after the browser has started the navigation because each URL retains its backing data. Run this sequence from a user-initiated event; programmatic clicks do not bypass browser download policy.

自动化与安全限制 #

Sandboxed frames need the allow-downloads sandbox token, and browsers can still block downloads without transient user activation or throttle repeated downloads. Cross-origin isolation, popup policy, mixed-content policy, and enterprise configuration can introduce additional restrictions.

在每个受支持的浏览器中测试完整导航流程:

  1. Verify status, Content-Type, and Content-Disposition.
  2. Confirm the suggested filename and downloaded bytes.
  3. Exercise authenticated, redirected, and error responses.
  4. Verify that HTML error pages are not saved under a trusted file extension.

Header inspection alone cannot prove the user-visible outcome because the browser performs the final policy decision.

评论

在 GitHub 上阅读或评论(发表评论需要登录)