如何将 Base64 解码为 HTML
- 把 Base64 粘贴到 Base64 或 data URI。
data:text/html;base64,URI 同样可以。如果是保存为文本的大型邮件正文,请使用 打开 .txt 文件。 - 信息列表显示字符集和行数。下方的沙箱框架显示渲染后的页面,并附有提示:“沙箱预览:脚本、表单和外部资源均已拦截。源码见下方。”
- 预览下方的 文本 区域是源码。复制文本 会复制全部源码。
- 点击 下载文件 保存
decoded.html。
不会向任何地方发送任何内容。解码在你的浏览器中进行,除 Cloudflare 的浏览量统计外,页面不允许发出网络请求。
为什么预览要放在沙箱里
来源不明的 HTML 能做的远不止显示文字。邮件正文可能带有跟踪像素,报告邮件何时何地被打开;钓鱼页面可能包含把数据提交给攻击者的登录表单;任何页面都可以运行脚本。预览逐一拦截了这些行为:
| 威胁 | 防护措施 |
|---|---|
脚本,包括内联的 onclick 和 <script> | iframe 带有不授予任何权限的 sandbox 属性,脚本永远不会运行 |
| 提交密码的表单 | 沙箱不允许提交表单 |
| 弹出窗口和主页面跳转 | 沙箱不允许 |
| 读取本页面或其存储 | 沙箱中的内容拥有唯一的源,无法访问任何东西 |
| 跟踪像素、远程图片、字体和 CSS | 页面的内容安全策略会拦截所有发往其他服务器的请求 |
该策略还会拦截内联样式,所以预览显示的邮件文本、链接和结构比邮件客户端更简朴。以 data: URI 嵌入的图片是允许的,会正常显示。
大于 2 MB 的页面不会预览(“太大,无法在此预览,请查看下方源码或下载文件。”)。源码区域显示任意文档的前 256 KB;对于不超过 8 MB 的文档,复制文本 会复制完整源码。
识别 Base64 中的 HTML
| Base64 开头 | 解码后的开头 |
|---|---|
PCFET0NUWVBFIGh0bWw | <!DOCTYPE html |
PCFkb2N0eXBlIGh0bWw | <!doctype html |
PGh0bWw | <html |
77u/PCFET0NUWVBF | UTF-8 字节顺序标记,然后是 <!DOCTYPE |
CjwhRE9DVFlQRS | 一个换行,然后是 <!DOCTYPE |
PGRpdg、PHA+ | <div、<p>:HTML 片段,会被识别为 HTML |
字符集根据字节检测:字节顺序标记、UTF-16、有效的 UTF-8,最后回退到 Windows-1252。文档内的 <meta charset> 标签不会被参考,所以采用其他旧式编码的页面在预览中可能出现重音字符乱码,而下载的文件会保留原始字节。
Base64 HTML 从哪里来
电子邮件的 HTML 版本通常是一个带有 Content-Type: text/html 和 Content-Transfer-Encoding: base64 的 MIME 部分。只把该部分的编码行粘贴到这里即可,或者在 EML 解码器 中打开整封原始邮件,它会显示每个部分和附件。邮件中的 Base64 讲解了邮件结构。
一些接收或渲染邮件的服务会在 webhook 或 API 的 JSON 中以 Base64 字段提供 HTML 正文,模板和 PDF 渲染 API 有时也以同样的方式返回生成的 HTML。解码 JSON 中的 Base64 可以一次处理整个载荷。
钓鱼活动用 data:text/html URI 在链接或附件中携带完整的虚假登录页面。把 URI 粘贴到这里,可以在不运行它的情况下查看页面。要构造这样的 URI,请参阅 HTML 转 Base64。
在你自己的应用中预览不可信的 HTML
同样的做法适用于任何网页:先解码,再把结果放进一个 sandbox 属性为空的 iframe。仅靠沙箱无法阻止远程图片和样式表加载,所以要为框架预先加上一条内容安全策略:
function previewHtml(b64, container) {
const bytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
const html = new TextDecoder().decode(bytes);
const csp = `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src data:; style-src 'unsafe-inline'">`;
const frame = document.createElement("iframe");
frame.setAttribute("sandbox", "");
frame.srcdoc = csp + html;
container.append(frame);
}
在 Chrome 中,用这个函数加载一个包含脚本、远程样式表和远程图片的测试页面,没有运行任何脚本,也没有发出任何请求;去掉那行 <meta> 后,图片和样式表都被请求了。与本页的预览不同,它保留了内联样式。更多内容见 JavaScript 中的 Base64。
常见问题
怎么把 Base64 解码为 HTML?
把字符串粘贴到上方的输入框。HTML 源码显示在 文本 下方,沙箱预览位于其上方,下载文件 会将其保存为 .html 文件。
在这里预览钓鱼邮件中的 HTML 安全吗?
预览运行时关闭了所有沙箱权限,所以脚本不会运行,表单也无法提交;页面的内容安全策略还会阻止它从互联网加载任何内容,跟踪像素也不例外。在普通浏览器标签页中打开下载的文件则没有这些保护。
为什么预览没有样式?
样式和其他内容一起被拦截了:把远程内容挡在外面的安全策略同样会阻止内联的 <style> 块和 style 属性。预览会显示文本、链接和嵌入的 data: 图片,足以判断一封邮件说了什么。
我的 Base64 解码后是 HTML,工具却显示 XML 或文本,为什么?
工具通过开头的 <!doctype html、<html 或常见的 HTML 标签(如 <div>、<p>、<table>)识别 HTML。以自定义元素或纯文本开头的片段会显示为 XML 或文本。在 MIME 类型 中填入 text/html 即可得到 HTML 预览,下载前在 扩展名 中填入 html。