构建网页收件箱时,有一件事很容易被忘掉:一封邮件并不是你自己创建的页面。它是别人提供的内容,而提供内容的人,可能正希望你的应用出点乱子。
这意味着,在应用里展示一封 HTML 邮件,应该和渲染任何用户提交的 HTML 一样保持警惕。一个看起来漂亮的预览,本身就可能是个安全问题。
邮件 HTML 可以包含图片、链接、内联样式和深层嵌套的标记。取决于处理方式,它也可能包含你从未打算在应用里放行的活动元素或 URL。即便邮件解析器工作得完美无缺,下一步——把解析出的 HTML 变成浏览器视图——也是一道独立的信任边界。
危险的捷径,是把任意邮件 HTML 当作可信内容,直接插入主应用的 DOM。
用分层代替单一过滤器
更安全的处理管线是这样的:
- 接收 MIME 内容
- 解析邮件各部分
- 清洗 HTML 并限制体积
- 存储被允许的内容
- 展示前再次清洗
- 在隔离的查看器中渲染
每一步解决的是不同的问题。解析把 MIME 信封变成可理解的部分;清洗移除危险的标记和属性;体积限制防止过大的内容压垮系统;隔离查看器则在有东西漏网时降低影响。这是纵深防御,并不保证每封邮件都安全。
属性和 URL 同样是输入
只剥掉标签并不能解决问题。事件处理属性、不受支持的嵌入元素、不安全的 URL 协议同样要紧。
远程图片也需要考虑。一封看似无害的邮件在打开时会加载远程资源,这个请求可能向发件人泄露信息,哪怕没有任何脚本运行。好的查看器应当对远程内容做出有意识的决定,而不是把每个图片 URL 都当成无害的。
纯文本版本同样不能省。开发者可能花一小时打磨 HTML 验证模板,却忘了它的纯文本替代版本。这对可访问性、兼容性和注重安全的读者都是失误。一封确认邮件仍应说明样式或图片被拦截时该怎么做;注册邮件则要检查纯文本正文里是否包含相关说明,以及可用的确认链接或验证码。
一个值得研究的实现是 10 Minute Temp Email,它提供只收不发的网页收件箱。其公开的实现说明描述了服务端清洗、浏览器端用 DOMPurify 再做一遍,以及在沙箱 iframe 中展示,同时还限制了可存储的附件类型。这些选择说明了一个原则:不能因为某一层是你自己的,就信任它的输出。
安全也不只关乎脚本。即便清洗得当的邮件,也可能包含有说服力的钓鱼信息、可疑的 PDF,或指向攻击者控制站点的链接。界面仍需清晰的发件人信息、可理解的链接行为,以及在适当位置给出诚实的警告。安全控制应当降低常见错误的概率,而不是鼓励人们不加思考地点下去。
从应用渲染邮件的那一刻起,你就已经创建了一个内容安全功能,无论你是否计划过。把邮件正文当作不可信数据处理,保留用户真正需要的安全内容,并把阅读器与应用其余部分隔离开来。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.