OurJS


OurJS-我们的JS, 我们的技术-IT文摘; 专注JS相关领域;
我们热爱编程, 我们热爱技术;我们是高大上, 有品味的码农;

欢迎您订阅我们的技术周刊


我们会向您分享我们精心收集整理的,最新的行业资讯,技术动态,外文翻译,热点文章;
我们使用第三方邮件列表向您推送,我们不保存您的任何个人资料,注重您的隐私,您可以随时退订,

欢迎分享您的观点,经验,技巧,心得

让我们一起找寻程序员的快乐,探索技术, 发现IT人生的乐趣;


本网站使用缓存技术每次加载仅需很小流量, 可在手机中流畅浏览;
如果您发现任何BUG,请即时告知我们: ourjs(at)ourjs.com

Node.js安全教程:防止阻塞Event Loop的潜在攻击


分享到
分类 骇客攻防   关键字 JavaScript   发布 newghost  1420606197252
注意 转载须保留原文链接,译文链接,作者译者等信息。  
注* 发表于2012年

有一些人问过我:

我们的node.js服务器会偶尔挂一段时间(几秒钟),为什么会这样?

那么,为什么会这样呢?简单的回答是,我们的代码时不时地阻塞了node.js的事件循环(Event Loop)。你可能已经知道了node.js —— 像浏览器中的JavaScript一样 —— 是单线程的。是由一个事件循环驱动的。一次只会处理一件事件。并行处理在这里是不存在的。所以node.js很善于处理I/O密集型的工作。因为在处理一个请求时,大部分时间是花在I/O等待上面了。(从磁盘上读取数据,从网络收发数据),但是它并不善长处理CPU密集型的工作。

当没有太多的计算量且不要求马上返回结果时,这种协同可以很好的工作,比如:

function requestHandler(req, res) {
   db.getUser(req.params.uid, function(err, user) {
       res.end(user.username);
   });
}

JavaScript在很多方面的设计都有缺陷,但是它有一个地方的设计是对的:无论何时requestHandler被调用(假设一个HTTP请求传进来),它会立即进行一次异步调用。假设db.getUser是一个异步操作,跟看上去的那样,它只需要很少的一些计算量,然后立即进行下一个异步I/O操作。


一年以前,Ted Dziuba 发表过 NodeJS就是癌症[2011]  ,其中有一个重要的观点是

让我们先从看看一些场景。拿函数调用来说,当执行此函数时当前线程会等到该功能结束,然后再继续下一个操作。通常情况下,我们认为I/O是“阻塞”的,比如你在调用socket.read(),程序会等待该调用完成后继续,因为你需要它的返回值。

这里有一个有趣的现象:每个函数的调用,在CPU里也是阻塞的。比如此功能,它计算的第n个Fibonacci数(斐波那契数列),将被阻塞CPU当前的执行线程。

function fibonacci(n) {
  if (n < 2)
    return 1;
  else
    return fibonacci(n-2) + fibonacci(n-1);
}

他证明了用node.js写斐波那契数列的性能的确很差。这一点没问题,但是我们不需要在服务器端用node.js来进行这种程度的数学运算。但是node.js经常在服务器端进行的CPU密集和阻塞运算,是下面一种情形:

function requestHandler(req, res) {
   var body = req.rawBody; // Contains the POST body
   try {
      var json = JSON.parse(body);
      res.end(json.user.username);
   }
   catch(e) {
      res.end("FAIL");
   }
}


看起来没什么问题,对吧?它接收POST过来的请求,然后解析成JSON字符串,这种方法是有效的,直到有人将一个15mb的JSON文件抛过来。

我在自己的笔记本上测试过。执行JSON.parse()解析一个15Mb的JSON文件大概需要1.5秒。同样,当我使用格式化的解析 JSON.stringify(json, null, 2) 大约需要3秒钟。


你可以会想: 1.5秒,3秒仍然很快,但你意识到这个过程中事件循环是被完全阻塞的吗?这个时侯你的node服务器不能做任何事情。当然1.5Mb看起来确实比较大,但20个200Kb的文件就很合理了。你的服务器同样会挂起。

让我们假设之前1毫秒可以处理一个请求,即1/0.001 = 1000 请求/秒 (假设你不做任何I/O操作),这个看上去不错。现在Event Loop被阻塞之后呢?

  • 5ms/请求 = 最多 200 请求/秒
  • 50ms/请求 = 最多 20 请求/秒
  • 500ms/请求 = 最多 2 请求/秒

当然这个问题在许多其它技术中也会存在,基本原理是一样的,平均每个请求花的时间越长,服务器能处理的并发就越少。


注* 在主流框架中都会限制POST数据的大小,如Express:

Express -> body_parser -> raw-body 中:

有一处限制 limit 默认为 100Kb

function onData(chunk) {
  received += chunk.length
  decoder
    ? buffer += decoder.write(chunk)
    : buffer.push(chunk)

  if (limit !== null && received > limit) {
    var err = makeError('request entity too large', 'entity.too.large')
    //……
  }
}

但在受大量的POST数据攻击时,100Kb也是不够的。

OurJS博客采用限制发贴间隔,并可以起多个相互独立的服务器实例来避免单个服务的阻塞,只需配置redis(存放Session)即可,此功能尚在测试。只因流量尚未达到必须起两个以上服务的程度。

原文地址: 点此
社区评论 ( Beta版 )
OnceDoc 您自己的企业内容管理系统——文档、流程、知识库、报表、网盘All In One

访问404页面,寻找丢失儿童
 热门文章 - 分享最多
  1. 2014年最受欢迎的前十大语言:JavaScript、PHP、Java排前三
  2. 主流JavaScript MVC框架性能比较测试:Angular vs Backbone vs Ember
  3. AngularJS在大型单页面应用中的性能优化(一)
  4. 为什么io.js要从Node.js中分裂出来?
  5. CSS3实现的响应式字体:自适应视图窗口大小的新单位
  6. JavaScript代码组织结构良好的5个特点[reuqire.js]
  7. io.js新图标logo征集中
  8. 在JavaScript的Array数组中调用一组Function方法
  9. AngularJS在大型单页面应用中的性能优化(二)
  10. WebPack:更优秀的模块依赖管理工具,及require.js的缺陷
  11. AirJD-简单好用的免费建站工具

 相关阅读 - 骇客攻防
  1. 避免Node.js中的命令行注入安全漏洞
  2. 提高NodeJS网站的安全性:Web服务器防黑客攻击技巧
  3. 浦发银行,请给我们一个解释!
  4. 你不知道的JavaScript用法,Hacker是这样写JS的
  5. QQ邮箱是如何泄密的:JSON劫持漏洞攻防原理及演练
  6. 为什么谷歌的JSON响应以while(1);开头?
  7. 技术宅黑入扎总Facebook主页 称不得已
  8. 创建高安全性PHP网站的几个实用要点
  9. 谷歌明文存储用户密码 与其交付不如自我保护
  10. 十大关系数据库SQL注入工具一览

 关键字 - JavaScript
  1. 40行JavaScript代码实现的3D旋转魔方动画效果
  2. 使用Javascript将相对路径地址转换为绝对路径
  3. 如何用CSS将select/option文本居中或居右对齐
  4. 给checkbox选择框设置不选中时的值
  5. 用原生HTML5控件实现输入框自动提示(下拉列表补全)功能
  6. JavaScript中怪异的地方
  7. 在JavaScript中创建命名空间的几种写法
  8. JavaScript中的继承,构造函数以及new关键字的作用
  9. 纽约时报使用Html5 WebRTC记录访问者IP地址
  10. 正则中test、exec、match的简单区别,以及括号的用法

 欢迎订阅 - 技术周刊

我们热爱编程, 我们热爱技术; 我们是高端, 大气, 上档次, 有品味, 时刻需要和国际接轨的码农; 欢迎您订阅我们的技术周刊; 您只需要在右上角输入您的邮箱即可; 我们注重您的隐私,您可以随时退订.
加入我们吧! 让我们一起找寻码农的快乐,探索技术, 发现IT人生的乐趣;


 关注我们

我们的微信公众号: ourjs-com
打开微信扫一扫即可关注我们:
IT文摘-程序员(码农)技术周刊

ourjs官方微信号