Node.js 安全清单

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介:

前言

安全性,总是一个不可忽视的问题。许多人都承认这点,但是却很少有人真的认真地对待它。所以我们列出了这个清单,让你在将你的应用部署到生产环境来给千万用户使用之前,做一个安全检查。

以下列出的安全项,大多都具有普适性,适用于除了Node.js外的各种语言和框架。但是,其中也包含一些用Node.js写的小工具。

配置管理

安全性相关的HTTP头

以下是一些安全性相关的HTTP头,你的站点应该设置它们:

  • Strict-Transport-Security:强制使用安全连接(SSL/TLS之上的HTTPS)来连接到服务器。

  • X-Frame-Options:提供对于“点击劫持”的保护。

  • X-XSS-Protection:开启大多现代浏览器内建的对于跨站脚本攻击(XSS)的过滤功能。

  • X-Content-Type-Options: 防止浏览器使用MIME-sniffing来确定响应的类型,转而使用明确的content-type来确定。

  • Content-Security-Policy:防止受到跨站脚本攻击以及其他跨站注入攻击。

Node.js中,这些都可以通过使用Helmet模块轻松设置完毕:


 
 
  1. var express = require('express');
  2. var helmet = require('helmet');
  3. var app = express();
  4. app.use(helmet());

Helmet在Koa中也能使用:koa-helmet

当然,在许多的架构中,这些头会在Web服务器(Apache,nginx)的配置中设置,而不是在应用的代码中。如果是通过nginx配置,配置文件会类似于如下例子:


 
 
  1. # nginx.conf
  2. add_header X-Frame-Options SAMEORIGIN;
  3. add_header X-Content-Type-Options nosniff;
  4. add_header X-XSS-Protection "1; mode=block";
  5. add_header Content-Security-Policy "default-src 'self'";

完整的例子可以参考这个nginx配置

如果你想快速确认你的网站是否都设置这些HTTP头,你可以通过这个网站在线检查:http://cyh.herokuapp.com/cyh 。

客户端的敏感数据

当部署前端应用时,确保不要在代码中暴露如密钥这样的敏感数据,这将可以被所有人看到。

现今并没有什么自动化检测它们的办法,但是还是有一些手段可以用来减少不小心将敏感数据暴露在客户端的概率:

  • 使用pull request更新代码

  • 建立起code review机制

身份认证

对于暴力破解的保护

暴力破解即系统地列举所有可能的结果,并逐一尝试,来找到正确答案。在web应用中,用户登陆就特别适合它发挥。

你可以通过限制用户的连接频率来防止这类的攻击。在Node.js中,你可以使用ratelimiter包。


 
 
  1. var email = req.body.email;
  2. var limit = new Limiter({ id: email, db: db });
  3. limit.get(function(err, limit) {
  4. });

当然,你可以将它封装成一个中间件以供你的应用使用。ExpressKoa都已经有现成的不错的中间件:


 
 
  1. var ratelimit = require('koa-ratelimit');
  2. var redis = require('redis');
  3. var koa = require('koa');
  4. var app = koa();
  5. var emailBasedRatelimit = ratelimit({
  6. db: redis.createClient(),
  7. duration: 60000,
  8. max: 10,
  9. id: function (context) {
  10. return context.body.email;
  11. }
  12. });
  13. var ipBasedRatelimit = ratelimit({
  14. db: redis.createClient(),
  15. duration: 60000,
  16. max: 10,
  17. id: function (context) {
  18. return context.ip;
  19. }
  20. });
  21. app.post('/login', ipBasedRatelimit, emailBasedRatelimit, handleLogin);

这里我们所做的,就是限制了在一段给定时间内,用户可以尝试登陆的次数 -- 这减少用户密码被暴力破解的风险。以上例子中的选项都是可以根据你的实际情景所改变的,所以不要简单的复制粘贴它们。。

如果你想要测试你的服务在这些场景下的表现,你可以使用hydra

Session管理

