本人新博客 {aa16aa}, 基于 360 的 firekylin,感兴趣的可以看看哈
本文翻译自 {aa15aa} , 并非逐字逐句的翻译,有错误的地方请指出,谢谢啦
应用程序的安全就像是你房间里突然出现一只大象,那么明显,但是写代码的同学还是会忽略。也都认为应用程序的安全非常重要但是却很少有时间认真对待,毕竟我们有那么多 bug 要改(坏笑)。所以我们整理了一个 NodeJs 应用安全备忘录,以帮助你在部署启动 NodeJs 应用程序的时候进行安全检查。当然,这些项目大部分是通用的,适用于所有的语言和框架而不仅仅是 Node.js。但是本文具体还涉及到一些 Node.js 的工具。感兴趣的同学也可以查看我的的博客。
Strict-Transport-Security:强制通过(SSL/TLS 上的 HTTP)连接到服务器
X-Frame-Options:提供阻止点击挟持攻击
X-XSS-Protection:启用浏览器内置的跨站点脚本(XSS)筛选器
X-Content-Type-Options:防止浏览器从 MIME 探查从声明内容类型的响应
Content-Security-Policy:防止各种攻击,包括跨站点脚本和其他跨网站注射
在 Express 中,我们可以很容易用来设置这些头部:
- var express = require('express');
- var helmet = require('helmet');
- var app = express();
- app.use(helmet());
当然,在 koa 框架中也可以使用:
这些头部不只是可以放在代码中,也可以配置在 web 服务器中(Apache、nginx),这样也就省了改动程序代码
- # nginx.conf
- add_header X-Frame-Options SAMEORIGIN;
- add_header X-Content-Type-Options nosniff;
- add_header X-XSS-Protection "1; mode=block";
- add_header Content-Security-Policy "default-src 'self'";
nginx 服务器的配置也可以参考:
在部署前端应用程序时要确保不会将秘密的 API 公开, 公开的 API 会被任何人访问
虽然没有好的自动检查的方法,但有两个注意点可以减轻由于意外而暴露敏感数据的风险
1. 检查使用的请求
2. 常规的代码审查
暴力破解(也称穷举法),即将密码进行逐个推算直到找到真正的密码,然后在 web 应用程序中登录。
为了防止应用程序受到暴力破解的攻击,应用程序最好要有密码错误容许次数机制,在 NodeJs 中,你可以使用:
- var limit = new Limiter({
- id: email,
- db: db
- });
- limit.get(function(err, limit) {});
当然啦,你也可以将他包装成一个中间件,就可以放在应用程序中,无论是 Express 框架还是 Koa 框都有厉害的中间件,在 koa 框架中,他可能是这个样子:
- var ratelimit = require('koa-ratelimit');
- var redis = require('redis');
- var koa = require('koa');
- var app = koa();
- var emailBasedRatelimit = ratelimit({
- db: redis.createClient(),
- duration: 60000,
- max: 10,
- id: function(context) {
- return context.body.email;
- }
- });
- var ipBasedRatelimit = ratelimit({
- db: redis.createClient(),
- duration: 60000,
- max: 10,
- id: function(context) {
- return context.ip;
- }
- });
- app.post('/login', ipBasedRatelimit, emailBasedRatelimit, handleLogin);
我们在这里做的是有限的用户在给定的时间里(60000 毫秒)可以出错多少次(10 次),这样我们的程序可以减轻被暴力破解的风险。不过这些配置必须为给定的应用,不要直接复制粘贴他们。
安全使用 Cookie 的重要性不能被低估:尤其是在动态 Web 应用程序,这就需要保持整个无状态协议状态,如 HTTP。
Cookie 的属性列表:
secure —这个属性设置为 true 时是告诉浏览器如果正在通过 HTTPS 发送请求,只发送 cookie。
HttpOnly—- 如果 Cookie 中设置了这个属性,那么通过程序 (JS 脚本、Applet 等) 将无法读取到 Cookie 信息,可以有效的用来防止诸如跨站点脚本攻击
限制 cookie 的作用范围
** Domain-- 这个属性是用来比较中被请求的 URL 服务器的域。如果域匹配,或者如果它是一个子域,则路径属性将下一个检查。
path-- 除了 Domain,该 Cookie 有效期可以指定 URL 路径。如果域名和路径匹配,那么该 cookie 将被请求发送。
expires** -- 这个属性是用来设置 Cookie 的到期时间,因为该 cookie 不会过期,直到超出设定的日期
在 NodeJs 中,可以很容易的创建 cookie, 通过或者
- 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 的会话模块文档)。
跨站请求伪造一种挟持用户在当前已登录的 web 应用程序上执行非自己操作的攻击方法,这种攻击专门针对更改请求,而不是窃取数据,因为攻击者也没法比见到伪造请求的响应
在 NodeJs 中要减轻这种攻击,可以使用 [csrf] (
在路由中,你需要做的是:
- var cookieParser = require('cookie-parser');
- var csrf = require('csurf');
- var bodyParser = require('body-parser');
- var express = require('express');
- // setup route middlewares
- var csrfProtection = csrf({
- cookie: true
- });
- var parseForm = bodyParser.urlencoded({
- extended: false
- });
- // create express app
- var app = express();
- // we need this because "cookie" is true in csrfProtection
- app.use(cookieParser());
- app.get('/form', csrfProtection,
- function(req, res) {
- // pass the csrfToken to the view
- res.render('send', {
- csrfToken: req.csrfToken()
- });
- });
- app.post('/process', parseForm, csrfProtection,
- function(req, res) {
- res.send('data is being processed');
- });
然后在视图层:
- <form action="/process" method="POST">
- <input type="hidden" name="_csrf" value="{{csrfToken}}">
- Favorite color:
- <input type="text" name="favoriteColor">
- <button type="submit">
- Submit
- </button>
- </form>
(这个例子是取自 csurf 模块文档)。
XSS 有两个相似,但不同类型的攻击防范。一个是跨站脚本的反射版本,另一个是存储跨站脚本。
反射式跨站脚本,通过注入发送带有恶意脚本代码参数的 URL,当 URL 地址被打开时,特有的恶意代码参数被 html 解析、执行。
存储跨站脚本,指的是恶意脚本代码被存储进被攻击的数据库,当其他用户正常浏览网页时,站点从数据库中读取了非法用户存入非法数据,恶意脚本代码被执行。
为了抵御这类攻击,确保你过滤或者清理用户输入。
SQL 注入是由用户输入部分或完整的 SQL 查询的注入。它可以读取敏感信息。
- select title,
- author from books where id = $id
在这个实例代码中,参数 $id 如果用户输入的是 2 or 1=1?,那查询变为如下:
- select title,
- author from books where id = 2 or 1 = 1
防范这类攻击的最简单的方法是使用参数化查询或准备好的语句。
是一个开源的渗透测试工具,它可以自动检测并利用 SQL 注入漏洞和接管数据库服务器的过程。使用此工具来测试 SQL 注入漏洞的应用程序。
命令注入是由攻击者向远程的 Web 服务器上运行的系统命令的技术。用这种方法攻击者可能甚至得到的系统的密码。
在实际开发中,如果你有一个网址,如:
- https: //example.com/downloads?file=user1.txt
它可以变成:
- https: //example.com/downloads?file=;cat /etc/passwd
在这个例子中; 变成了分号,所以多个系统命令可以运行。
为了抵御这类攻击,确保你始终过滤或清理了用户输入。
另外,在 Node.js 中我们可以这样来检测:
- child_process.exec('ls',
- function(err, data) {
- console.log(data);
- });
child_process.exec 创建一个子线程来调用执行 / bin/sh,所以他是一个 bash 的解释,而不是一个程序的启动,当用户输入被传递给这个方法,就会被执行,显示目录下的所有文件。一个新的命令被攻击者注入。
为了防止被攻击,可以使用 child_process.execFile
由于 HTTP 是一种明文协议,如果通过了 SSL / TLS 隧道,被称为 HTTPS 进行保护。如今高档的密码通常使用,在服务器配置错误可以用来强制使用弱密码 - 或者在最坏的情况没有加密。
你必须测试:
使用工具和可以很容易扫描出来
检查证书信息
- nmap--script ssl - cert,
- ssl - enum - ciphers - p 443,
- 465,
- 993,
- 995 www.example.com
利用 sslyze 可以测试 SSL / TLS 的漏洞
- ./sslyze.py --regular example.com:443
在配置管理的一部分,我们使用这个 briefly - Strict-Transport-Security 头强制执行安全(基于 SSL 的 HTTP / TLS)连接到服务器上。就拿从 Twitter 下面的例子:
- strict-transport-security:max-age=631138519
这里 max-age 定义为秒,浏览器自动将所有的 HTTP 请求转换为 HTTPS 的数量。
它的测试是非常简单的:
- curl - s - D - https: //twitter.com/ | grep -i Strict
帐户锁定是减少暴力攻击的方法。这就意味着,如果账户多次登录失败,就让这个账户在一定时间内(最初也可以是一两分钟,然后就可以成倍增加)锁定。
这可以保护应用程序不被攻击。
大多数正则表达式可能会导致攻击者的破解工作变得缓慢和低效。这些的正则表达式被称为邪恶的正则表达式:
([a-zA-Z]+)*,(a+)+ 或者 (a|a?)+ 是所有弱势的正则表达式作为一个简单的输入一样 aaaaaaaaaaaaaaaaaaaaaaaa! 会导致重计算。每增加一个 a,时间就会翻倍。
在 NodeJs 中,如果要检查正则表达式,你可以
- $ node safe.js '(beep|boop)*' true $ node safe.js '(a+){10}' false
不同的错误情况的应用程序可能会泄漏对底层基础架构的敏感细节,如:X-Powered-By:Express。
栈跟踪不被视为自己的漏洞,但他们往往可能是吸引的攻击者的信息。提供了调试信息和产生错误操作的结果都被认为是不好的做法。应该用日志记录下来,而不是显示给用户。
NPM 有很多包提供给大家使用,但是这也是有代价的:应该好好检查你需要为你的应用程序是什么。也许你使用之后可能含有重要的安全问题。
不过幸运的是,有一个伟大的工具 --The Node Security Platform,可以检查使用的模块为已知的漏洞。
- npm i nsp -g # either audit the shrinkwrap nsp audit-shrinkwrap # or the package.json nsp audit-package
你还可以使用。
SnykSnyk 类似于 The Node Security Platform,但他的目的是提供一种工具,不能只检测,只是在代码库修复安全相关的问题。
更多信息你可以看看
本人新博客, 基于 360 的 firekylin,感兴趣的可以看看哈
来源: