nodejs的数据上传与安全

  Node提供了相对底层的API,通过它构建各种各样的Web应用都是相对容易的,但在Web应用中,不得不重视数据上传相关的安全问题。由于Node与前端Javascript的近缘性,前端Javascript甚至可以上传至服务器直接执行,但在这里我们并不讨论这样危险的动作,而是介绍内存和CSRF相关的安全问题。

  1. 内存限制

  在解析用户提交的表单、JSON和XML的时候,我们采取的策略是先保存所有数据,然后再解析处理,最后才传递给业务逻辑。这种策略存在潜在的问题是,它仅仅适合数据量小的提交请求, 一旦数据量过大,将发生内存被占光的情况。攻击者通过客户端能够十分容易地模拟伪造大量数 据,如果攻击者每次提交1 MB的内容,那么只要并发请求数量一大,内存就会很快地被吃光。

  要解决这个问题主要有两个方案。

  ? 限制上传内容的大小,一旦超过限制,停止接收数据,并响应400状态码。

  ? 通过流式解析,将数据流导向到磁盘中,Node只保留文件路径等小数据。

  首先介绍一下Connect框架中采用的上传数据量的限制方式,如下所示:  

const bytes = 1024;

(req, res) => {
  let received = 0,
  const len = req.headers[‘content-length‘] ? parseInt(req.headers[‘content-length‘], 10) : null;
  // 如果内容超过长度限制,返回请求实体过长的状态码
  if (len && len > bytes) {
    res.writeHead(413);
    res.end();
    return;
  }
  // limit
  req.on(‘data‘, function (chunk) {
    received += chunk.length
    if (received > bytes) {
      // 停止接收数据,触发end()
      req.destroy();
    }
  })
  handle(req, res)
}

  从上面的代码中我们可以看到,数据是由包含Content-Length的请求报文判断是否长度超过限制的,超过则直接响应413状态码。对于没有Content-Length的请求报文,则更为简略些,在每个data事件中判断即可。一旦超过限制值,服务器停止接收新的数据片段。如果是JSON文件或 XML文件,极有可能无法完成解析。对于上线的Web应用,添加一个上传大小限制十分有利于保 护服务器,在遭遇攻击时,能镇定从容应对。

  2. CSRF

  CSRF的全称是Cross-Site Request Forgery,中文意思为跨站请求伪造。通常而言,服务器端与客户端通过Cookie来标识和认证用户,用户通过浏览器访问服务器端的Session ID 是无法被第三方知道的,但是CSRF的攻击者并不需要知道Session ID就能让用户中招。

  为了详细解释CSRF攻击是怎样一个过程,这里以一个留言的例子来说明。假设某个网站有 这样一个留言程序,提交留言的接口如下所示:  

http://domain_a.com/guestbook 

  用户通过POST提交content字段就能成功留言。服务器端会自动从Session数据中判断是谁提 交的数据,补足username和updatedAt两个字段后向数据库中写入数据,如下所示:  

