神刀安全网

构建 Express Api 五个有用的中间件[译]

最近在学习 Node+Express ,由于个人水平有限以及令人捉急的英文,无法完美的呈现出作者的意思,也少不了错误,还请各位童鞋多多指正。本文纯粹是给自己在学习 Node + Express 的路上做一个记录。并没有多少技术含量,对 Express 开发很熟悉的人可以绕道。

如果你正使用 Node.jsExpress 构建 Api ,这篇文章将告诉你提高 RESRTFul Api 安全和性能的一些诀窍和技巧。

在这篇文章中,我们将创建一个简单的只有一个端口的 Express Api 的示例。现在开始构建我们的项目吧。

  • 在终端输入以下的命令
$ mkdir my-api $ cd my-api $ npm init 

npm init 对我们的项目可以快速设置一些简短的描述,主入口文件和我们将要安装的一些模块,并生成一个 package.json 文件。用你自己的方式随时回复每个问题。

  • 现在运行下面的命令来安装 Express 框架。
$ npm install express --save 

到此 Express 框架已经安装成功。开始我们的一个小而简单的 API 代码并开始创建 index.js 文件。

var express = require('express');   var app = express();  app.get('/', function(req, res) {     res.json({status: 'My Api is alive!'}); });  app.listen(3000, function() {     console.log('My Api is running...'); });  module.exports = app;   

启动服务器,测试是否正常

$ node index.js 

在浏览器地址栏内输入 localhost:3000

再下一节中,我们将要通过一个小的功能来探讨一些有用的可以提高应用程序的中间件。

CORS 简介

为防止你不了解, CORS 全称: Cross-origin resource sharing 跨域资源共享 ,是一种重要的 HTTP 机制。它负责准许跨域或同步请求。

在实际项目中,服务器端 CORS 只包含在 HTTP's 的头部。这些头文件可以告知哪个域可以请求API,哪些http方法是被允许的。最主要的是哪些终端可以跨域共享公共的应用程序。

Api 内启用 CROS

在我们正在开发的 API 中,需要启用 CORS 的中间件使之成为公共的端口,可用于任何客户端共享数据。这意味着某些客户端可以访问我们的 Api

  • 需要安装 cors 模块来启用它
$ npm install cors --save    
  • 然后,在 index.js 内添加中间件 app.use(cors())
var express = require('express');   var cors = require('cors');   var app = express();  app.use(cors());  app.get('/', function(req, res) {     res.json({status: 'My Api is alive!'}); });  app.listen(3000, function() {     console.log('My Api is running...'); });  module.exports = app;   

只有使用 cors() 中间件才会释放出我们 Api 的访问权限。最好是控制哪些客户端可以进行连接,哪些方法可以使用。最主要的是,必须要在请求的时候加入到头部。在我们这个例子中仅需要设置三个属性: orgin(访问域)、method(访问方法)、alloweHeaders(请求头)。

因此,向 app.use(cors()) 添加一些参数。

var express = require('express');   var cors = require('cors');   var app = express();  app.use(cors({     origin: ['http://localhost:3001'],   methods: ['GET', 'POST'],   alloweHeaders: ['Conten-Type', 'Authorization'] }));  app.get('/', function(req, res) {     res.json({status: 'My Api is alive!'}); });  app.listen(3000, function() {     console.log('My Api is running...'); });  module.exports = app;   

现在我们可以在流览器中访问 localhost:3001 ,该客户端应用程序只能通过头为: Content-TypeAuthorization 进行 GETPOST 请求。

详细了解一下 CORS

学习 CORS 的目的是为了了解它的请求头,更重要的是学会如何自定义 API 规则 ,建议你完整读完这篇文章: developer.mozilla.org/en-US/docs/Web/HTTP/Access control CORS

生成日志

在本节中,设置我们的应用程序报告并把用户的请求生成日志文件。要做到这一点,需要使用 服务器生成请求日志的中间件- morgan 模块。

  • 运行如下命令
$ npm install --save morgan 

然后,在上面引用 app.use(morgan('common')) 以记录所有的请求。

var express = require('express');   var cors = require('cors');   var morgan = require('morgan');   var app = express();  app.use(morgan('common'));   app.use(cors({     origin: ['http://localhost:3001'],   methods: ['GET', 'POST'],   alloweHeaders: ['Conten-Type', 'Authorization'] }));  app.get('/', function(req, res) {     res.json({status: 'My Api is alive!'}); });  app.listen(3000, function() {     console.log('3000  My Api is running...'); });  app.listen(3001, function() {     console.log('3001  My Api is running...'); });  module.exports = app;   

