数据输入验证-在哪里?多少?[关闭]


28

数据输入验证对我来说一直是内部的斗争。

即将在我们的旧应用程序重写项目中添加一个真正的安全框架和代码(到目前为止,该框架几乎保持了卡式城堡般的旧安全代码和数据验证),我再次想知道应该验证多少,哪里等等

在担任Java专业开发人员的5年中,我创建并完善了个人规则,以进行数据输入验证和安全措施。当我想改进自己的方法时,我希望有人听到你们的一些想法。通用规则和过程很好,并且特定于Java的规则和过程也很好。

归纳起来,以下是我的指南(在3层Web应用程序样式中公开),并带有简要说明:

  • 第一层客户端(浏览器):最低限度的验证,只有不变的规则(必填电子邮件字段,必须选择一项,依此类推);减少使用诸如“ 6到20个字符之间”之类的附加验证的频率,因为这会增加对变更的维护工作(可以在业务代码稳定后添加);

  • 第一层服务器端(网络通信处理,“控制器”):我对此没有规定,但我认为此处仅应处理数据处理和组装/解析错误(生日字段不是有效日期);在此处添加进一步的验证很容易使其变得很无聊。

  • 第二层(业务层):可靠的验证,不少于;输入数据格式,范围,值,内部状态检查(是否可以随时调用方法),用户角色/权限等;使用尽可能少的用户输入数据,如果需要,再次从数据库中检索它;如果我们也将检索到的数据库数据也视为输入,则只有在已知某些特定数据在DB上不可靠或已损坏得足够多的情况下,我才会对其进行验证-强类型化在这里做了大部分工作,恕我直言;

  • 第三层(数据层/ DAL / DAO):从来没有认为这里需要太多的验证,因为只有业务层才可以访问数据(在某些情况下,例如“ param1为true时,param2不能为空”验证);但是请注意,当我的意思是“这里”是指“访问数据库的代码”或“ SQL执行方法”时,数据库本身是完全相反的;

  • 数据库(数据模型):需要充分考虑,强大和自我实施,以尽可能避免DB上的数据不正确和损坏,并具有良好的主键,外键,约束,数据类型/长度/大小/ precision等-我不再赘述,因为他们有自己的私人讨论。

我知道早期的数据验证是不错的并且是性能方面的,但是重复的数据验证是一个无聊的过程,并且我承认数据验证本身很烦人。这就是为什么这么多编码员跳过它或半途而废的原因。同样,如果每个重复的验证并非始终保持同步,则可能是一个错误。这些是当今我更喜欢将大多数验证放到业务层的主要原因,但要浪费时间,带宽和CPU,并要逐案处理异常。

所以,对于这个你有什么想法?反对意见?您还有其他程序吗?提到这样的话题?任何贡献均有效。

注意:如果您正在考虑Java的做事方式,我们的应用程序是基于Spring的Spring MVC和MyBatis(性能和不良的数据库模型排除了ORM解决方案);我计划将Spring Security添加为我们的安全提供程序以及JSR 303(休眠验证器?)。

谢谢!


编辑:在第三层的一些额外的澄清。


我的建议是研究Hibernate Validator的工作方式。对于持久性期间进行的验证,我还没有发现JSR 303有用,而我的某些规则必须在持久性之前执行很多,因为我的业务规则依赖于基本验证。我认为,它适用于非常封闭的模型;也许我使用的方式不正确,但我从未找到任何经验与我不同的人。
Vineet Reynolds,

@Vineet Reynolds我已经将它用于Spring MVC的表单验证,这确实是一个很好的组合。我得到服务器端的验证,其中包含细粒度的消息,几乎不费吹灰之力,就会向用户显示适当的错误。我仍要完全在服务器端对象上对其进行测试,不确定其优势。看看这个示例帖子,这就是我的用法:codemunchies.com/2010/07/…– mdrg 2011
6

2
进行过多验证。到处都是该死的用户输入@#!@@!
Chani

Answers:


17

您的验证应一致。因此,如果用户在Web表单上输入了一些确定为有效的数据,则由于某些未在客户端实现的条件,数据库层不应拒绝该数据。

作为用户,没有什么比看上去明显正确地输入页面数据更令人烦恼的了,而只有在经过大量的数据库往返之后才被告知某些问题。如果我在此过程中进行了一些客户端验证,则尤其如此。