(req, res) => {
  // req.body.content来自connect框架
  const content = req.body.content || ‘‘;
  // session需自行实现,此处假设上文已实现session
  const username = req.session.username;
  const feedback = {
    username: username,
    content: content,
    updatedAt: Date.now()
  };
  // 此处根据自己使用的数据库类型自行修改
  db.save(feedback, err => {
    res.writeHead(200);
    res.end(‘Ok‘);
  });
}

  正常的情况下,谁提交的留言,就会在列表中显示谁的信息。如果某个攻击者发现了这里的 接口存在CSRF漏洞,那么他就可以在另一个网站(http://domain_b.com/attack)上构造了一个表 单提交,如下所示:  

<form id="test" method="POST" action="http://domain_a.com/guestbook">
  <input type="hidden" name="content" value="vim是这个世界上最好的编辑器" />
</form>
<script type="text/javascript">
  $(function () {
    $("#test").submit();
  });
</script>

  这种情况下,攻击者只要引诱某个domain_a的登录用户访问这个domain_b的网站,就会自动提交一个留言。由于在提交到domain_a的过程中,浏览器会将domain_a的Cookie发送到服务器, 尽管这个请求是来自domain_b的,但是服务器并不知情,用户也不知情。

  以上过程就是一个CSRF攻击的过程。这里的示例仅仅是一个留言的漏洞,如果出现漏洞的 是转账的接口,那么其危害程度可想而知。

  尽管通过Node接收数据提交十分容易,但是安全问题还是不容忽视。好在CSRF并非不可防御,解决CSRF攻击的方案有添加随机值的方式,如下所示:  

const generateRandom = function (len) {
  return crypto.randomBytes(Math.ceil(len * 3 / 4))
    .toString(‘base64‘)
    .slice(0, len)
}

  也就是说,为每个请求的用户,在Session中赋予一个随机值,如下所示:  

const token = req.session._csrf || (req.session._csrf = generateRandom(24)); 

  在做页面渲染的过程中,将这个_csrf值告之前端,如下所示:

<form id="test" method="POST" action="http://domain_a.com/guestbook">
 <input type="hidden" name="content" value="vim是这个世界上最好的编辑器" />
 <input type="hidden" name="_csrf" value="<%=_csrf%>" />
</form> 

  由于该值是一个随机值,攻击者构造出相同的随机值的难度相当大,所以我们只需要在接收端做一次校验就能轻易地识别出该请求是否为伪造的,如下所示:  

(req, res) => {
  const token = req.session._csrf || (req.session._csrf = generateRandom(24));
  const _csrf = req.body._csrf;
  if (token !== _csrf) {
    res.writeHead(403);
    res.end("禁止访问");
  } else {
    handle(req, res);
  }
} 

  _csrf字段也可以存在于查询字符串或者请求头中。

  

  

原文地址:https://www.cnblogs.com/Mr-CCQT/p/11641941.html

时间: 2024-11-09 02:48:53

nodejs的数据上传与安全的相关文章

【AllJoyn专题】基于AllJoyn和Yeelink的传感器数据上传与指令下行的研究

笔者接触高通物联网框架AllJoyn不太久,但确是被深深地吸引了.在我看来,促进我深入学习的原因有三点:一.AllJoyn开源,对开源的软硬件总会有种莫名的喜爱,尽管也许不会都深入下去:二.顺应潮流,物联网虽远未普及,但已是大势所趋,高通公司在领域布局,致力于打造舒适高效的智能家居场景,推出AllJoyn软件框架,适应了发展趋势:三.文档丰富,开源软件的使用,特别是框架,若没有文档相助,相信没有多少开发者愿意尝试,AllJoyn在这方面做得不错,日后还需做得更好.当然啦,也有些额外原因,包括高通

C#工业物联网和集成系统解决方案的技术路线(数据源、数据采集、数据上传与接收、ActiveMQ、Mongodb、WebApi、手机App)

目       录 工业物联网和集成系统解决方案的技术路线... 1 前言... 1 第一章           系统架构... 3 1.1           硬件构架图... 3 1.2           组件构架图... 4 第二章           技术选型与介绍... 5 2.1           开发环境... 5 2.2           数据源... 5 2.3           数据采集... 5 2.4           数据上传服务... 6 2.5      

Chromium硬件加速渲染的GPU数据上传机制分析

在Chromium中,WebGL端.Render端和Browser端通过命令缓冲区将GPU命令发送给GPU进程执行.GPU命令携带的简单参数也通过命令缓冲区发送给GPU进程,但是复杂参数,例如纹理数据,有可能太大以致命令缓冲区无法容纳,因此需要通过其它机制传递给GPU进程.本文接下来就主要以纹理数据上传为例,分析WebGL端.Render端和Browser端将GPU命令数据传递给GPU进程的机制. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! WebGL

一个简单实际的Windows服务:实现本地数据上传到服务器

功能:实现本地数据上传到远程服务器 操作实现: 1.发送本地ID到远程服务器进行身份验证,验证成功则可Get到本地需要发送的数据的ID,例如: 本地发送身份ID:key123,验证成功,则远程服务器匹配到该ID所包含的数据条目,例如传回7个ExdID. 2.收到7个ExdID后,本地需要传输数据库中许多数据中的这7个ExdID所对应的数据到远程服务器,远程服务器将收到的数据保存.更新到远程数据库中. 注意问题: 1.为保证带宽负载轻松,不能频繁往远程服务器传输数据. 2.考虑到断网情况,断网之间

C#数据上传方法

/// <summary> /// 连接成功后开始调用数据上传程序 /// </summary> public void CallDataUpload() { //指定上传日期后,只上传指定日期的数据 //取指定的上传日期 string defineScrq = GetDefineScrq(); if (defineScrq != "") { scrq = Convert.ToDateTime(defineScrq); CreateUploadFile(); r

ios开发 将json格式数据上传服务器

看了一些大小牛的资料其实就3步 1.使用post 请求 ,因为get是不能上传的 2.设置请求类型 , 讲你的json数据上传 3.向服务器发送数据按照下面示例代码,就差不多了 1 // 1.创建请求 2 NSURL *url = [NSURL URLWithString:@"http://192.168.1.200:8080/MJServer/order"]; 3 NSMutableURLRequest *request = [NSMutableURLRequest requestW

重新想象 Windows 8.1 Store Apps (89) - 通信的新特性: 下载数据, 上传数据, 上传文件

原文:重新想象 Windows 8.1 Store Apps (89) - 通信的新特性: 下载数据, 上传数据, 上传文件 [源码下载] 作者:webabcd 介绍重新想象 Windows 8.1 Store Apps 之通信的新特性 下载数据(显示下载进度,将下载数据保存到本地) 上传数据(显示上传进度) 上传文件 示例HTTP 服务端WebServer/HttpDemo.aspx.cs /* * 用于响应 http 请求 */ using System; using System.IO;

7-28 数据上传上线bug

由于是之前的项目,在看到无效的序列的时候,第一反应是之前没有碰到无效的 序列,思路停留在客户端的代码上,按照经理给的思路 我逐渐把问题排除到服务端出现了问题,在今天早上,测了一遍没有出现什么无效的序列,但小问题还是有,各种奇葩问题.昨天真的把我给搞死了,死活想不到什么问题.还有就是client_log_id在上线的项目上没有 加上的是客户端的id而是一个序列值.还需要升级版本的时候,给测试新的修改完毕的项目. 7-28 数据上传上线bug

云上树莓派(2):将传感器数据上传到 AWS IoT 并利用Kibana进行展示

云上树莓派(1):环境准备 云上树莓派(2):将传感器数据上传到AWS IoT 并利用Kibana进行展示 1. 传感器安装及配置 1.1 DHT22 安装 DHT22 是一款温度与湿度传感器,它有3个针脚,左边的第一个引脚(#1)为3-5V电源,第二个引脚(#2)连接到数据输入引脚,最右边的引脚(#4)接地. 而树莓派3B 一共有40个针脚(GPIO,General Purpose I/O Ports,通用输入/输出端口),只需要将传感器的3个引脚接入板子上的合适引脚即可.我的连接是 1 -