粉丝9898获赞3.2万


老板,我累了,我累了,你知道吗?你们知道吗?缓解由于 react, next js 和 apm 用户不可恢复的堆占空间耗尽而导致拒绝服务漏洞, 所以今天我们要讨论的是一个远程 dos, 它会影响基于 try 剪 catch 处理程序和易补钩子的 nojsv 八实现。 你可能会问,谁会使用异步钩子呢? react 服务器组建,也就是任何进行服务器端渲染的地方,比如 next js, 其他使用异步本地存储的框架,以及基本上所有的 a p m 工具,比如 data dog, neuralic, data trace 等等,它们都使用了 a single cray hook 包。 各位,这里的主要问题是,在使用地规函数进行计算时存在一个问题,地规允许我们创建任意的战争。 如果你不清楚,堆栈帧基本上就是一块内存区域,用于存放给定函数的局部变量。所以在这个例子里,我们有阶乘函数。阶乘可以写成递归函数, 递归的意思就是我们调用函数自身,所以当我们调用阶乘五四三二一时,每次我们调用一个新的阶乘十力。除非我们做尾调用优化,否则我们会在堆栈上分配更多的内存来运行阶乘函数。 我们会分配更多内存来存储结成函数所需的变量,这样就会一直增长,一直增长,直到我们分配了太多的堆占空间, 超过了该进程允许的最大堆占空间量。在某些情况下,这被称为占溢出。现在问题在于,你知道,通常在 java script 中,如果你创建了一个非常非常递归的函数,你会得到一个范围错误,超过了最大调用堆占大小。你可以用一个非常简单的 try 减 catch 来阻止这种情况发生,对吧? 你可以用那个,你可以说,老兄你递归过头了,你递归的太深了,然后它就会进入你的 accept 块儿,对吧?问题在于,如果你使用了异步勾子系统,并且函数是异步的底层,使用了递归,那么它会直接杀死你的进程并返回退出代码七, 而不是允许 try 减 catch 快 来处理错误。而实际发生的情况是,它跳过了未捕获的异常处理程序,直接结束了进程。 想象一下,比如说你有一个 next js 的 api 路由,它调用了一个 handler, 而这个 handler 是 一个进行递归操作的 a sin 函数,对吧?它处理嵌套数据, 而处理嵌套数据实际上就是递归的映射到自身,直到到达某个数值的底部,对吧?你有数值,然后它会一直深入,深入,深入到数据中,直到数据不再是数值,然后你转换数据并返回,对吧?这里的视力数据是一个五万层深的 g s o n 数值,对吧? 这有可能任意的用户数据,这可能是用户提供给服务器的数据。所以你知道,在一个普通的非易步的不易受死影响的函数中, no 进城知道最大低规深度,如果你每次调用都超过这个深度,又会抛出一个范围错误,然后你就可以用 try 减 cash 来处理,对吧?这里发生的问题真的非常有趣。从非常技术性的角度深入来看, asincoke 的 工作方式是 javascript 中的任何一步操作,如果你不知道的话,都是一个 promise, 对 吧? 你实际上无法从异步调用中取回数据,你会得到一个 promise, 然后底层的异步运行时会解析这个 promise。 实际上它底层的工作方式是,这个异步沟子会触发以跟踪异步上下文,对吧?现在底层实际发生的情况是,异步沟子被包裹在一个 try catch 作用域中, 其中的 catch 模式是 k fatal, 明白了吗?所以,当你使用 try accept 时,对吧?可能会有多层嵌套的 try accept 语句。 当一个 e 不 勾子函数运行时,它会用这个 k f t 包裹它。 k f t 字面意思就是,如果发生任何事情,这都是一个不可恢复的错误,你需要立即退出。 问题是,如果你在这里更深入地进入调用堆栈,在一个使用此 e 不 勾子的递归函数中,即使你注册了内部 try 嵌处理程序, 他仍然被 k 减 fto 外部包装。这意味着,当你最终得到堆栈溢出错误时,他应该抛出一个范围错误,但你实际上得到的是一个 k 减 fto。 他 告诉晋城,嘿, 我们不知道该怎么处理,这很危险,我们必须杀死他,你必须离开那里,好吗?这不太妙。顺便说一句,我发现这件事超级有趣的事。这是 node js 内部的一个问题。 node js 是 javascript 的 运行时环境,在这个运行时中,它使用 v 八引擎来执行 javascript 本身,对吧?有趣的是, v 八并不认为这是一个安全问题。 你可能想知道为什么崩溃,非常糟糕。好吧, v 八主要是一个为浏览器开发的 javascript 引擎,对吧?浏览器是客户端软件, 与服务器端软件相比,客户端软件的安全模型大相径庭,对吧?浏览器崩溃并不算安全漏洞。 如果你过去两年用过互联网,你就会知道,我感觉我访问的每个网站,不管是哪种形式,比如 twitch, 都会导致我的浏览器崩溃。所以正因如此, v 八并没有意识到这个问题,因为它并不在它们的威胁模型之内,对吧?它不属于它们建立的威胁范围。 如果你能以一种不可利用的方式让 v 八崩溃,它们其实并不在意。好吧,我想从堆战溢出的角度来看,它就是崩溃了,对吧?或者堆战堆战耗尽。你知道,我们在这里使用了过载的术语,因此由于 nojs 依赖于 v 八,所以也继承了这个问题。 而且非常有趣的是,甚至定义 javascript 的 e c m a script 规范也规定你应该使用伪调用优化,这样你就不会有巨大的堆栈帧了。在地规情况下,你应该尽可能多地重用堆栈帧。 但即使是 v 八在内的大多数 javascript 的 引擎也没有实现这一点,它们通常只是像 c 语言那样进行地规调用,而且堆栈空间耗尽不是指定的行为。所以我们又回到 e c m a script 了。 超出最大调用堆栈大小错误并非 e c m a script 规范的一部分。规范没有施加任何限制。假设有无限的堆栈空间,施加限制和抛出错误仅仅是 java script 引擎尽力而为的行为。 基于未公开的功能构建安全模型不能保证其始终有效,因此是不可靠的。是的,这就是有趣的地方,对吧?就像即使规范里没有规定,堆栈也会受到内核的限制,对吧?进程是有优限制的。 归根结底,无论是规范还是实现者,都应该对堆站大小分配设置限制,而且它确实存在。很明显,就像我们有处理这个问题的范围错误一样。问题在于,一步沟子的异常处理程序与堆站溢出的异常处理程序交织在一起,对吧? 所以正因为如此,当你最终解决了那个错误时,他就会说,嗨,这是一个致命错误,我搞不定了,结束进程吧。然后突然你就陷入了拒绝服务攻击的境地,所以 是挺奇怪的。那这个是怎么修复的?实际上,在 node 的 try 减 catch 作用域内,它们所做的就是,嘿,如果我们捕获到一个异常,就进入这个异常。如果这个异常是战一出错误导致的, 我们只需要在较低层重新抛出这个异常,然后我们就可以继续沿着 catch frame 向下执行,对吧?否则,如果不是战一出,就把它当做 k 级致命错误处理 并终止异常。现在补丁已经发布了以下版本,所以如果你是使用了异步沟子的应用程序的开发者,并且可以接收欠套的 jason 对 象,我强烈建议你去打补丁, 因为你可能会遇到 dos 攻击的情况。所以各位有趣的事情是,即使在像 java script 这样沙盒化的语言中,处理任意用户数据也是非常困难的。真的非常困难。回答你的问题, rust 能解决这个问题吗? 不不,一概不,无限低微在 ras 中仍然会发生,对吧?实际上, ras 以更容易崩溃进程而闻名。如果你没有意识到这一点的话, 过去几个月发生的主要云服务中断事件之一就是由随按 rap 引起的分呐。阿摆是指打开合资的过程,你可以把它叫做 option, 它包含在一个 option, 要么是 non 类型。如果你按 rap 一个 option, 你 会使进程崩溃。 所以作为一种安全选择, rust 更有可能杀死一个进程,而不是让某些事情发生。这我猜和 v 八的模型类似,但至少在这种情况下,你知道这并不能解决问题。这里没有真正使用 rust 的 理由。总之,各位今天就到这里感谢观看,我很感激。 如果你喜欢这个视频,帮个忙,点个赞,然后去看看另一个视频,我觉得你也会一样喜欢。在那边见。保重。再见。

