网络埋伏纪事

Node Hero - 11. Node.js 安全教程

网络埋伏纪事 · 2016-11-22翻译 · 446阅读 原文链接

本教程将学习如何让应用程序防御常用的攻击途径。

Node.js 安全威胁

当今我们几乎每周都可以看到一些严重的安全漏洞,比如 LinkedInMySpace 的案例。在这些攻击期间,大量的用户数据被泄露 - 企业声誉也受损。

研究还表明,在某些行业,平均 18 个月就有安全门被公开。

我们必须解决这种看法。如果你开发软件,那么安全性就是你工作的一部分

开始 Node.js 安全教程

下面我们开始,通过恰当的编码,工具使用,以及操作,保护你的 Node.js 应用程序!

安全的编码风格

规则 1: 不要用 eval

Eval 可以为代码注入式攻击打开你的应用程序。尽量不要用它,但是如果你必须用它,不要把未经校验的用户输入注入到 eval

Eval 不是应该避免的唯一一个 - 在幕后,如下表达式的每一个都会用 eval:

  • setInterval(String, 2)
  • setTimeout(String, 2)
  • new Function(String)

规则 2: 总是用严格模式

使用 'use strict',可以确保使用受限制的 JavaScript "变体"。它可以消除一些莫名其妙的错误,并且总是会抛出这些错误。

'use strict'  
delete Object.prototype  
// TypeError
var obj = {  
    a: 1, 
    a: 2 
} 
// syntax error

规则 3: 仔细处理错误

在不同的错误场景下,应用程序会泄露关于下层基础架构的一些敏感细节,比如:X-Powered-By:Express

栈跟踪本身是不会被当作易受攻击的,但是它们经常会暴露一些攻击者会感兴趣的信息。将调试信息提供为产生错误的操作的结果,被认为是糟糕的实践。应该将其写在日志中,而不是将其展示给用户看。

规则 4: 对代码库做静态分析

应用程序代码库的静态分析可以捕获很多错误。为此,我们建议使用 ESLint 建议的标准代码风格

安全地在产品环境中运行服务

使用恰当的代码风格对于有效保护 Node.js 应用程序是不够的 - 还应该注意如何在产品环境中运行你的服务。

规则 5: 不要用超级用户权限运行进程

可悲的是,我们看到很多:开发者用超级用户权限运行他们的 Node.js 应用程序,因为他们想让它监听 80 或者 443 端口。

这完全是错的。 在有错误或者 bug 的情况下,你的进程会拖垮整个系统,因为它是有资格做任何事情的。

你应该做的是,设置一个 HTTP 服务器或者代理来转发请求。可以是 nginx 或 Apache。要学到更多知识,请看看我们的文章在产品环境中操作 Node.js

规则 6: 设置强制的 HTTP 头

有些与安全相关的 HTTP 头是网站应该设置的,这些头是:

  • Strict-Transport-Security 强制使用 HTTPS 连接到服务器
  • X-Frame-Options 提供 点击劫持(clickjacking) 保护
  • X-XSS-Protection 启用最新浏览器内置的跨站脚本(XSS)筛选器
  • X-Content-Type-Options 防止浏览器用 MIME-sniffing 确定响应的类型从而偏离声明了的 content-type
  • Content-Security-Policy 防止许多各种不同的攻击,包括跨站脚本攻击以及其它跨站注入攻击

在 Node.js 中用 Helmet 模块,很容易设置这些 HTTP 头:

var express = require('express')  
var helmet = require('helmet')

var app = express()

app.use(helmet())

Helmet 也可以用于 Koa koa-helmet

规则 7: 正确管理会话

应该在每个 cookies 中设置如下的标志列表:

  • secure - 该属性告诉浏览器只在请求通过 HTTPS 发送时才发送 cookie。
  • HttpOnly - 该属性用于帮助阻止诸如跨站脚本这类攻击,因为它不允许用 JavaScript 访问 Cookie。
  • domain - 该属性用于将服务器域名与被请求的URL 对比。如果域名匹配,或者是一个子域名,那么就接着检查 path 属性。
  • path - 除了域名以外,也可以指定 URL 路径判断 cookie 是否有效。如果域名和路径都匹配,那么 cookies 就会在请求中发送。
  • expires - 该属性用于设置持久的 cookie,因为 cookie 在设置了的日期超过之前是不会到期的。

在 Node.js 中,用 cookies 包可以很容易创建这个 cookie。这个包的 API 也是相当低层的,所以你可能会最终会用一个封装好的,比如 cookie-session

var cookieSession = require('cookie-session')  
var express = require('express')

var app = express()

app.use(cookieSession({  
  name: 'session',
  keys: [
    process.env.COOKIE_KEY1,
    process.env.COOKIE_KEY2
  ]
}))

app.use(function (req, res, next) {  
  var n = req.session.views || 0
  req.session.views = n++
  res.end(n + ' views')
})

app.listen(3000)

(本示例来自 cookie-session 模块文档。)

要使用的工具

恭喜,你已经快到了!如果你跟着本教程,把前面的步骤全都做一遍,那么就只剩下最后一个与 Node.js 安全相关的区域没有覆盖了。下面我们研究使用恰当的工具来查找模块的漏洞。

规则 9: 用 Retire.js 查找漏洞

Retire.js 的目标是帮助用已知的漏洞检测模块版本的使用。

只需要安装:

npm install -g retire

之后,用 retire 命令运行它,就会在你的 node_modules 目录中查找漏洞。(也请注意,retire.js 不仅可以用于 node 模块,而且也可以用于前端库。)

规则 10: 用 Node 安全平台 CLI 审核模块

nsp 是 Node 安全平台的主要命令行接口。它允许审核 package.json 或者 npm-shrinkwrap.json 文件,从而让 NSP API 检查易受攻击的模块。

npm install nsp --global  
# From inside your project directory
nsp check

下一步

Node.js 安全问题毕竟不是什么大不了的事情吗?我希望你发现这些规则对保护你的 Node.js 应用程序安全有帮助,并且在将来会遵循这些规则,因为安全是你工作的一部分!

如果想阅读更多有关 Node.js 安全的文章,推荐从这些文章开始:

下章将学习如何部署安全的 Node.js 应用程序,这样大家就可以实际开始用它!