Avatar

Balakir

Fullstack Developer

Read Resume

Web 上线前的检查清单

  • 安全性:
  • 发送邮件
  • SEO
  • OGP

安全性

与认证相关的 Cookie 属性

设置了 HttpOnly 属性

减轻了 XSS 攻击

HttpOnly 表示只能通过 HTTP(S) 发送到服务器,而不能被 JavaScript 通过 document.cookie 的方式获取到。这样 XSS 就算获取了 JavaScript 能力,也无法获取到用户的这部分 cookie。

SameSite 属性设置为 Lax 或 Strict

主要为了防止 CSRF 攻击。在 Lax 的情况下,还需要同时检查是否有通过 GET 请求执行更新操作的端点

设置了 Secure 属性

仅通过 HTTPS 通信传输 Cookie

Domain 属性已适当设置

如果 Cookie 设置为也发送到子域名,则需要了解如果其他子域站点存在漏洞,可能会导致安全事件的风险。 例如:example.com 的 Cookie 也发送到了招聘站点的 jobs.example.com,而该服务器存在漏洞等 参考:Cookie 的 Domain 属性最安全的设置是不指定 *

将 Cookie 名的前缀设置为 __Host- 可以使不为空的 Domain 属性的 Cookie 被忽略(参考:Cookie Prefix 的绕过

用户输入值的验证

验证不仅在客户端进行,而且在服务器端也进行

对用户输入的 URL 进行适当验证

不要忘了限制协议。禁止指定例如 javascript: 这样的 URL

使用正则表达式时,检查是否存在绕过的可能(忽略文首检查或 Ruby 的多行标志的绕过等

接收到的 HTML 被直接输出的部分已排除了传递危险字符串的可能性

element.innerHtml = inputReactdangerouslySetInnerHtml 等部分

显示用户输入值时,事先进行逃逸或清理

不存在可能导致 SQL 注入的 SQL 语句

参考:构建安全的网站 – 1.1 SQL 注入

如果用户可以指定 URL 中包含的用户名等,那么进行了适当的验证

用户指定的用户名被设置到类似 https://example.com/◯◯ 的情况需要注意

拒绝与应用程序正在使用的路径可能重叠的字符串

拒绝以下划线开头的字符串(托管在某些云服务上时,可能已经保留。例如:Google App Engine 保留了 /_ah

拒绝仅由数字组成的字符串(根据路径的构成,框架可能会自动将对 /404 的请求处理为 404,这在某些情况下可能不是问题)

设置保留字符串列表,防止用户注册。例如 admin 或 contact 等(参考:reserved-usernames

响应头

指定了 Strict-Transport-Security 响应头

指示浏览器在指定时间内,对于指定的域名只能通过 HTTPS 而不是 HTTP 连接

{
  key: 'Strict-Transport-Security',
  value: 'max-age=31536000; includeSubDomains; preload'
}

每个页面的响应头中都提供了 X-Frame-Options: "DENY"X-Frame-Options: "SAMEORIGIN"(补充:建议设置 CSP 的 frame-ancestors

防止不期望的其他网站通过 iframe 等方式嵌入页面 = 防止点击劫持

指定了 X-Content-Type-Options: nosniff

参考:X-Content-Type-Options: nosniff 不仅仅是 IE 需要

其它安全性

在注销/更改电子邮件地址等需要特别防御的部分,要求必须重新登录

防范 XSS 或会话劫持造成的损害

确保用户可变响应内容没有被缓存到 CDN 或 KVS 中

确保对象存储的目录页面 URL 没有公开

防止通过图片 URL 追踪到其他图片 URL。根据服务要求,这可能没问题,但进行设置更安全

参考:Cloud Storage 中索引页面应设为非公开

对客户端传递的 URL 进行验证再重定向(防止开放重定向攻击)

例如:不应该让用户点击 https://example.com/login?redirect_to=https://evil.example 后重定向到 https://evil.example

在更新/删除操作中,未经认证的用户或无权限的用户不能更新数据

在 SQL 的 DELETE 或 UPDATE 语句中 WHERE 条件被正确设置

例如:本意是批量更新某个用户的 Product,结果却让所有 Product 都被更新。在我的项目中,除了特定查询以外,我通过 Extensions 设置禁用了 Prisma 的 updateMany/deleteMany。

用户提供的字符串没有直接包含在响应头中

响应头被篡改的风险

服务器发生的错误消息没有直接显示在浏览器上

在文件上传功能中对文件格式、大小、文件名等进行了验证

数据库的定期备份已启用

对象存储的备份已启用

使用的云服务账户已启用双因素认证

(根据服务的要求设置 CSP

登录

需要确认电子邮件地址已经过本人验证

即使是从 ID 提供商那里获得的电子邮件地址,也需验证其是否进行了本人确认

不能列举已注册的电子邮件地址

通过登录画面或密码重置画面的“该电子邮件地址未注册”等错误信息,第三方不应能查明电子邮件地址是否已被注册

例如,Firebase Authentication 在这方面有漏洞,但似乎在 2023 年得到了解决

如果提供多种登录方式,当相同用户注册账户时,应明确规定其规范,并反映在实现中

例:用户已通过电子邮件 + 密码认证注册账户,之后使用同一电子邮件的 Google 账户登录时的处理方式

允许更改电子邮件地址和关联账户

发送邮件

如果用户的输入值包含在邮件中,不应利用这些输入发送垃圾邮件

例:如果用户名或物品标题包含宣传或垃圾邮件内容,通过编辑这些内容便可发送垃圾邮件等

用户执行特定操作时,应避免向大量用户重复发送邮件

例:如果使用了关注功能关注了一万人,则会向一万人发送通知邮件等

已完成 SPF / DKIM / DMARC 的设置

如果通过批处理发送邮件,即使连续调用处理程序,也应避免邮件重复发送

例如,在 AWS 或 Google Cloud 等服务中,可能会存在「At least once delivery」的情况

对于新闻通讯或营销邮件,应能在未登录的情况下取消订阅

向大量用户发送营销邮件时,应支持 List-Unsubscribe=One-Click

检查 Gmail 的邮件发送者指南 是个不错的选择

SEO

所有页面都应正确指定 title 标签

对 SEO 至关重要的页面应设定 canonical URL

例:确保搜索引擎能识别 https://example.com/products/foohttps://example.com/products/foo?query=bar 是相同的内容

错误相关页面的状态码应为 40x 或 50x,或设置为 noindex

搜索结果页面应设置 noindex 或 canonical URL

或者,在 <title> 标签和 <h1> 标签的内容中明确包含“搜索结果:◯◯”。否则,可能会有奇怪的关键字被索引进搜索结果

例如:如果 https://example.com/search?keyword=UNKO 的页面标题是“UNKO”,那么“UNKO”可能会被索引进搜索结果

确保整个站点未被设置为 noindex

“等到发布时再移除”很容易被忘记

确保高搜索流量页面(如首页)设置了 meta description

个人认为对于用户生成的页面等无需强制设置,宁愿不设置也不要设置奇怪的 meta description。

OGP

经常被分享的页面已完成 OGP 的设置

想要设置的几个关键点:

添加支付功能时

已确认如何处理结算流程的负责人

支付失败时,应用内的数据与 Stripe 等支付服务商的数据不会产生不一致

万一发生这种情况,是否能够被检测到

例如:在 Stripe 上支付成功,但数据库更新失败等

实现了避免重复支付的措施

即使之前进行过支付的用户注销了账户,也不会对财务或应用逻辑产生不一致

订阅中的用户退订(或账号被冻结)时,能够自动取消订阅

用户退订时是否退款或按日计费的规定写在了使用条款中

在退订页面上写明这些细节也是个好主意

准备了取消订阅的引导流程

如果因信用卡过期等原因导致订阅更新失败,能够处理这种情况,并且用户可以轻松找到更新支付信息的途径

收据满足合格发票要求(发票制度)

如是合格发票发行者。使用 Stripe 的话,在日本设置发票/发票的最佳实践会有所帮助

可访问性

图像(<img>)的 alt 属性被适当地指定

alt 的指定方式可以参考 信息无障碍门户网站

仅含 svg 图标的 <button><a> 能够被屏幕阅读器正确识别其作用

<a href="/" aria-label="显示链接作用的文本">
  <svg aria-hidden="true" ... ></svg>
</a>

这两点很容易被忽略,因此加入了检查清单。关于其他项目,freee 可访问性指南会有帮助。

性能

确保打包的 JS 中不含有无用模块

发布前用 bundle-analyzer 等工具检查是个好方法

静态文件被缓存到 CDN 上

使用 Next.js 或 Nuxt.js 等框架时,会有大量的 js/css 文件请求,这些静态文件最好通过 CDN 分发

避免因图片造成的布局偏移

在 img 元素上指定 CSS 的 aspect-ratio 或 width/height 属性

没有加载过大的图片

示例:宽度为 400px 的图片实际大小却是 2MB。这种情况很常见

确保适当地添加了 SQL 的索引

在发布后数据增加时进行对策似乎也不错

在多个环境中确认操作

在手机或平板尺寸的屏幕上显示时 UI 没有崩溃

这个问题非常常见

在不同的操作系统上查看时字体没有出现问题

确保 font-family 在 Mac、Windows、iOS、Android、(Linux) 等操作系统上的设置不会显得不自然

(如果开发环境是 Mac)在系统环境设置中把「始终显示滚动条」选项打开也不会出现问题

在设置为始终显示滚动条的情况下,打开模态框等时可能会出现抖动。可能需要采用 scrollbar-gutter 进行相应的处理

用户指定的昵称等输入值过长时界面不会崩溃

其他

本地存储或非 http-only 的 Cookie 等在 7 天后消失也没问题

虽然不太为人所知,但最近的 iOS Safari 中由于 ITP 的规范,如果用户 7 天以上没有操作,通过浏览器上的 JavaScript 保存的 Cookie 或本地存储的内容将自动删除(参考

不依赖第三方 Cookie

参考:准备废除第三方 Cookie

如果是日文网站,确保为 <html lang="ja">

需要注意的是,一些框架的默认设置可能是 lang="en"

当发生服务器错误时,错误内容被通知或可以被检测到

404 页或 50x 系列页面的表现不错

在 404 的情况下,应该显示指向首页等的链接,引导进行下一步操作

设置了网站图标(Favicon)

设置了 apple-touch-icon

安装了 Google Analytics 等访问分析工具(如果需要)

如果提供封闭聊天等服务,已向电信业务申请(参考

服务名称在其他语言中没有不恰当的含义

可以询问 ChatGPT,或使用 WordSense 等工具进行检查

2024 — Built by  Balakir