parachute 降落伞,比喻安全措施。 parachute 降落伞,比喻安全措施。 automated backups serve as a parachute when data corruption occurs。 当发生数据损坏时自动备份,可以作为一种安全措施降落伞。 automated backups serve as a parachute when data corruption occurs。 当发生数据损坏时,自动备份,可以作为一种安全措施。降落伞。

我们都知道船看起他可以捕获杰斯代码的报错,但有时候也会发生令人惊悚的失效情况。这里有一个揣看起他抛出了个错误,点击运行他可以捕获到错误,这没有任何问题。 但是如果我们在这里给他加上一部代码,也就是用 ctm out 包裹一次,那么他还能如期的捕获到错误吗?我们一起来看一看。 延时两秒, 点击运行, 看他的报错没有被捕获到,直接抛出来了,这是为什么呢?这个结果是不是非常离奇惊悚?这样场景其实还有很多,像阿贾克斯的回调 动物事件监听的毁掉里面的代码的报错,揣看起都是不能被捕获到的。他的原因是揣看起只能捕获同步的代码,因为他执行在主线城当中, 第二用战一旦结束了他的调用,他就会被清空掉,等一不代码爆错的时候,揣看起已经没有了,所以就捕获不到,直接抛出来了。 这个在实际开发当中,我们有时候会一不小心写出这样令人惊悚的代码,大家有这样的经历吗?

