Node.jsで 80番ポートをListenするWebサーバを作る

簡単にWebサーバが作れますとかいって、よく、以下のようなコードが紹介されています。(余談ながら、私個人としてはコードが短いことがどうしていいことなのかは理解に苦しみます。ある特定の、かつ、まったく現実的に役に立たないコードが短いことにどんな利点があるのでしょうか???)
var http = require('http');
http.createServer(function (request, response) {
  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.end('Hello World\n');
}).listen(3000, '127.0.0.1');
これを実行したあと、ブラウザで

http://127.0.0.1:3000

を開くとHello Worldというページが見れます。3000番ポートをhttp標準の80番ポートにして動かそうと単純に以下のようにすると
var http = require('http');
http.createServer(function (request, response) {
  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.end('Hello World\n');
}).listen(80, '127.0.0.1');
と修正すると
node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
Error: listen EACCES
    at errnoException (net.js:640:11)
    at Array.0 (net.js:726:28)
    at EventEmitter._tickCallback (node.js:192:40)
みたいな例外が発生して動きません。1023番までは一般ユーザではlistenできないからです。rootでなら動きますが、それじゃprocessがrootで動いちゃいます。なんかあったときに(セキュリティの問題とか)全部システムがのっとられてしまうかもしれない。

これは、以下のようにsetuidでlistenしたあとに、プロセスのオーナを変更するのが「よい実装」でしょう。一度でも listenしちゃえばプロセスのオーナを誰に変えても問題ないのです(この例では80番にしている)

listenのコールバックに置いておくのは listenを読んだ直後にsetuidをすると、listenが完了する前にsetuidをしてしまう可能性があるから。このあたりイベント駆動型の言語はめんどくさいよなぁ。
var http = require('http');
http.createServer(function (request, response) {
  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.end('Hello World\n');
}).listen(80, '0.0.0.0', function(){process.setuid(80)});


このあたり、昔のUNIXの人には常識なんだろうけど、rootで動かせばいいじゃんみたいなページが沢山あるので老婆心ながらブログに書いておきます。ま、Apacheとかを前段に置いて、reverse proxyというのが、さらなる正解なのかもですが。

コメント一覧

root権限で動かすサンプル多いですね。だからか・・・root権限を要求している人が多いな~。
makoto

伝統的な超越的root権限ってのはそういった点でも強力過ぎて扱いに困るってんで、近代的なシステムではちょっとセキュリティモデルを変えて権限を細分化する方向に行ってますよね。まぁ、細分化した権限だろうとあらぬことされないように不要になったら権限放棄するのは正しいし必要だと思いますけど。
ふたつき