对于cookie的安全使用,其重要性是不言而喻的。特别是对于动态的web应用,在如HTTP这样的无状态协议的之上,它们需要使用cookie来维持状态。

Cookie标示

以下是一个每个cookie可以设置的属性的列表,以及它们的含义:

  • secure - 这个属性告诉浏览器,仅在请求是通过HTTPS传输时,才传递cookie。

  • HttpOnly - 设置这个属性将禁止javascript脚本获取到这个cookie,这可以用来帮助防止跨站脚本攻击。

Cookie域

  • domain - 这个属性用来比较请求URL中服务端的域名。如果域名匹配成功,或这是其子域名,则继续检查path属性。

  • path - 除了域名,cookie可用的URL路径也可以被指定。当域名和路径都匹配时,cookie才会随请求发送。

  • expires - 这个属性用来设置持久化的cookie,当设置了它之后,cookie在指定的时间到达之前都不会过期。

Node.js中,你可以使用cookies包来轻松创建cookie。但是,它是较底层的。在创建应用时,你可能更像使用它的一些封装,如cookie-session 。


 
 
  1. var cookieSession = require('cookie-session');
  2. var express = require('express');
  3. var app = express();
  4. app.use(cookieSession({
  5. name: 'session',
  6. keys: [
  7. process.env.COOKIE_KEY1,
  8. process.env.COOKIE_KEY2
  9. ]
  10. }));
  11. app.use(function (req, res, next) {
  12. var n = req.session.views || 0;
  13. req.session.views = n++;
  14. res.end(n + ' views');
  15. });
  16. app.listen(3000);

(以上例子取自cookie-session模块的文档)

CSRF

跨站请求伪造(CSRF)是一种迫使用户在他们已登录的web应用中,执行一个并非他们原意的操作的攻击手段。这种攻击常常用于那些会改变用户的状态的请求,通常它们并不窃取数据,因为攻击者并不能看到响应的内容。

Node.js中,你可以使用csrf模块来缓和这种攻击。它同样是非常底层的,你可能更喜欢使用如csurf这样的Express中间件。

在路由层,可以会有如下代码:


 
 
  1. var cookieParser = require('cookie-parser');
  2. var csrf = require('csurf');
  3. var bodyParser = require('body-parser');
  4. var express = require('express');
  5. // setup route middlewares
  6. var csrfProtection = csrf({ cookie: true });
  7. var parseForm = bodyParser.urlencoded({ extended: false });
  8. // create express app
  9. var app = express();
  10. // we need this because "cookie" is true in csrfProtection
  11. app.use(cookieParser());
  12. app.get('/form', csrfProtection, function(req, res) {
  13. // pass the csrfToken to the view
  14. res.render('send', { csrfToken: req.csrfToken() });
  15. });
  16. app.post('/process', parseForm, csrfProtection, function(req, res) {
  17. res.send('data is being processed');
  18. });

在展示层,你需要使用CSRF token


 
 
  1. <form action="/process" method="POST">
  2. <input type="hidden" name="_csrf" value="{{csrfToken}}">
  3. Favorite color: <input type="text" name="favoriteColor">
  4. <button type="submit">Submit</button>
  5. </form>

(以上例子取自csurf模块的文档)

数据合法性

XSS

以下是两种类似的,但是略有不同的攻击方式,一种关于跨站脚本,而另一种则关于存储。

  • 非持久化的XSS攻击 在攻击者向指定的URL的响应HTML中注入可执行的JavaScript代码时发生。

  • 持久化的XSS攻击 在应用存储未经过滤的用户输入时发生。用户输入的代码会在你的应用环境下执行。

为了防御这类攻击,请确保你总是检查并过滤了用户的输入内容。

SQL注入

在用户的输入中包含部分或完整的SQL查询语句时,SQL注入就有可能发生。它可能会读取敏感数据,或是直接删除数据。

例如:


 
 
  1. select title, author from books where id=$id

