Express.js req.ip の IPv6 表現について
Node.js と Express.js を使用したプログラミングにおいて、req.ip
が ::ffff:127.0.0.1
を返すことがあるのは、IPv6 のアドレス表記に関する仕様によるものです。
IPv6 と IPv4 の関係
- IPv4 は、現在広く使用されている旧式のバージョンです。
- IPv6 は、インターネットプロトコルの次世代バージョンで、より多くの IP アドレスをサポートします。
IPv4 アドレスの IPv6 表現
IPv6 は、IPv4 アドレスをサポートするために、::ffff:
というプレフィックスを使用します。このプレフィックスは、IPv4 アドレスを IPv6 アドレスに変換するためのものです。
なぜ ::ffff:127.0.0.1
なのか
- req.ip の挙動
req.ip
は、クライアントの IP アドレスを取得します。ローカルホストからのアクセスでは、IPv6 アドレス::ffff:127.0.0.1
が返されます。 - IPv6 によるアクセス
Node.js アプリケーションが IPv6 をサポートしている場合、ローカルホストへのアクセスは IPv6 アドレス::1
または::ffff:127.0.0.1
で表されます。 - ローカルホストへのアクセス
127.0.0.1
は、ローカルホストへのアクセスを表す IPv4 アドレスです。
対処方法
もし、IPv4 アドレスのみが必要な場合は、req.ip
の値をパースして、::ffff:
プレフィックスを取り除くことができます。ただし、IPv6 アドレスもサポートする必要がある場合は、req.ip
の値をそのまま使用することができます。
コード例
const express = require('express');
const app = express();
app.get('/', (req, res) => {
const clientIp = req.ip.replace(/^::ffff:/, '');
console.log(clientIp); // 127.0.0.1
res.send('Hello, world!');
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
このコードでは、req.ip
の値から ::ffff:
プレフィックスを取り除き、純粋な IPv4 アドレスを取得しています。
const express = require('express');
const app = express();
app.get('/', (req, res) => {
const clientIp = req.ip.replace(/^::ffff:/, '');
console.log(clientIp); // 127.0.0.1
res.send('Hello, world!');
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
コードの説明
-
ライブラリのインポート
-
ルートの定義
-
クライアント IP アドレスの取得
req.ip
プロパティでクライアントの IP アドレスを取得します。req.ip.replace(/^::ffff:/, '')
で、IPv6 アドレスの::ffff:
プレフィックスを除去し、純粋な IPv4 アドレスに変換します。- 変換された IPv4 アドレスを
clientIp
変数に格納します。
-
ログ出力
-
レスポンスの送信
-
サーバーの起動
動作
- ユーザーがブラウザで
http://localhost:3000
にアクセスします。 - サーバーがリクエストを受け取り、
req.ip
でクライアントの IP アドレスを取得します。 req.ip
は::ffff:127.0.0.1
を返します。- コードは
::ffff:
プレフィックスを除去し、127.0.0.1
を取得します。 127.0.0.1
がコンソールに出力されます。- サーバーは "Hello, world!" をクライアントに送信します。
- IPv6 アドレスをそのまま使用したい場合は、
req.ip
の値を直接使用することができます。 - このコードは、ローカル環境でのテスト用に設計されています。本番環境では、より適切な IP アドレスの取得方法やセキュリティ対策が必要になる場合があります。
- IPv6 アドレスの場合でも、IPv4 形式で取得できます。
req.socket.remoteAddress
プロパティは、クライアントの IP アドレスを直接取得します。
const express = require('express');
const app = express();
app.get('/', (req, res) => {
const clientIp = req.socket.remoteAddress;
console.log(clientIp); // 127.0.0.1
res.send('Hello, world!');
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
ミドルウェアの使用
- ミドルウェアを使って、リクエストオブジェクトにクライアントの IP アドレスを直接追加することができます。
const express = require('express');
const app = express();
app.use((req, res, next) => {
req.clientIp = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
next();
});
app.get('/', (req, res) => {
const clientIp = req.clientIp;
console.log(clientIp); // 127.0.0.1
res.send('Hello, world!');
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
ip モジュールの使用
ip
モジュールは、IP アドレスを解析するための便利な機能を提供します。
const express = require('express');
const ip = require('ip');
const app = express();
app.get('/', (req, res) => {
const clientIp = ip.address();
console.log(clientIp); // 127.0.0.1
res.send('Hello, world!');
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
選択のポイント
- 機能性
ip
モジュールは、IP アドレスに関するさまざまな操作を提供します。 - 柔軟性
ミドルウェアを使用すると、リクエストオブジェクトにカスタムプロパティを追加できます。 - シンプルさ
req.socket.remoteAddress
は最もシンプルで直接的な方法です。
注意
- セキュリティ
クライアントの IP アドレスを信頼する前に、適切な検証とセキュリティ対策を講じる必要があります。 - プロキシサーバーやロードバランサー
プロキシサーバーやロードバランサーを使用している場合、req.headers['x-forwarded-for']
ヘッダーに実際のクライアント IP アドレスが含まれていることがあります。
node.js express