在公开这些内容时,您需要在各个不同级别进行验证,并且可能无法控制谁在调用它们。因此,您需要(尽可能)安排将验证定义在一个位置,并在需要的地方调用。如何安排将取决于您的语言和框架。例如,在Silverlight中,您可以在服务器端定义它,并使用合适的属性将其复制到客户端以供使用。


2
+1。我本来想对ASP.NET MVC说同样的话,但是您击败了我。:)实际上,我们只需要进行必要的验证,以确保系统保持有效状态。其余的验证(如客户端)将提高用户的可用性和时间浪费,因此这应该是主要重点。一致性是关键。
Ryan Hayes

2
关于“往返”,只要页面重新加载正确的错误消息,并且所有字段都填写了您之前输入的内容(大多数接口在最后一个细节中都不够用),我就认为没有问题。如果花很长时间才能找回错误,则可以进行其他客户端验证。
mdrg 2011年

并且可以肯定的是,如果可以轻松地在整个应用程序中复制验证,则没有理由浪费它。在服务器端,这很容易,但是在客户端,如果没有诸如您提到的验证工具之类的工具,它将变得非常沮丧(即:编写许多JS验证代码,就像您在服务器上编写的那样)。 。
mdrg 2011年

10

在关系系统中,我将其视为三层方法。每层都受到以下层的约束:

  • 演示/ UI
    • 简单的输入验证
    • 如果输入格式错误,请不要继续
    • 向服务器“门”客户端请求以减少往返次数,以提高可用性并减少带宽/时间
  • 逻辑
    • 业务逻辑和授权
    • 不要让用户做他们不允许做的事情
    • 在此处处理“派生的”属性和状态(在数据库中将被非规范化的事物)
  • 数据
    • 基本数据完整性层
    • 绝对拒绝存放任何垃圾
    • 数据库本身会强制使用数据格式(整数,日期等)
    • 使用数据库约束来确保适当的关系

理想的答案,这将是一个系统,可以让你在一个地方的所有三层定义的约束。这将涉及一些用于SQL的代码生成,以及至少一些针对客户端和服务器的数据驱动的验证。

我不知道这里是否有任何灵丹妙药...但是由于您使用的是JVM,我建议您考虑使用Rhino至少在客户端和服务器之间共享JavaScript验证代码。不要写两次输入验证。


我来看一下犀牛。如果它可以某种方式与Spring MVC表单验证集成,那就更好了。
mdrg 2011年

8

•第三层(数据层/ DAL / DAO):从来没有认为这里需要太多的验证,因为只应该访问业务层(验证在某些情况下,例如“ param1为true时,param2不能为空”) 。

错了 进行验证的最重要位置是数据库本身。数据几乎总是受到比应用程序更多的影响(即使您认为不会),充其量没有将适当的控件放入数据库中也是不负责任的。决定不这样做的数据完整性损失比任何其他因素都多。数据完整性对于数据库的长期使用至关重要。我从未见过任何在包含良好数据的数据库级别上未能执行完整性规则的数据库(并且我已经看过数以千计的数据库中的数据)。

他说的比我好:http : //softarch.97things.oreilly.com/wiki/index.php/Database_as_a_Fortress


我同意本文的最后一部分,我想我在这一部分还没有说清楚。我用进一步的细节更新了这个问题。谢谢!
mdrg 2011年

2

以上所有假设均假设开发人员和维护人员是完美的,并且编写了始终能够完美运行的完美代码。未来的软件版本将了解您所做且从未记录过的所有假设,以及以前所未有的方式将数据放入系统的用户和黑客。

当然,过多的验证是一件坏事,但是假设程序,网络和操作系统完美无缺,黑客不会通过您的防火墙,DBA不会手动“调整”数据库可能会更糟。

在事物周围绘制边界圆,确定其所防止的故障模式,并对该边界实施适当级别的检查。例如,您的数据库永远都不会看到无效数据,但是它将如何发生?您的用户是谁,失败的代价是多少?

研究物理世界的安全模型时,安全性应该是分层的,就像洋葱一样。一堵厚墙被认为安全性差。数据验证应以相同方式考虑。


1

两条简短的通用验证规则:

如果您要调用的任何内容都不能保证会返回某些内容(错误,异常),以使您可以将其传递回调用方的方式告诉您无效的输入,请对其进行验证。

如果您要对数据做其他任何事情(制定决策,进行数学运算,存储数据等),请对其进行验证。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.