重启服务器,多次访问 localhost:3000 , 验证是否生成日志。

  • 多次请求之后,在终端上面你会看到类似下面的结果。

构建 Express Api 五个有用的中间件[译]

使用 cluster 模块配置并行处理

大家都知道 Node.js 是一个单线程的运行的。很多开发者不认同这一点,把它当回事,进而影响了他们的学习兴趣。然而,尽管他是单线程的,但通过一些准备还是可以做到并行运行的。可以通过内置的 cluster 模块做到这一点。

它基本上在分布式方面是一个新的初始化应用并且该模块可以在活动集群间共享同一个网络端口。它可以决定创建的进程数量。但一个更好的做法是实例化基于多个服务器的处理器或者相当数量的多核处理器。

例如:如果我有一个八核单处理器,就可以实例化创建八个集群网络的八个进程;但是,如果我有四个八核处理器,就可以创建32个活动集群网络。

若要确保集群可以分布式和有组织的工作,父进程是必须存在的(也称之为集群主机)。 因为它是负责平衡其他集群之间的并行处理,将负载分发到其他进程叫做子进程(或者 cluster slave )。作为一个开发者在nodejs上抽象的分配执行这种技术,是非常容易的。

另一个优点是 cluster 是独立的。也就是说,即使一个 cluster 出现故障,其他将会继续工作。然而,有必要管理实例和手动关闭集群确保集群可以回归。

根据这些概念,我们将在实践中采用 cluster

在根目录下创建 clusters.js 文件,代码如下:

var cluster = require('cluster');   var os = require('os');  const CPUS = os.cpus();  if (cluster.isMaster) {     CPUS.forEach(function () {     cluster.fork();   });   cluster.on('listening', function(worker) {     console.log('Cluster %d connected', worker.process.pid);   });    cluster.on('disconnect', function(worker) {     console.log('Cluster %d disconnected', worker.process.pid);   });    cluster.on('exit', function(worker) {     console.log('Cluster %d dead', worker.process.pid);     // Ensuring a new cluster will start if an old one dies     cluster.fork();   }); } else {   require("./index.js"); } 
  • 这次,运行如下命令启动服务器
$  node clusters.js 

执行此命令后,运行应用程序分配到集群,在终端上你会看到不止一次的出现 My Api is running... 这条消息,就像如下图所示:

构建 Express Api 五个有用的中间件[译]

基本上我们都需要加载 cluster 模块,并通过 cluster.isMaster 来验证当前进程是不是主进程。一旦确定是主进程通过 CPUS.forEach(function() { cluster.fork() }) 函数循环所有的内核处理器forking一个新的子进程。

if(cluster.isMaster) 条件的时候并不适合(在这种情况下子进程)创建一个新的进程。所以,通过 require("./index.js") 为子进程启动应用服务器。

另外,通过主进程创建了一些事件也都包括在内。在代码的最后一个列子,我们只用下面列出的主要事件:

listening:进程发生时监听的端口,当前情况下,哦们的应用程序正在监听3000端口

disconnect: 一个进程从进程网络中断开时发生

exit: 一个进程在操作系统关闭时发生

clusters的发展

很多事情都可以进行探讨关于Node.js 的集群发展。在这里我们只采用一点足以运行并行处理。万一你要执行更加详细的clusters,建议您要阅读文档: nodejs.org/api/cluster.html

使用 GZIP 中间件合并请求

为了使请求更轻,加载速度更快。我们可以用采用另外一个中间件负责压缩响应的json数据和静态文件为GZIP格式,可以设置一些浏览器的兼容性。我们做的简单但却很重要的是模块压缩。

  • 安装依赖
$ npm install --save compression 
  • 然后将该中间件引入到 index.js 文件内。
var express = require('express');   var cors = require('cors');   var morgan = require('morgan');   var compression = require('compression');   var app = express();  app.use(morgan('common'));   app.use(cors({     origin: ['http://localhost:3001'],   methods: ['GET', 'POST'],   alloweHeaders: ['Conten-Type', 'Authorization'] })); app.use(compression());   app.get('/', function(req, res) {     res.json({status: 'My Api is alive!'}); });  app.listen(3000, function() {     console.log('My Api is running...'); });  module.exports = app;   

安装 SSL 支持使用 HTTPS

现如今,创建服务器和客户端之间的安全连接的安全应用程序。要做到这一点,许多应用程序购买和使用的安全证书,以确保SSL(安全套接层)通过HTTPS协议连接。

为了实现 HTTPS 协议链接,必须要购买一个生产环境使用的数字证书。假设你已经有一个了,在项目根目录下创建两个文件(文件扩展名一个为 .key ,一个为 .cert )。然后,我们启用 https 模块来实现 HTTPS 服务器,通过 fs 模块 来打开和读取证书文件 my-api.keymy-api.cert 作为凭证参数来启动我们服务器的 HTTPS 模式。我们可以把 app.listen() 函数改为 https.createServer(credentials, app).listen() 函数来实现这一功能。

  • 就拿下面的 API 代码看看
var express = require('express');   var cors = require('cors');   var morgan = require('morgan');   var compression = require('compression');   var fs = require('fs');   var https = require('https');   var app = express();  app.use(morgan('common'));   app.use(cors({     origin: ['http://localhost:3001'],   methods: ['GET', 'POST'],   alloweHeaders: ['Conten-Type', 'Authorization'] })); app.use(compression());  app.get('/', function(req, res) {     res.json({status: 'My Api is alive!'}); });  var credentials = {     key: fs.readFileSync('my-api.key', 'utf8'),   cert: fs.readFileSync('my-api.cert', 'utf8') };  https.createServer(credentials, app)        .listen(3000, function() {       console.log('My Api is running...');      });  module.exports = app;   

恭喜!现在您的应用程序在一个安全的协议下运行,不用再担心数据被拦截了。请注意,实际项目中需要一个有效的数字证书来实现这种需求。所以不要忘了买一个在生产环境内你的重要API。

如何生成签名证书

# 生成 my-api.key $ openssl genrsa -des3 -out my-api.key 1024 # 生成签名请求的csr 文件 $ openssl req -new -key my-api.key -out my-api.csr # 对自己证书进行签名,签名有效期是365天 $ openssl x509 -req -days 365 -in my-api.csr -signkey my-api.key -out my-api.cert # 去除签名文件的password $ cp my-api.key my-api.key.orig $ openssl rsa -in my-api.key.orig -out my-api.key 
  • 测试这种变化,只需要重启服务器,然后访问: https://localhost:3000

API 头部武装起来

纵观我们的API开发,有一个非常重要的模块就是处理攻击 HTTP/HTTPS 协议的安全中间件。此模块称之为安全帽一共有九个内部组件,负责下列http 设置:

  • 设置 Content Security Policy 防止XSS 攻击
  • 可以移除 X-Powered-By 头部
  • 配置http 公共秘钥规则
  • 配置http 严格安全输出规则
  • 设置IE8+的 X-Download-Options
  • 禁用客户端缓存
  • 避免客户端进行MIME类型进行嗅探
  • 阻止点击劫持攻击
  • 防止XXS (跨站脚本)攻击

综上所述,即使你对 http 安全性不适很明白,你可以使用 helmet 模块,它会增加一个简单的界面让你的web应用程序应对多种类型的攻击。

安装 helmet 依赖

$ npm install --save helmet 

我们很容易的通过 app.use(helmet()) 引入 helmet 模块所提供的中间件, 最大程度的确保我们 API 的安全性。

var express = require('express');   var cors = require('cors');   var morgan = require('morgan');   var compression = require('compression');   var fs = require('fs');   var https = require('https');   var helmet = require('helmet');   var app = express();  app.use(morgan('common'));   app.use(helmet());   app.use(cors({     origin: ['http://localhost:3001'],   methods: ['GET', 'POST'],   alloweHeaders: ['Conten-Type', 'Authorization'] })); app.use(compression());  app.get('/', function(req, res) {     res.json({status: 'My Api is alive!'}); });  var credentials = {     key: fs.readFileSync('my-api.key', 'utf8'),   cert: fs.readFileSync('my-api.cert', 'utf8') };  https.createServer(credentials, app)        .listen(3000, function() {       console.log('My Api is running...');      });  module.exports = app;   

打开浏览器控制台,并在 Networks 菜单中,您可以详细的查看GET/ 请求的数据。你会看到头部有新的名目。类似下面这样图像上的:

构建 Express Api 五个有用的中间件[译]

结论

所有的数据通过 cluster 并行处理、通过 GZIP 压缩优化数据传输。通过 CORS 启用受限制的web客户端、所有的请求都会通过 morgan 模块记录到日志文件。现在你的 API 通过这些最佳的安全做法,让你免受一些常见的攻击。

随时在你新的 Express 项目中引用这些小的 API

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 构建 Express Api 五个有用的中间件[译]

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址