输入验证策略¶
输入验证速查表¶
简介¶
本文旨在为您的应用程序提供清晰、简单、可操作的输入验证安全功能指导。
输入验证的目标¶
执行输入验证是为了确保只有格式正确的数据才能进入信息系统的工作流,防止格式错误的数据在数据库中持久化并触发各种下游组件的故障。输入验证应尽可能早在数据流中进行,最好是在从外部方接收到数据后立即进行。
来自所有潜在不可信来源的数据都应进行输入验证,这不仅包括面向互联网的Web客户端,还包括通过外部网络(如来自供应商、合作伙伴、厂商或监管机构)的后端馈送,它们各自都可能被攻破并开始发送格式错误的数据。
输入验证不应作为防止跨站脚本 (XSS)、SQL注入以及其他在相关速查表中涵盖的攻击的主要方法,但如果实施得当,它能显著有助于减少这些攻击的影响。
输入验证策略¶
输入验证应在句法和语义层面同时应用
句法验证应强制执行结构化字段(例如,社会安全号、日期、货币符号)的正确语法。
语义验证应强制执行其值在特定业务上下文中的正确性(例如,开始日期在结束日期之前,价格在预期范围内)。
始终建议在处理用户(攻击者)请求时尽早阻止攻击。输入验证可用于在应用程序处理未经授权的输入之前检测到它们。
实施输入验证¶
输入验证可以使用任何允许有效强制执行句法和语义正确性的编程技术来实现,例如:
Web应用框架中原生提供的数据类型验证器(如Django验证器、Apache Commons验证器等)。
针对这些格式的输入,根据JSON Schema和XML Schema (XSD)进行验证。
具有严格异常处理的类型转换(例如 Java 中的 Integer.parseInt(),Python 中的 int())
数值参数和日期的最小和最大值范围检查,字符串的最小和最大长度检查。
小范围字符串参数(例如,星期几)的允许值数组。
用于任何其他结构化数据的正则表达式,覆盖整个输入字符串 (^...$),并且不使用“任意字符”通配符(例如 . 或 \S)
拒绝列表(即拒绝已知危险模式)可以用作额外的防御层,但它应补充而非替代允许列表,以帮助捕获一些常见的攻击或模式,而不应将其作为主要的验证方法。
允许列表与拒绝列表¶
使用拒绝列表验证来试图检测可能危险的字符和模式,如撇号 ' 字符、字符串 1=1 或 "@example.org
[email protected]
user@[IPv6:2001:db8::1]
" "@example.org
使用正则表达式正确解析电子邮件地址以验证其有效性非常复杂,尽管有一些公开可用的正则表达式文档。
最大的注意事项是,尽管RFC定义了一种非常灵活的电子邮件地址格式,但大多数实际实现(例如邮件服务器)都使用更受限制的地址格式,这意味着它们会拒绝技术上有效的地址。虽然这些地址可能在技术上是正确的,但如果您的应用程序无法实际向它们发送电子邮件,那么这些地址就没有多大用处。
因此,验证电子邮件地址的最佳方法是执行一些基本的初始验证,然后将地址传递给邮件服务器,如果邮件服务器拒绝则捕获异常。这意味着应用程序可以确信其邮件服务器可以向其接受的任何地址发送电子邮件。初始验证可以像这样简单:
电子邮件地址包含两部分,由 @ 符号分隔。
电子邮件地址不包含危险字符(例如反引号、单引号或双引号,或空字节)。
哪些字符是危险的将取决于地址的使用方式(在页面中回显、插入数据库等)。
域部分只包含字母、数字、连字符 (-) 和点 (.)。
电子邮件地址长度合理
本地部分(@ 前面)不应超过63个字符。
总长度不应超过254个字符。
语义验证¶
语义验证是关于确定电子邮件地址是否正确和合法的。最常见的方法是向用户发送一封电子邮件,并要求他们点击电子邮件中的链接,或者输入发送给他们的代码。这提供了一个基本的保证,即:
电子邮件地址是正确的。
应用程序可以成功地向其发送电子邮件。
用户可以访问该邮箱。
发送给用户以证明所有权的链接应包含一个令牌,该令牌应:
至少32个字符长。
使用安全的随机数源生成。
一次性使用。
有时限(例如,八小时后过期)。
验证电子邮件地址的所有权后,用户应通过常规机制在应用程序上进行身份验证。
一次性电子邮件地址¶
在某些情况下,用户在应用程序上注册时可能不想提供真实的电子邮件地址,而是提供一次性电子邮件地址。这些是公开可用的地址,不需要用户进行身份验证,通常用于减少用户主要电子邮件地址收到的垃圾邮件数量。
阻止一次性电子邮件地址几乎是不可能的,因为有大量的网站提供这些服务,并且每天都有新的域名创建。有一些公开可用的列表和已知的商业一次性域名列表,但这些总是会不完整。
如果使用这些列表来阻止一次性电子邮件地址的使用,则应向用户显示一条消息,解释他们为何被阻止(尽管他们很可能只会寻找另一个一次性提供商,而不是提供其合法地址)。
如果必须阻止一次性电子邮件地址,则应只允许来自特定允许的电子邮件提供商的注册。然而,如果这包括Google或Yahoo等公共提供商,用户可以简单地向它们注册自己的一次性地址。
子地址¶
子地址允许用户在电子邮件地址的本地部分(@ 符号之前)指定一个标签,该标签将被邮件服务器忽略。例如,如果 example.org 域支持子地址,则以下电子邮件地址是等效的:
[email protected]
[email protected]
[email protected]
许多邮件提供商(如Microsoft Exchange)不支持子地址。最著名的支持者是Gmail,尽管还有许多其他提供商也支持。
有些用户会为他们注册的每个网站使用不同的标签,这样如果他们开始收到发送到某个子地址的垃圾邮件,他们就可以识别是哪个网站泄露或出售了他们的电子邮件地址。
由于它可能允许用户使用单个电子邮件地址注册多个账户,一些网站可能希望通过删除 + 和 @ 符号之间的一切内容来阻止子地址。这通常不被推荐,因为它暗示网站所有者要么不知道子地址,要么希望阻止用户在其泄露或出售电子邮件地址时识别他们。此外,通过使用一次性电子邮件地址,或简单地向受信任的提供商注册多个电子邮件账户,可以轻易绕过此限制。
参考资料¶
OWASP 2024十大主动控制:C3:验证所有输入并处理异常
CWE-20 不当的输入验证
OWASP 2021十大:A03:2021-注入
Snyk:不当的输入验证