网站是否应该限制可以在其字段中输入的字符?

信息安全 防御 验证 统一码
2021-08-31 14:26:24

今天我和我的同事就我们的应用程序应该接受哪些字符进行了(有点激烈的)讨论。这是由发现您可以在搜索框中输入任何内容而提示的,应用程序将尽职尽责地按该字符串执行搜索。但是,这同样适用于应用程序中的所有文本框,而不仅仅是搜索框。

我的同事认为,最佳实践(从安全角度来看)是将允许的字符限制为某些字母、数字和符号子集。这可以防止用户输入各种不可打印的 Unicode 控制字符等。

另一方面,我认为这只会惹恼用户并且不会提供任何额外的安全性。我认为最好的做法是让您的应用程序接受任何内容,然后使用正确的编码函数(以及参数化查询,如果它们可用)来确保输入的字符串未经修改通过并按输入显示/使用。如果用户输入垃圾,他会看到垃圾,但系统会正常工作。

这里的行业最佳实践是什么?

补充:好像我还不是很清楚。问题是关于服务器端的,假设是在使用字符串时所有正确的编码/转义都到位(例如,使用 SQL 参数、用于输出到 HTML 的 HtmlEncode 等)。鉴于所有这些,限制从客户端到达的允许字符是否仍然有意义?

4个回答

你不应该相信客户。编写 Javascript 来阻止输入字符不会阻止任何人将它们提交给您的搜索。

您的搜索例程应该删除它不支持的字符,并且在将其打印出来时,它应该显示它实际接受的内容,而不是提交的内容。

对于表单中的通用字段,考虑添加客户端验证以获得更愉快的用户体验;在我点击提交之前,我宁愿知道您不会在电话号码字段中接受非数字。但是,如果我绕过您的 Javascript 检查并提交表单,后端服务器应该完全拒绝我的无效数据;不要只使用 Javascript 来清理输入。

此外,虽然大多数字段可以接受用户可以输入的任何内容并在其他地方重复,但必须正确转义以防止跨站点脚本(例如,用户不能将其名称设置为<script src="...">)。一些领域有额外的担忧;例如,如果您允许用户选择唯一的用户名,则Unicode 等效性可以允许他们为其名称选择唯一的编码,但看起来与另一个用户的名称相同,从而允许冒充。规范化是不够的,因为某些角色看起来像其他角色,仍然允许模仿。阅读 Unicode 安全注意事项以了解更多信息。

编辑:你的同事仍然有观点。服务器端并不是孤立存在的。如果它接受来自用户的输入,然后稍后将其中一些输入显示给其他用户,那么服务器端对狡猾的输入具有防弹能力是不够的。客户端发生了一整类安全问题,因为服务器端完全按原样存储数据并盲目地将其分发给其他客户端(然后被攻击或愚弄)。的,服务器端需要限制输入字符,如果它们在再次发回时会利用或欺骗您的用户。

推荐阅读:

你的方法——如果使用得当——可以保护你免受两种非常常见的攻击:SQL 注入和 XSS。转义/编码/准备好的语句绝对是必备的,也是你的主要防线。

但是当您特别提到搜索框时,您的方法可能例如无法捕获 SQL 通配符 DOS 攻击(请参阅此处此处),这可能会被输入验证(服务器端;您显然不应该使用客户端 JavaScript )。

您的方法也不会捕获代码中的安全漏洞。当你的代码库变得足够大时,你在一个地方忘记正确编码的可能性就会增加,所以有额外的保护——以服务器端输入验证的形式——来防止它不是一个坏主意。

从用户体验的角度来看,这也不错(如果用户输入了无效数据,最好将其报告给他们,以便他们知道出了什么问题,并且现在可以输入有效数据)。

缺点是工作量更大。您实际上必须考虑应该允许哪些输入,不应该允许哪些输入,因为正如您所说,如果您过滤掉太多,它可能会限制用户。如果您不想为每个可能的输入字段执行此工作,Web 应用程序防火墙可能是一种替代方法。

您应该同时实施这两项措施,并说明原因。

例如,如果您限制用户可以输入的字符空间 (a-zA-Z!@#$%^&*),那么不知情的用户就不太可能搞砸并输入一些垃圾数据。但是,这只会真正阻止尝试使用您的应用程序的最终用户输入格式错误的数据。第二步,对数据进行适当的清理和编码将确保您免受 XSS/SQLi 和各种其他潜在攻击。

所以两者都用。限制用户进入以阻止不了解的最终用户,并清理数据以阻止那些更聪明的人。

上面的答案中有很多很好的建议,但我不确定他们是否解决了您问题的主要部分,即限制输入数据的数量/大小。

回顾已经陈述的内容

  • 使用客户端输入验证和反馈来改善客户端用户体验,但不要出于安全目的依赖任何客户端。所有客户端措施都很容易被击败。客户端是为客户服务的,应该以客户为中心

  • 在服务器端进行所有安全检查、数据验证、清理数据等。假设提供的数据是敌对的并且不能被信任。尽可能使用经过充分测试的已知解决方案,而不是重新发明轮子,如果您不允许某些事情,请尝试向用户提供反馈,以便他们知道正在发生的事情并可能重新构建他们的输入

关于限制数据量和允许哪些数据的问题,我认为这是对你接受的自由和你所做的保守的概念的不准确解释,我建议

  • 接受你不能使用的数据是没有意义的。您可以使用的内容取决于构成您的应用程序的组件的限制(数据库、支持的字符编码、最大缓冲区限制等)

  • 接受太长的数据以适应您对它的任何用途是没有意义的,即接受长于数据库字段长度的数据字段是没有意义的

  • 考虑与极长输入数据相关的性能损失。例如,如果它是一个搜索字符串,是否存在限制,即极长查询消耗的性能或资源会对您的系统产生不利影响或最终返回不可用的结果?

  • 是否存在无限输入长度可能触发缓冲区溢出漏洞的风险?是否所有组件(库、外部系统、数据库等)都能够处理任意长度的输入数据,或者它们会崩溃、意外截断等

在你接受的东西上自由并不意味着你必须使用你接受的一切。这真的意味着不要只是失败或崩溃。这意味着向用户提供反馈,为什么您无法处理输入并捕获故障,以便妥善管理它们。如果您不能使用所提供的内容或以可靠的方式处理它,那么争论您应该接受一切以获得良好的用户体验是没有意义的。但是,您不应在未告知用户原因或限制的情况下静默删除字符或截断输入。只有在不清楚什么是可接受的,什么是不可接受的时候,用户才会感到沮丧——提供清晰的信息,以便他们的期望与您的能力相匹配,这样沮丧的用户就会少得多。