[譯]Node.js安全清單

前言

安全性,老是一個不可忽視的問題。許多人都認可這點,可是卻不多有人真的認真地對待它。因此咱們列出了這個清單,讓你在將你的應用部署到生產環境來給千萬用戶使用以前,作一個安全檢查。javascript

如下列出的安全項,大多都具備普適性,適用於除了Node.js外的各類語言和框架。可是,其中也包含一些用Node.js寫的小工具。php

配置管理

安全性相關的HTTP頭

如下是一些安全性相關的HTTP頭,你的站點應該設置它們:前端

  • Strict-Transport-Security:強制使用安全鏈接(SSL/TLS之上的HTTPS)來鏈接到服務器。java

  • X-Frame-Options:提供對於「點擊劫持」的保護。node

  • X-XSS-Protection:開啓大多現代瀏覽器內建的對於跨站腳本攻擊(XSS)的過濾功能。nginx

  • X-Content-Type-Options: 防止瀏覽器使用MIME-sniffing來肯定響應的類型,轉而使用明確的content-type來肯定。git

  • Content-Security-Policy:防止受到跨站腳本攻擊以及其餘跨站注入攻擊。github

Node.js中,這些均可以經過使用Helmet模塊輕鬆設置完畢:web

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

var app = express();

app.use(helmet());

Helmet在Koa中也能使用:koa-helmet正則表達式

固然,在許多的架構中,這些頭會在Web服務器(Apache,nginx)的配置中設置,而不是在應用的代碼中。若是是經過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配置

若是你想快速確認你的網站是否都設置這些HTTP頭,你能夠經過這個網站在線檢查:http://cyh.herokuapp.com/cyh

客戶端的敏感數據

當部署前端應用時,確保不要在代碼中暴露如密鑰這樣的敏感數據,這將能夠被全部人看到。

現今並無什麼自動化檢測它們的辦法,可是仍是有一些手段能夠用來減小不當心將敏感數據暴露在客戶端的機率:

  • 使用pull request更新代碼

  • 創建起code review機制

身份認證

對於暴力破解的保護

暴力破解即系統地列舉全部可能的結果,並逐一嘗試,來找到正確答案。在web應用中,用戶登錄就特別適合它發揮。

你能夠經過限制用戶的鏈接頻率來防止這類的攻擊。在Node.js中,你可使用ratelimiter包。

var email = req.body.email;  
var limit = new Limiter({ id: email, db: db });

limit.get(function(err, limit) {

});

固然,你能夠將它封裝成一箇中間件以供你的應用使用。ExpressKoa都已經有現成的不錯的中間件:

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);

這裏咱們所作的,就是限制了在一段給定時間內,用戶能夠嘗試登錄的次數 -- 這減小用戶密碼被暴力破解的風險。以上例子中的選項都是能夠根據你的實際情景所改變的,因此不要簡單的複製粘貼它們。。

若是你想要測試你的服務在這些場景下的表現,你可使用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

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模塊的文檔)

CSRF

跨站請求僞造(CSRF)是一種迫使用戶在他們已登陸的web應用中,執行一個並不是他們原意的操做的攻擊手段。這種攻擊經常用於那些會改變用戶的狀態的請求,一般它們並不竊取數據,由於攻擊者並不能看到響應的內容。

Node.js中,你可使用csrf模塊來緩和這種攻擊。它一樣是很是底層的,你可能更喜歡使用如csurf這樣的Express中間件。

在路由層,能夠會有以下代碼:

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');
});

在展現層,你須要使用CSRF token

<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

如下是兩種相似的,可是略有不一樣的攻擊方式,一種關於跨站腳本,而另外一種則關於存儲。

  • 非持久化的XSS攻擊 在攻擊者向指定的URL的響應HTML中注入可執行的JavaScript代碼時發生。

  • 持久化的XSS攻擊 在應用存儲未通過濾的用戶輸入時發生。用戶輸入的代碼會在你的應用環境下執行。

爲了防護這類攻擊,請確保你老是檢查並過濾了用戶的輸入內容。

SQL注入

在用戶的輸入中包含部分或完整的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

最簡單的預防方法則是使用參數化查詢(parameterized queries)或預處理語句(prepared statements)。

若是你正在經過Node.js使用PostgreSQL。那麼你可使用node-postgres模塊,來建立參數化查詢:

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

命令注入

攻擊者使用命令注入來在遠程web服務器中運行系統命令。經過命令注入,攻擊者甚至能夠取得系統的密碼。

實踐中,若是你有一個URL:

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

它能夠變成:

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

在這個例子中,%3B會變成一個分號。因此將會運行多條系統命令。

爲了預防這類攻擊,請確保老是檢查過濾了用戶的輸入內容。

咱們也能夠以Node.js的角度來講:

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

child_process.exec的底層,它調用了/bin/sh,因此它是一個bash解釋器,而不只僅是隻能執行用戶程序。

當用戶的輸入是一個反引號或$()時,將它們傳入這個方法就很危險了。

能夠經過使用child_process.execFile來解決上面這個問題。

安全傳輸

SSL版本,算法,鍵長度

因爲HTTP是明文傳輸的,因此咱們須要經過一個SSL/TLS通道來加密,即HTTPS。現在高級別的加密方式已被廣泛使用,可是,若是在服務端缺少配置,也可能會致使服務端使用低級別的加密,或不加密。

你須要測試:

  • 密碼,密鑰和重協商(renegotiation)都已經合法妥善得配置完畢。

  • 證書的合法性。

使用如nmapsslyze這樣的工具可使這項工做很是簡單。

檢查證書信息

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

使用sslyze來檢查SSL/TSL:

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

HSTS

在上文的配置管理章節咱們已經對其有了接觸 - Strict-Transport-Security頭會強制使用HTTPS來鏈接服務器。如下是一個Twitter的例子:

strict-transport-security:max-age=631138519

這裏的max-age定義了瀏覽器須要自動將全部HTTP請求轉換成HTTPS的秒數。

對於它的測試是很是簡單的:

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這檢測你的正則:

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

錯誤處理

錯誤碼,堆棧信息

一些錯誤場景可能會致使應用泄露底層的應用架構信息,如:like: X-Powered-By:Express

堆棧信息可能本身自己並無什麼用,但它常常能泄露一些攻擊者很是感興趣的信息。將堆棧信息返回出來是很是很差的實踐。你須要將它們記錄在日誌中,而不是展現給用戶。

NPM

更強的能力意味着更大的責任 - NPM有這許多能夠現成使用的包,可是代價是:你須要檢查這些包自己是否存在安全問題。

幸運的是Node Security project(nsp)是一個很是棒的工具,來檢查你使用的模塊是不是易被一些已知的手段攻擊的。

npm i nsp -g  
# either audit the shrinkwrap
nsp audit-shrinkwrap  
# or the package.json
nsp audit-package

最後

這個清單主要根據OWASP維護的Web Application Security Testing Cheat Sheet所列。

原文連接

https://blog.risingstack.com/node-js-security-checklist/

相關文章
相關標籤/搜索