周志明的软件架构课
周志明
博士,远光软件研究院院长,《深入理解 Java 虚拟机》《凤凰架构》等书作者
54203 人已学习
免费领取
课程目录
已完结/共 74 讲
架构师的视角 (24讲)
周志明的软件架构课
15
15
1.0x
00:00/00:00
登录|注册

30 | 验证:系统如何确保提交给服务的数据是安全的?

你好,我是周志明。今天是安全架构这个小章节的最后一讲,我们来讨论下“验证”这个话题,一起来看看,关于“系统如何确保提交到每项服务中的数据是合乎规则的,不会对系统稳定性、数据一致性、正确性产生风险”这个问题的具体解决方案。

数据验证也很重要

数据验证与程序如何编码是密切相关的,你在做开发的时候可能都不会把它归入安全的范畴之中。但你细想一下,如果说关注“你是谁”(认证)、“你能做什么”(授权)等问题是很合理的安全,那么关注“你做的对不对”(验证)不也同样合理吗?
首先,从数量上来讲,因为数据验证不严谨而导致的安全问题,要比其他安全攻击所导致的问题多得多;其次,从风险上来讲,由于数据质量而导致的安全问题,要承受的风险可能有高有低,可当我们真的遇到了高风险的数据问题,面临的损失不一定就比被黑客拖库来得小。
当然不可否认的是,相比其他富有挑战性的安全措施,比如说,防御与攻击之间精彩的缠斗需要人们综合运用数学、心理、社会工程和计算机等跨学科知识,数据验证这项常规工作确实有点儿无聊。在日常的开发工作当中,它会贯穿于代码的各个层次,我们每个人肯定都写过。
但是,这种常见的代码反而是迫切需要被架构约束的。
这里我们要先明确一个要点:缺失的校验会影响数据质量,而过度的校验也不会让系统更加健壮,反而在某种意义上会制造垃圾代码,甚至还会有副作用。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了Java Bean Validation的重要性和最佳实践。文章强调了数据验证在系统安全中的关键作用,指出了数据验证与程序编码同样重要,而且不严谨的数据验证可能导致比其他攻击更为常见的安全问题。作者通过实际段子展示了数据验证在前端和服务端的重要性,并讨论了在哪一层进行验证的最佳实践。文章提倡使用Java Bean Validation来剥离验证行为,而不是依赖于特定的层级。通过讨论数据验证的重要性和最佳实践,为读者提供了关于系统数据安全的深入了解。文章还介绍了Bean Validation的优势,包括对无业务含义的格式验证的预置、对有业务含义的业务验证的重用,以及避免对输入数据的防御污染到业务代码。作者还给出了具体的代码示例,展示了Bean Validation在用户资源上的应用,以及对校验结果不满足时的提示信息处理等。总的来说,本文通过介绍Bean Validation的最佳实践,为读者提供了系统数据验证的重要性和实际应用方面的深入了解。

该试读文章来自《周志明的软件架构课》,如需阅读全部文章,
请先领取课程
免费领取
登录 后留言

全部留言(13)

  • 最新
  • 精选
  • 三产
    老师,之前在项目中推广过bean校验器,但是会被别的同事以性能比直接写代码低回怼,请问这个应该在考量范围么?还是影响极其有限呢?还是确实有些场景性能要求比较高(比如一些中间件之类),需要分情况来决定是否使用呢?我这边只做过业务系统,所以视野比较狭窄,希望能得到您的回复

    作者回复: 以性能为主要考量依据在这个场景下是不恰当的。 软件开发中有一个著名的经验法则——克努特优化原则 ,比起名字,它的内容陈述也许更广为人知:过早优化是万恶之源。 “过早优化”是指试图在没有实践数据或者合理的预测下,过度追求效率的行为。过早的优化尝试通常会导致适得其反,并导致浪费大量资源,如时间、金钱和精力,同时也增加了未来出问题的可能性。

    2021-01-26
    38
  • Jxin
    1.而把简单的校验交给 Bean Validation,把复杂的校验留给自己,这简直是买椟还珠故事的程序员版本。正中红星。 2.对校验这个做法,我与周大佬的观点不同,提出来求指正: a.大部分业务校验我是在工厂类里面做的。理由是,合规校验的逻辑是聚合创建这个业务事件的组成部分,不该将它与创建事件分离。一个聚合创建需要做的合规性校验分散到工厂外不符合高内聚的要求,是一种怀味道。 b.有些校验是基于中间实例做的,生成聚合实例后再返回去查找出这个中间实例做校验是反人类的,并且也不是所有场景你都能反查到,比如多对一。 c.领域层的聚合类要保证干净,哪怕是校验注解我都觉得是坏味道,因为当我这个聚合实例被创建成功,那么它必然是合规的。 4.一个聚合的行为,它可能是校验+功能逻辑共同组成。如果把校验逻辑抽离聚合行为,那么聚合行为就会是一个没有校验的行为。你没办法保证别人不会误用这个行为,因为你把原本应该是一个原子的校验+功能逻辑拆分开了。(等下去拜读下周大老的代码。不过哪怕还没看,我也能确信,这个校验注解无法在new出来的实体里面生效,应该是只能对绑定在一个上下文中的实例做切面校验)

    作者回复: 不同观点是好事,欢迎欢迎。 我的看法:Bean Validation所面向的场景,或者说校验这种行为的本意重点应该是面向外部防御,譬如用户输入的信息、方法被他人调用所传入的参数、服务从客户端接受的数据是否正确,工厂类的产出一般是面向内部的,一般不包含外部输入的信息。 校验这件事情既可以在边界上刚刚收到对象时做,也可以在对象将要被消费时候进行,甚至在中间过程中的某个阶段中完成,很难会说有哪一种做法是绝对正确的,也就很难只局限在某一处(工厂类或者其他某个特定的层次、功能)中完成,这也是文中的观点:将校验独立出来,不必与任何一层耦合,但任何一层都可以使用,需要时,通过注解或者代码来触发。对应到实际软件的例子中,譬如最外层的RESTEasy有Bean Validation支持,最内层的Hibernate也有Bean Validation支持。 关于4,new出来的对象【一般】是不会被注解所影响的,所以Bean Validation提供了Validation Methods(https://beanvalidation.org/2.0-jsr380/spec/#validationapi-validatorapi-validationmethods)供用户通过编码来调用。 这里“一般”二字加粗,是因为它存在着“抬杠”的余地,JSR269(https://jcp.org/en/jsr/detail?id=269,随着JDK6发布的)之后,其实是可以通过注解来实现元编程的(Metaprogramming,就是写出编写代码的代码)。如果我写一个(代码中并没有写)Annotation Processer,完全可以在编译时自动生成出校验的调用代码,这时候“我也能确信,这个校验注解无法在new出来的实体里面生效”就并不成立。这点也可以对应到实际软件的例子中,譬如lombok中的@Getter、@Setter等注解,就是可以对自己new的对象生效的。

    2021-02-09
    25
  • walnut
    实际是需要在controller或service都进行bean校验吗?

    作者回复: 不不不,倡导的是不把校验代码耦合在任何一层。校验只是与bean相关,bean是各层通用的,用到bean的地方有需要就可以用注解触发校验,没有需要就不去校验。

    2021-01-25
    9
  • zhanyd
    而把简单的校验交给 Bean Validation,把复杂的校验留给自己,这简直是买椟还珠故事的程序员版本。扎心了,说的就是我。。。 如果是比较简单的业务校验又不涉及到重用,是不是在Service层做就行了啊?毕竟采用 Bean Validation还要新增好多类,增加了代码的复杂度。

    作者回复: 你的是代码的所有者,并没有什么条条框框的约束是不可逾越的。只要合理,就可以做。

    2021-01-25
    2
    7
  • 有铭
    通过代码手动触发校验是什么意思,注解不都是自动触发的吗

    作者回复: 可以使用BeanValidator::validate()方法来手动校验。 譬如在方法过程中,需要验证某些中间对象,就需要用到。

    2021-02-03
    2
    3
  • d
    周老师我之前所在的业务场景本来就小也没人 软件也只满足功能即可 用量一年新增不会超过一万,我搞的无bean处理 java地方做了些封装处理 全部采用nashorn/graaljs 写逻辑 java地方大多封工具包 我这种方法是不是很垃圾啊 不过开发速度是真快改着也快 一个功能热更新还是改点逻辑上生产都是秒级分钟级,响应速度上感觉还好无io之类也就1ms😂

    作者回复: 当然不垃圾呀,相反在合适的场景选择合适的方案是务实的体现。 在许多性能不敏感啦、又经常容易发生变动的地方我也常采用类似方案。

    2021-03-13
    2
  • 冬风向左吹
    不错的扩展文章: https://www.cnblogs.com/beiyan/p/5946345.html
    2021-02-02
    4
  • walkingonair
    终于差不多要跟上老师的脚步了,这么多篇看下来,老师从源头上讲述问题真的很赞。 Bean验证器我恰好也是老师说的把复杂校验留给自己的人,哈哈。主要原因是复杂校验千奇百怪,再做一层封装虽说与业务逻辑解耦了,但是校验层变复杂了,或许会把问题转移到校验层。 另外,对校验的封装后大量使用注解对性能的影响可以忽略不计吗?期待老师解答 最后,老师讲的校验使用方法挺酷的,我也打算少量使用,看看效果。 函数式编程很棒👍🏻
    2021-01-29
    2
  • laolinshi
    我理解的是把各种验证功能从业务逻辑中独立出来,不跟各个层的代码耦合在一起,是为了复用各种的验证功能。当某个层的代码在执行过程中需要验证功能时,就可以通过恰当的方式(比如注解)把符合要求的验证功能引入进来
    2022-04-10
    1
  • neohope
    之前只是零零散散有了一些想法,也落地了。但看完今天老师的讲解,感觉落地的很难看。 数据校验这部分,回顾了一下,我们真的做了很多,但十分十分的零散。根据各种要求,包括架构、运维、数据安全、数据合规要求、数据脱敏、敏感数据加密,每年都要折腾个几轮。此类代码横跨了文章中提到的全部层,实现方式从单纯的编码规范,到各层编码,到切面,到流水线扫描,到Jar包,到中间件、到持久化层验证,都有零散涉及。如果能尽量统一到 Bean Validation处理,就不至于每次加个要求,都要一通大改了。
    2021-04-05
    1
收起评论
显示
设置
留言
13
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部