Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8835

Node.jsのHTTPリクエストヘッダの最大サイズでハマった話

$
0
0

現象

  • Node.js(v12.3.1)で立てたWebサーバにアクセスすると、時折HTTPリクエストに失敗する
  • Cookieを削除したり、ブラウザを再起動すると治ることもあるが、根本的な原因がわからない
サンプルコード
consthttp=require('http');constserver=http.createServer((req,res)=>{res.writeHead(200,{'Content-Type':'text/plain'});res.end('Hello World');});server.listen(8080);

原因

  • Node.jsの最大HTTPリクエストヘッダサイズのデフォルト値である8kBを越えるHTTPリクエストヘッダサイズを送信していたことが原因だった

  • Node.jsは、2018/11にDoS攻撃の脆弱性対応として、デフォルトのHTTPリクエストヘッダの最大サイズを変更前の80kBから8kB(8192Bytes)に変更する修正が加えられた

  • デフォルトでは、HTTPリクエストヘッダのサイズが8kBを越えるとソケットが強制破棄されて「431 Request Header Fields Too Large」を返す

$ npm start

> sample-nodejs-header-overflow@1.0.0 start /../../../sample-nodejs-header-overflow
> node index.js

// curlで8kB以上のHTTPリクエストを送信
ErrorCode:  HPE_HEADER_OVERFLOW
BytesParsed:  8559

// curlで8kB以上のHTTPリクエストを送信
ErrorCode:  HPE_HEADER_OVERFLOW
BytesParsed:  8559

// curlで8kB以上のHTTPリクエストを送信
ErrorCode:  HPE_HEADER_OVERFLOW
BytesParsed:  9085

対策

  • HTTPリクエストヘッダのサイズが超えた場合に起こるclientErrorイベントを補足して、ソケットが強制的に破棄されないようにエラーハンドリングを行う
consthttp=require('http');constserver=http.createServer((req,res)=>{res.writeHead(200,{'Content-Type':'text/plain'});res.end('Hello World');});server.on('clientError',(err,socket)=>{console.log('ErrorCode: ',err.code);console.log('BytesParsed: ',err.bytesParsed);socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');});server.listen(8080);
  • アプリケーション起動時に「--max-http-header-size」という起動オプションを設定して、Node.jsが受け取る最大のHTTPリクエストヘッダサイズを増やす
$ node --max-http-header-size=16384 index.js

おわりに

今回リクエストヘッダのサイズが8kBを越えた主な原因は、多数のCookieを使ってWebサーバにアクセスしていたことでした。
仕様上Cookieの数が多くなり、HTTPリクエストのサイズに不安がある場合は、エラーハンドリングを正しく実装して、起動オプションでNode.jsが受け取るHTTPリクエストサイズの最大値を上げておくと良いかと思います。

参考


Viewing all articles
Browse latest Browse all 8835

Trending Articles