哈哈~标题党了,各位。
事情是这样的,今天在做接口测试,我对接口的每一个传参都进行了长度和数据类型验证。发现每个传参在后台都没有校验,然后和开发人员沟通后出现了以下对话。
我:接口传参长度和数据类型应该与数据库设计的对应字段保持一致。(该接口是实现保存功能)
开发:接口参数没有可能完全校验,代码量非常庞大 性能也受影响
开发:这些都要检查是不是真实有效 全部去数据库中查一遍,这样就要查 N 遍数据库,校验都能把性能搞死去
所以我想请教一下各位大佬,以下问题。解决我自己的疑惑
1、一般的软件公司是有此规范吗(对参数长度数据类型和数据库保持一致)
2、如果进行这些校验真的会造成大量的冗余代码和对接口性能影响会很大吗?(这里我说一下自己的理解,我认为接口传输到 java 代码层面上,封装对应的校验长度和类型的方法是不至于会对接口造成很大的性能影响,更别提冗余代码。也不会出现开发人员所说的要去查询 N 遍数据库的情况,因为在代码层面已经拦截并抛出异常了,不会再去到数据库进行查询)
3、各位大佬是怎么解决这样的问题吗,可以给一点思路或者方向吗。谢谢大家了。
你的开发在瞎扯淡。。。。
不过,一般来说除了特殊情况,是不会每个字段都去检验长度的
用拳头说话吧
但我觉得接口层面做了这两个校验会把很大一部分的安全问题都拦截了啊,所以我觉得是有必要的,当然从功能层面上考虑确实是增加了开发人员的工作量~
啥都不做肯定会增加报错几率,比如字段超长了啊……
可以从前端/客户端控制就没必要一定后端限制,保持一定的兼容性
不需要每个字段都校验 最好保持和前端校验一样的限制就行。有些东西最好产品项目上一起具体讨论下
建议先把这个问题作为一般级别的 bug 记录下来,提交给对应研发人员,如果无法解决,让他给出明确的解释,然后给到上级决策,没必要跟他私下过多沟通
客户端做一下限制就好了吧
核心字段做个 CRC。。。
有必要一个字段一个字段判断么。。。
你测试可以造异常数据,只要不崩没有影响不就好了。出错、崩了、内存泄漏就给你改啊。
我现在是真的怕有些人长期在不重要的事情上过度设计,头疼。。。
接口传参长度和数据类型应该与数据库设计的对应字段保持一致
楼主可以分享下你要测的接口参数是什么,对应设计的测试用例大概是什么,哪些用例执行失败引发这个帖子的思考么?
如果从上面这个文字意思上看,这个接口和数据库长度、类型保持一致的限制有点死,一旦长度要变化(比如需求有改动),服务端代码 + 数据库 DML 都得改,略麻烦。一般来说,数据库字段长度限制会设置得比实际业务规定长一些,避免后面改大还得改 DML 走审批流程那么麻烦。而且常用的 varchar 变长字段类型是按实际内容占用存储空间的,这个长度设大一点,不会引起什么副作用。有时候偷懒会直接不设置接口的校验,直接交给数据库来限制(大于字段定义长度,数据库会直接无法入库,返回失败,但一般这种情况不好给明确指示用户是超出长度,只能后台查日志看出,所以说是偷懒)
另外,不知道你们后端使用什么语言框架做开发,如果用的 spring ,类型和长度这类比较死的限制,复杂度不高,甚至在写接口定义代码的时候就可以完成了。
数据类型:数据类型这个 spring 是自动根据服务端设定的参数数据类型转换的。比如类型是字符串,那接口不管传字符串的 0 和数字的 0,框架都会自动转为字符串的 0。但如果类型是数字,传了个转不了数字的字符串(比如 a ),框架会自动报错拦截。
长度限制:接入 JSR 303 框架,给要限制的参数加上 @Size(min, max)
注解就可以了(可以参考 https://www.jianshu.com/p/d2ddd856cce2 )
en~,我先来解析一下第三点,这里并不是要求开发人员写代码去到数据库找到对应的字段来进行校验,其实在做数据库设计的时候设计人员就把对应的数据字段对应的长度和类型设计好,所以我的意思是要求开发人员实现接口的时候,对应的数据类型和长度要和数据库设计的保持一致。
第二点的话,我和开发人员沟通后,他们也说是采用 validator 做简单的校验,但是如果做长度校验的话很多地方都会写死。这个他们当时也是认为太不灵活,如果用此方法,后面修改对应的字段长度的话会涉及很多地方的修改。
嗯嗯,应该和产品、开发人员进行会议讨论,但是团队还是有一些模糊的理解。比如我们都约定好,只对一些有业务修改的接口做长度的校验限制,但是那些接口需要我们就比较难定义,或者说什么样的接口是一定要做长度校验的呢?(因为我之前的认为都是所有接口都是必须做长度校验)
其实我是基于安全方面进行考虑的,当时我在写接口用例,然后我就想如果前端/后端都按数据库设计来进行的话是不是很大一个程度提高了系统的安全性(如:SQL 注入,只要对每个传参类型和长度进行校验,就能很大的把 SQL 注入难度提升一个级别。)所以我当时的理解就是所有的接口都必须做长度和类型的校验,最好和数据库设计的字段保持一致。
但是开发人员说用另外的一种方式也能有效的解决 SQL 注入的问题,不需要在接口上对每个传参做校验。经过产品、开发和测试人员的会议沟通后我们达成了一点意见,就是重要的功能或者有必要的字段就必须做长度校验,类型校验的话在接口实现时候定义变量和数据库设计保持一致。但是问题又来了,那些接口需要我们就比较难定义,或者说什么样的接口是一定要做长度校验的呢?(既然开发人员也说有另外的方法对安全问题进行拦截,我觉得我当时考虑的问题就已经解决了)
第二点,我们采用也是 springboot 架构。也和你说的一样,当时开发人员人为写死的话不够灵活,如果数据库字段改变后需要修改写死的地方~
看了楼上的一位同学的说法~,我也在考虑我这样的用例设计是不是真的是过度设计了~。纠结…
这么说吧,软硬件设计从来就不是 0 和 1 的事情。
具体到具体的项目,实际上是开发成本和质量的博弈。
我目前的主要的核心思想是:利用 28 原则,关注最重要的 20% 的事情,剩下的能不动就不动。
怎么写接口,怎么规范化,没有多人合作的项目这些都不重要。
对我自己来说,只有两件事重要:
其实我是基于安全方面进行考虑的,当时我在写接口用例,然后我就想如果前端/后端都按数据库设计来进行的话是不是很大一个程度提高了系统的安全性(如:SQL 注入,只要对每个传参类型和长度进行校验,就能很大的把 SQL 注入难度提升一个级别。)所以我当时的理解就是所有的接口都必须做长度和类型的校验,最好和数据库设计的字段保持一致。
你说的这个想法,是有具体实例佐证么?有的话,可以分享下?
以我对 sql 注入的了解,通过这种方式去防范有点 隔靴搔痒 的味道。sql 注入防范的核心是在数据解析 sql 的位置,防范用户原始输入值带有 sql 关键字引发 sql 查询实际作用和设计目的产生很大的差异,进而泄漏一些不应该出现的数据。比如很常见的 sql 注入参数输入值:1 or 1 = 1
,长度一点都不算长,类型也只是一个很普通的字符串,但里面带有 sql 关键字 or
、=
,会引发 sql 语义变化,所以需要进行防范。而且这类防范,mybatis、jpa 等常见的数据库连接框架,写法规范的情况下已经自动进行防范了,从接口规范层面通过字符类型 + 长度去防范,个人觉得实在没有必要,也不一定能起到实质性的防范效果。
可以问问自己以下两个问题:
有 SQL 注入风险,可以用 SQLMAP 扫一遍,用安全缺陷说话。
有功能上的缺陷,可以用功能缺陷来说话。
设计上的问题,我们可以给建议,但是建议最好有事实的依据,毕竟你不是产品,也不是设计者。
之前遇见过的一些安全问题,虽然问题是不太大,但确实是一个安全隐患。接口要求传参数,zbdw(int),zbdh(int)。后传入参数 zbdw=njdhs>'',zbdh='1',发送请求后,接口返回的数据把对应的实例、表,字段都暴露
sql 注入一般只是后端 ORM 框架使用问题,参数未绑定,造成了动态 sql,可以百度 PreparedStatement
你这个返回是单纯的 Oracle 字段超长错误,后端没有做捕捉统一封装处理,跟你输入的是不是用作注入测试的字符串无关,这种不友好的 exception 暴露到前端可以提 bug 给后端请他们统一封装处理就行了,办法么,在 spring 下自然绕不过 AOP 去实现,并不需要通过本 topic 所讨论的接口参数限制来实现。
一般后端的框架里面都带有校验的功能吧,很少再需要开发再写校验逻辑了; 向 python 中 DRF 框架 ,serializers 就充当了参数校验的功能。 java 的话应该也带的有,可能只是你们开发没有使用吧。
你这里的安全问题应该是暴露了敏感的内部错误信息吧。解决方法应该是线上环境通过配置 AOP ,在最后返回内容前换用统一的错误信息(比如常见的 Internal Error )避免直接返回原始 exception 信息。
接口入参类型不一致只是引起这个问题的其中一种原因,如果下一次这个入参不是来自于接口,而是来自于数据库数据或者别的输入,你光限制接口参数长度就没法防范了,所以这个问题不应该通过限制接口参数长度来解决,成本高且无法彻底解决问题。