网站审核
如何检查网站的表单:标签、输入类型、HTTPS 与 CSRF
表单是访客把数据交给你的地方。本文介绍每个表单该检查什么、常见问题如何修复,以及 Rudra 为何在检查表单时从不提交它们。
本页内容
联系表单、注册、登录、结账和搜索框,都是你的网站请访客采取行动的地方。一个让人看不懂、在手机上难以填写或不安全的表单,会让你流失潜在客户和信任;而表单的问题往往要等到有人投诉才会暴露,因为中途放弃的人不会告诉你。
大多数表单问题在 HTML 中就能看出来,所以不用填写任何内容就可以检查。下面是需要关注的地方。
易用性与无障碍
每个字段都需要标签
每个输入框都需要一个通过 for 和 id 与之关联(或直接把它包裹起来)的 <label>。屏幕阅读器会朗读标签,点击标签也会让对应字段获得焦点。placeholder 不是标签:用户一开始输入它就消失了,对比度往往偏低,而且不一定会被可靠地朗读出来。如果设计上实在无法显示可见的标签,aria-label 可以作为后备,但可见的标签对所有人都有帮助。我们的无障碍指南对标签有更深入的介绍。
使用正确的输入类型
type="email"、type="tel" 和 type="url" 能在手机上调出合适的键盘,并提供基本的浏览器校验。电话字段如果用的是 type="text",移动端访客就得费劲地去找数字键。使用 type="number" 时要小心:它是为数量设计的,不适用于电话号码、银行卡号或邮政编码。
添加 autocomplete 提示
autocomplete 属性告诉浏览器和密码管理器每个字段是什么:name、email、tel、street-address、postal-code、cc-number、current-password、new-password、one-time-code。它让访客轻点一下就能填好表单,而且对于收集用户个人信息的字段,这是 WCAG 2.1 的一项要求(成功准则 1.3.5)。不要给密码字段加 autocomplete="off":这会把人们推向更弱的、重复使用的密码。
真正的提交按钮和有帮助的校验
使用 <button type="submit">,这样表单既能用回车键提交,也不依赖自定义 JavaScript。用 required 属性标记必填字段,并在标签中注明;错误提示要用通俗的文字显示在字段旁边。加上 novalidate 会关闭浏览器内置的检查,只有在你用自己的校验取而代之时才可以这么做。
安全
- 页面和提交地址都要用 HTTPS。HTTP 页面上的密码字段,或者
action指向http://网址的表单,都会以明文发送用户输入的内容。页面和提交地址必须都是 HTTPS。 - 密码绝不用 GET。使用
method="get"时,表单的值会进入网址,进而出现在浏览器历史记录、服务器日志和 Referer 请求头中。任何敏感内容都要使用method="post"。 - CSRF 防护。会改变状态的表单(登录、修改账户、下单)应当防范跨站请求伪造,通常的做法是在隐藏字段中放一个由服务器校验的秘密令牌,再配合
SameSiteCookie。参阅如何检查 Cookie 安全性。 - 弄清数据去了哪里。表单提交到另一个域名(比如邮件列表或 CRM 服务商)可能在意料之中,但要确保这是有意为之,并且已写入你的隐私政策。
- 在服务器端校验。浏览器校验只是给诚实访客提供的便利,任何人都能绕过。服务器必须把每个值重新检查一遍。
无需提交即可检查你的表单
Rudra 的免费死链检测工具会读取页面上的每个表单,标出不安全的提交地址、用 GET 发送的密码、缺失的标签等问题;它从不提交、点击或填写任何内容。
Rudra 如何检查表单,而又不提交它们
免费死链检测工具和网站审核会在真实浏览器中加载你的页面,并检查页面上最多 10 个表单。它们会标出以下问题,并注明涉及的表单和字段名称:
- HTTP 页面上的密码字段、提交到
http://的表单,以及使用 GET 的密码表单(每项扣 10 分); - 只用 placeholder 充当标签的字段(扣 3 分);
- 没有无障碍标签的字段、与字段不匹配的输入类型(如使用
type="text"的邮箱字段)、缺少 autocomplete 提示、密码字段上的autocomplete="off"、提交到另一个主机的表单、没有提交按钮的表单、没有约束条件的必填邮箱或电话字段,以及novalidate,这些都只作为提示信息; - 没有可见的 CSRF 类令牌的 POST 表单,以低置信度标出,因为令牌可能由 JavaScript 添加,服务器也可能用其他方式保护表单。
它还会向浏览器询问一次:对于标记为必填的字段,浏览器是否会阻止空表单提交。做法是读取每个字段的校验状态,既不让字段获得焦点,也不填写任何内容,更不会触发网站自身的校验处理程序。
为什么我们从不提交表单
提交表单会产生实实在在的后果:某人的收件箱里多了一封邮件,一个账户被创建,一笔订单或一张支持工单出现了,速率限制或反欺诈过滤被触发。自动化工具无从知道哪些表单可以放心提交,所以我们的工具一个都不提交。表单绝不会被提交、点击、聚焦或填写,报告中也只包含字段名称和标签,绝不包含值。
这样做的代价是,有些事情只有真正提交表单才能测试,这部分就要靠你自己了:提交的内容是否送达,确认信息和错误提示是什么样的,服务器是否会拒绝非法输入或跨站输入,以及垃圾信息防护是否有效。
为每个表单做一次手动测试
- 在手机上填写一遍,检查每个字段是否调出了合适的键盘、自动填充是否合理。
- 只用键盘完成填写,然后再用 NVDA 或 VoiceOver 等屏幕阅读器操作一遍。
- 分别在留空和填入错误邮箱地址的情况下提交,并阅读错误提示。
- 正常提交一次,确认信息送到了该送达的地方。
- 对于登录和账户表单,请开发人员确认 CSRF 防护和服务器端校验已经到位。
常见问题
我的表单明明有防护,为什么 Rudra 还提示缺少 CSRF 令牌?
这项检查只能看到以隐藏字段形式出现在 HTML 中的令牌。你的框架可能是用 JavaScript 添加令牌的,或者是通过 SameSite Cookie 或自定义请求头来保护表单。所以这项发现的置信度为低,并建议人工复核。
用 placeholder 文字当标签够吗?
不够。placeholder 在用户开始输入时就会消失,对比度往往偏低,屏幕阅读器也不一定能可靠地朗读出来。请使用可见的 label 元素。
应该关闭表单的 autocomplete 吗?
一般不应该。autocomplete 能帮人们又快又准地填写表单,而且按照 WCAG 2.1,个人信息字段必须提供它。在密码字段上关闭它,会让密码管理器不那么好用。
Rudra 能测试我的联系表单是否会发出邮件吗?
不能。表单从不会被提交,所以邮件送达、确认信息和服务器端校验都得由你亲自提交表单来测试。