POSTD PRODUCED BY NIJIBOX

POSTD PRODUCED BY NIJIBOX

ニジボックスが運営する
エンジニアに向けた
キュレーションメディア

POSTD PRODUCED BY NIJIBOX

POSTD PRODUCED BY NIJIBOX

ニジボックスが運営する
エンジニアに向けた
キュレーションメディア

FeedlyRSSTwitterFacebook
Gergely Nemeth

本記事は、原著者の許諾のもとに翻訳・掲載しております。


(2016/1/5)

   RisingStack使

Node.jsNode.js Node.js 稿

HTTP


WebHTTP


Strict Transport Security HTTPSSL/TLS

X-Frame-Options   

X-XSS-ProtectionXSS

X-Content-Type-Options content-typeMIME

Content-Security-Policy 


Node.js Helmet 使
var express = require('express');  
var helmet = require('helmet');

var app = express();

app.use(helmet());  

Koa  koa-helmet 使

WebApache, nginxNginx
# 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 configuration 

Web http://cyh.herokuapp.com/cyh 


API secretAPI




使




Web

rate-limitingNode.js ratelimiter 
var email = req.body.email;  
var limit = new Limiter({ id: email, db: db });

limit.get(function(err, limit) {

});

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

 &

Web hydra 


使HTTPWeb





  HTTPS

HttpOnly  JavaScript使



  URL使

  URL

  使


Node.js 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


CSRFCross-Site Request ForgeryWeb

Node.js csrf 使 csurf CSRFExpress


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トークンを使う必要があります。

<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


211

Refrected()  JavaScriptHTML

Stored()  Web


SQL


SQLSQL


select title, author from books where id=$id  

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

使

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


sqlmap SQLSQL使


WebOS使

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

これは以下のように変更されることがあります。

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

 %3B OS




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

child_process.exec  /bin/sh bash

 $() 

 child_process.execFile 使

SSL


HTTPHTTPSSSL/TLS使使









 nmap  sslyze 使


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 ヘッダは、サーバへの安全な(SSL/TLS経由のHTTP)接続を強制しています。以下のTwitterの例を見てみましょう。

strict-transport-security:max-age=631138519  

この max-age は、ブラウザが自動的に全てのHTTPリクエストをHTTPSに変換する秒数を定義します。

これは以下のようにすると、とても簡単にテストできます。

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

サービスの拒否

アカウントのロックアウト




Rate Limiter使


















([a-zA-Z]+)*  (a+)+  (a|a?)+  aaaaaaaaaaaaaaaaaaaaaaaa! CPU Regular expression Denial of Service  ReDoS 

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


 X-Powered-By:Express 


NPM


NPM使使

Node Security Project使
npm i nsp -g  
# either audit the shrinkwrap
nsp audit-shrinkwrap  
# or the package.json
nsp audit-package

requireSafe も役立ちます。

まとめと考察

このリストを作成する上で、 OWASP が管理する Web Application Security Testing Cheat Sheet(Webアプリケーションのためのセキュリティテスト用チートシート) の内容を大いに参考にさせていただきました。

Open Web Application Security Project (OWASP)は、ソフトウェアのセキュリティ向上を目的とした世界規模の非営利組織です。

このリストに不足している内容があれば追加しますので、ご連絡ください。

監修者
監修者_古川陽介
古川陽介
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
複合機メーカー、ゲーム会社を経て、2016年に株式会社リクルートテクノロジーズ(現リクルート)入社。 現在はAPソリューショングループのマネジャーとしてアプリ基盤の改善や運用、各種開発支援ツールの開発、またテックリードとしてエンジニアチームの支援や育成までを担う。 2019年より株式会社ニジボックスを兼務し、室長としてエンジニア育成基盤の設計、技術指南も遂行。 Node.js 日本ユーザーグループの代表を務め、Node学園祭などを主宰。