以上这个例子中,$id来自于用户输入。用户输入2 or 1=1也可以。这个查询可能会变成:


 
 
  1. select title, author from books where id=2 or 1=1

最简单的预防方法则是使用参数化查询(parameterized queries)或预处理语句(prepared statements)。

如果你正在通过Node.js使用PostgreSQL。那么你可以使用node-postgres模块,来创建参数化查询:


 
 
  1. var q = 'SELECT name FROM books WHERE id = $1';
  2. client.query(q, ['3'], function(err, result) {});

命令注入

攻击者使用命令注入来在远程web服务器中运行系统命令。通过命令注入,攻击者甚至可以取得系统的密码。

实践中,如果你有一个URL:


 
 
  1. https://example.com/downloads?file=user1.txt

它可以变成:


 
 
  1. https://example.com/downloads?file=%3Bcat%20/etc/passwd

在这个例子中,%3B会变成一个分号。所以将会运行多条系统命令。

为了预防这类攻击,请确保总是检查过滤了用户的输入内容。

我们也可以以Node.js的角度来说:


 
 
  1. child_process.exec('ls', function (err, data) {
  2. console.log(data);
  3. });

child_process.exec的底层,它调用了/bin/sh,所以它是一个bash解释器,而不仅仅是只能执行用户程序。

当用户的输入是一个反引号或$()时,将它们传入这个方法就很危险了。

可以通过使用child_process.execFile来解决上面这个问题。

安全传输

SSL版本,算法,键长度

由于HTTP是明文传输的,所以我们需要通过一个SSL/TLS通道来加密,即HTTPS。如今高级别的加密方式已被普遍使用,但是,如果在服务端缺乏配置,也可能会导致服务端使用低级别的加密,或不加密。

你需要测试:

  • 密码,密钥和重协商(renegotiation)都已经合法妥善得配置完毕。

  • 证书的合法性。

使用如nmapsslyze这样的工具可以使这项工作非常简单。

检查证书信息


 
 
  1. nmap --script ssl-cert,ssl-enum-ciphers -p 443,465,993,995 www.example.com

使用sslyze来检查SSL/TSL:


 
 
  1. ./sslyze.py --regular example.com:443

HSTS

在上文的配置管理章节我们已经对其有了接触 - Strict-Transport-Security头会强制使用HTTPS来连接服务器。以下是一个Twitter的例子:


 
 
  1. strict-transport-security:max-age=631138519

这里的max-age定义了浏览器需要自动将所有HTTP请求转换成HTTPS的秒数。

对于它的测试是非常简单的:


 
 
  1. curl -s -D- https://twitter.com/ | grep -i Strict

拒绝服务

账号锁定

账号锁定用于缓和暴力破解带来的拒绝服务方面的影响。实践中,它意味着,当用户尝试了几次登陆并失败后,将在其后的一段内,禁止他的登陆操作。

可以使用之前提到的rate-limiter来阻止这类攻击。

正则表达式

这类攻击主要是由于一些正则表达式,在极端情况下,会变得性能及其糟糕。这些正则被称为恶魔正则(Evil Regexes):

  • 对于重复文本进行分组

  • 在重复的分组内又有重复内容

    ([a-zA-Z]+)*, (a+)+ 或 (a|a?)+在如aaaaaaaaaaaaaaaaaaaaaaaa! 这样的输入面前,都是脆弱的。这会引起大量的计算。更多详情可以参考ReDos

可以使用Node.js工具safe-regex这检测你的正则:


 
 
  1. $ node safe.js '(beep|boop)*'
  2. true
  3. $ node safe.js '(a+){10}'
  4. false

错误处理

错误码,堆栈信息

一些错误场景可能会导致应用泄露底层的应用架构信息,如:like: X-Powered-By:Express

堆栈信息可能自己本身并没有什么用,但它经常能泄露一些攻击者非常感兴趣的信息。将堆栈信息返回出来是非常不好的实践。你需要将它们记录在日志中,而不是展示给用户。

NPM

更强的能力意味着更大的责任 - NPM有这许多可以现成使用的包,但是代价是:你需要检查这些包本身是否存在安全问题。

幸运的是Node Security project(nsp)是一个非常棒的工具,来检查你使用的模块是否是易被一些已知的手段攻击的。


 
 
  1. npm i nsp -g
  2. # either audit the shrinkwrap
  3. nsp audit-shrinkwrap
  4. # or the package.json
  5. nsp audit-package

最后

这个清单主要根据OWASP维护的Web Application Security Testing Cheat Sheet所列。

本文来自云栖社区合作伙伴“Linux中国”,原文发布日期:2015-10-19   

目录
相关文章
|
6月前
|
存储 安全 JavaScript
JavaScript 中整数的安全范围
JavaScript 中整数的安全范围
44 3
|
13天前
|
JavaScript 安全 前端开发
探索Deno 1.x:安全JavaScript/TypeScript运行时的新篇章
【10月更文挑战第21天】Deno 1.x 是由Node.js创始人Ryan Dahl发起的项目,旨在解决Node.js的安全和模块化问题。Deno 1.x 版本带来了统一的运行时、默认安全、ES模块支持和内置TypeScript支持等新特性。其安全模型基于最小权限原则、沙箱环境和严格的远程代码执行控制,适用于Web服务器、命令行工具、桌面和移动应用及微服务开发。本文探讨了Deno 1.x的核心特性、安全模型及其在现代Web开发中的应用。
|
19天前
|
JavaScript 安全 前端开发
掌握Deno:新一代安全的JavaScript和TypeScript运行时
【10月更文挑战第15天】Deno是由Node.js创始人Ryan Dahl发起的新一代JavaScript和TypeScript运行时,旨在解决Node.js的设计问题,提供更安全、现代的开发体验。本文介绍Deno的核心特性、优势及使用方法,包括安全性、统一的运行时、现代Web标准和内置工具等,帮助开发者快速上手Deno,适用于Web开发、工具开发和教育等领域。
|
3月前
|
Java 开发者 关系型数据库
JSF与AWS的神秘之旅:如何在云端部署JSF应用,让你的Web应用如虎添翼?
【8月更文挑战第31天】在云计算蓬勃发展的今天,AWS已成为企业级应用的首选平台。本文探讨了在AWS上部署JSF(JavaServer Faces)应用的方法,这是一种广泛使用的Java Web框架。通过了解并利用AWS的基础设施与服务,如EC2、RDS 和 S3,开发者能够高效地部署和管理JSF应用。文章还提供了具体的部署步骤示例,并讨论了使用AWS可能遇到的挑战及应对策略,帮助开发者更好地利用AWS的强大功能,提升Web应用开发效率。
61 0
|
4月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的实验室安全考试系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的实验室安全考试系统附带文章源码部署视频讲解等
63 2
|
5月前
|
JavaScript 前端开发 安全
安全开发-JS应用&原生开发&JQuery库&Ajax技术&加密编码库&断点调试&逆向分析&元素属性操作
安全开发-JS应用&原生开发&JQuery库&Ajax技术&加密编码库&断点调试&逆向分析&元素属性操作
|
5月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的实验室安全考试系统附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的实验室安全考试系统附带文章和源代码部署视频讲解等
42 6
|
6月前
|
JavaScript Java 测试技术
基于ssm+vue.js的安全教育平台附带文章和源代码设计说明文档ppt
基于ssm+vue.js的安全教育平台附带文章和源代码设计说明文档ppt
32 1
|
5月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的食品安全信息管理系统附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的食品安全信息管理系统附带文章和源代码部署视频讲解等
44 0
|
安全 JavaScript
js如何安全的获取undefinde值?
为什么要安全的获取undefinde值? 因为 undefined 是一个标识符,所以可以被当作变量来使用和赋值,但是这样会影响 undefined 的正常判断。
164 0
下一篇
无影云桌面