我呢去阅读大家,老师说处理异常就揣开始一下,其他的不用管,结果他在演示的时候特意留了一段永远都不会出错的代码,现在我在开始语句里永远只有一句输出 error。

面试官问,异常处理,别只说拆,开始包起来说我之前的做法,业务异常,比如库存不足,自定义异常,用十五跑 系统异常,比如数据库断联用拆开始抓,还要打日制。但更关键的是分层处理,在 ctrl 了层局补货,给用户友好的提示,在设备层抛出,让上层知道业务失败了。 在第一个层处理数据访问异常。还有 catch 的 时候,要从小到大先抓具体的,比如 no point exception, 再抓通用的 exception, 否则具体的异常永远抓不到,别逮一下都 catch。 之前有个同事把 no point exception 吞了,查了三个小时才找到 老樊整理的一份题目,全面命中率高、原创体检、持续更新的面试宝典,不管你是前端后端测试运维还是大数据,通通都整理在里面,粉丝群自取。你踩过异常的坑吗?评论区说说。

面试一个刚独立负责一个微服务模块的初级 java 工程师,我问你们服务中异常是怎么处理的?有没有统一的异常处理规范?他回答,每个方法都用 try catch 包起来,确保不会抛到外层。 我追问,那 catch 块里你写了什么?如果只是打印到控制台,线上服务器重启后日期就没了怎么办?如果异常被补货后没有重新抛出,调用方怎么知道失败了?他意识到问题没那么简单。 异常处理是代码健壮性的基石,也是初级开发者最容易忽视的细节。如果这道题目你也不会回答的话。我整理了让大厂 hr 沉默的必考题库,包含 jvm 夺命连环问、 spring 灵魂八谷高并发必杀场景、 radis 深度陷阱点个赞, 评论区甩六六六,打包带走 nice。 构建完善的异常处理体系需要掌握四个原则,一、理解异常的分类与处理策略。受检异常必须处理,如 a u i post 代表可预见的错误, 非瘦检异常 rationmention 及其此类。如 new protein 及其此类。如 new protein, 通常代表编程错误。错误如 opu memory error 一 般不应捕获。二、异常处理的最佳实践,永远不要空的 catch 快, 至少要记录日记, 使用日制框架 log back log 四 g r 而不是 system 点 out 点 clint, 保留原始异常信息 log 点 error, 而不是 log error。 适当包装异常,根据需要将底层异常包装为业务异常,但要保留卡斯链。三、异常处理的设计模式,统一异常处理。 spring 中可以使用 at controller advice 自定义业务异常,继承 run time inspection, 携带错误码和友好提示异常转换,将底层技术异常转换为业务层理解的异常。四、常见陷阱与解决方案异常被吞掉 在 find 的 块中,不要返回可能覆盖 try catch 中的返回值。过度捕获,不要直接 catch 应捕获具体异常 资源泄露,使用 try with resources, 确保资源被正确关闭。牛逼牛逼!这道题从简单的加 try touch 深入到异常分类、日制规范、 架构设计等多个层面,良好的异常处理能极大提升系统的可维护性和可调试性。你见过最糟糕的异常处理代码是什么样子?

