Node.js セキュリティ強化:blockList.addSubnet()サンプルコード集

2025-04-26

以下に、より詳細な説明をします。

blockList.addSubnet()の役割と機能

  • 柔軟性
    サブネットマスクを指定することで、IPアドレスの範囲を柔軟に設定できます。
  • アクセス制御
    このメソッドを使用することで、特定のIPアドレス範囲からのアクセスを効果的に制御し、セキュリティを強化できます。
  • サブネットのブロック
    指定されたIPアドレスのサブネット(ネットワークアドレスとサブネットマスクで定義されるIPアドレスの範囲)をブロックリストに追加します。

構文

一般的には、以下のような構文で使用されます。

blockList.addSubnet(networkAddress, subnetMask);
  • subnetMask: サブネットマスク(例: "255.255.255.0" または "/24")。
  • networkAddress: ブロックするサブネットのネットワークアドレス(例: "192.168.1.0")。


例えば、192.168.1.0/24のサブネットをブロックする場合、以下のように記述します。

blockList.addSubnet("192.168.1.0", "255.255.255.0");
// または
blockList.addSubnet("192.168.1.0", "/24");
  • APIのアクセス制御
    APIへのアクセスを特定のIPアドレス範囲に制限します。
  • Webアプリケーションのセキュリティ強化
    特定のIPアドレス範囲からのアクセスを制限し、Webアプリケーションのセキュリティを向上させます。
  • 不正アクセス対策
    特定のIPアドレス範囲からの不正なアクセスを遮断します。
  • この機能は、セキュリティ関連のライブラリやフレームワーク(例: express-ipfilter, ip-filter)で利用できます。
  • サブネットマスクは、CIDR表記(例: "/24")またはドット区切りの10進数表記(例: "255.255.255.0")で指定できます。
  • blockListは、IPアドレスのブロックリストを管理するオブジェクトです。具体的なライブラリやフレームワークによって、blockListの生成方法や利用方法が異なる場合があります。


無効なIPアドレスまたはサブネットマスク

  • トラブルシューティング
    • IPアドレスとサブネットマスクの形式が正しいか確認してください。
    • IPアドレスはIPv4またはIPv6の形式に従っている必要があります。
    • サブネットマスクはCIDR表記(例: "/24")またはドット区切りの10進数表記(例: "255.255.255.0")で指定してください。
    • 入力値のタイプをしっかり確認しましょう。文字列型で渡す必要があります。
  • 原因
    networkAddressまたはsubnetMaskに無効な値が渡された場合に発生します。
  • エラー
    TypeError: Invalid IP address または TypeError: Invalid subnet mask

サブネットマスクの範囲外の値

  • トラブルシューティング
    • CIDR表記の場合、/0から/32(IPv4の場合)または/128(IPv6の場合)の範囲内であるか確認してください。
    • ドット区切りの10進数表記の場合、各オクテットが0から255の範囲内であるか確認してください。
    • サブネットマスクの値がネットワークの範囲を正しく定義しているか確認してください。
  • 原因
    サブネットマスクの値が不正な場合に発生します。
  • エラー
    サブネットマスクの値が範囲外であるために、期待通りのブロックがされない。

blockListオブジェクトの初期化エラー

  • トラブルシューティング
    • blockListオブジェクトが正しく作成されているか確認してください。
    • 必要なライブラリやフレームワークが正しくインストールされ、インポートされているか確認してください。
    • blockListを生成する関数やメソッドを呼び出しているか確認してください。
  • 原因
    blockListオブジェクトが初期化されていないか、存在しない場合に発生します。
  • エラー
    TypeError: Cannot read property 'addSubnet' of undefined

ライブラリまたはフレームワークの互換性問題

  • トラブルシューティング
    • ライブラリまたはフレームワークのドキュメントを確認し、互換性のあるバージョンを使用してください。
    • ライブラリまたはフレームワークを最新バージョンに更新してみてください。
    • 関連するライブラリも全て更新して試してください。
  • 原因
    使用しているライブラリまたはフレームワークのバージョンが互換性がない場合に発生します。
  • エラー
    予期しないエラーや動作が発生する。

ブロックリストが期待通りに動作しない

  • トラブルシューティング
    • blockList.addSubnet()に渡されたIPアドレスとサブネットマスクが正しいか再確認してください。
    • 他のアクセス制御の設定(ファイアウォール、ロードバランサーなど)と競合していないか確認してください。
    • ログを出力して、実際にどのようなIPアドレスからのアクセスが来ているのか確認しましょう。
    • 設定を一つずつ変更して、原因を特定しましょう。
  • 原因
    ブロックリストの設定が正しくないか、他の設定と競合している場合に発生します。
  • エラー
    特定のIPアドレス範囲からのアクセスがブロックされない。
  • ネットワークツール
    pingtracerouteなどのネットワークツールを使用して、IPアドレスの到達性を確認してください。
  • ドキュメントの参照
    使用しているライブラリまたはフレームワークのドキュメントを参照し、blockList.addSubnet()の正しい使用方法を確認してください。
  • エラーハンドリング
    try...catchブロックを使用して、エラーを適切に処理し、エラーメッセージを表示してください。
  • ログ出力
    console.log()を使用して、networkAddresssubnetMaskの値、およびblockListオブジェクトの状態を出力し、デバッグに役立ててください。


express-ipfilterのインストール

まず、express-ipfilterをインストールする必要があります。ターミナルで以下のコマンドを実行します。

npm install express-ipfilter

この例では、192.168.1.0/24のサブネットからのアクセスをブロックします。

const express = require('express');
const ipfilter = require('express-ipfilter').IpFilter;

const app = express();

// ブロックするサブネットのリストを作成
const blocked = ['192.168.1.0/24'];

// IPフィルタリングミドルウェアを作成
const ipFilterMiddleware = ipfilter(blocked, { mode: 'deny' });

// ミドルウェアを適用
app.use(ipFilterMiddleware);

// ルートハンドラ
app.get('/', (req, res) => {
  res.send('アクセス許可されました。');
});

// サーバーを起動
app.listen(3000, () => {
  console.log('サーバーがポート3000で起動しました。');
});

説明

  1. expressexpress-ipfilterをインポートします。
  2. blocked配列に、ブロックするサブネットをCIDR表記で指定します。
  3. ipfilter()関数を使用して、IPフィルタリングミドルウェアを作成します。mode: 'deny'は、指定されたIPアドレス範囲からのアクセスを拒否することを意味します。
  4. app.use()を使用して、ミドルウェアを適用します。
  5. ルートハンドラで、アクセス許可された場合に表示するメッセージを送信します。
  6. サーバーをポート3000で起動します。

この例では、複数のサブネットをブロックします。

const express = require('express');
const ipfilter = require('express-ipfilter').IpFilter;

const app = express();

// ブロックするサブネットのリストを作成
const blocked = ['192.168.1.0/24', '10.0.0.0/8', '2001:db8::/32']; //ipv6もブロック可能

// IPフィルタリングミドルウェアを作成
const ipFilterMiddleware = ipfilter(blocked, { mode: 'deny' });

// ミドルウェアを適用
app.use(ipFilterMiddleware);

// ルートハンドラ
app.get('/', (req, res) => {
  res.send('アクセス許可されました。');
});

// サーバーを起動
app.listen(3000, () => {
  console.log('サーバーがポート3000で起動しました。');
});

説明

  1. blocked配列に、複数のサブネット(IPv4とIPv6を含む)をCIDR表記で指定します。

この例では、特定のIPアドレス範囲からのみアクセスを許可し、それ以外をブロックします。

const express = require('express');
const ipfilter = require('express-ipfilter').IpFilter;

const app = express();

// 許可するサブネットのリストを作成
const allowed = ['192.168.1.0/24', '127.0.0.1'];

// IPフィルタリングミドルウェアを作成
const ipFilterMiddleware = ipfilter(allowed, { mode: 'allow' });

// ミドルウェアを適用
app.use(ipFilterMiddleware);

// ルートハンドラ
app.get('/', (req, res) => {
  res.send('アクセス許可されました。');
});

// サーバーを起動
app.listen(3000, () => {
  console.log('サーバーがポート3000で起動しました。');
});
  1. allowed配列に、許可するサブネットとIPアドレスを指定します。
  2. mode: 'allow'は、指定されたIPアドレス範囲からのアクセスのみを許可することを意味します。
  • 実際のアプリケーションでは、データベースや設定ファイルからIPアドレス範囲を読み込むことも可能です。
  • エラーメッセージのカスタマイズや、IPアドレスの取得方法のカスタマイズなど、さまざまなオプションが用意されています。
  • modeオプションを使用して、許可または拒否のモードを選択できます。
  • express-ipfilterは、柔軟なIPフィルタリング機能を提供します。


自作のミドルウェアを使用する

expressなどのフレームワークを使用している場合、自作のミドルウェアを作成してIPアドレスのブロックリストを実装できます。

const express = require('express');
const app = express();

const blockedSubnets = [
  { network: '192.168.1.0', mask: '255.255.255.0' }, // または { network: '192.168.1.0', mask: '/24' }
  { network: '10.0.0.0', mask: '255.0.0.0' },
];

function isIpInSubnet(ip, network, mask) {
  const ipParts = ip.split('.').map(Number);
  const networkParts = network.split('.').map(Number);
  const maskParts = mask.startsWith('/') ? mask.substring(1) : mask.split('.').map(Number);

  if (mask.startsWith('/')) {
    const maskBits = parseInt(maskParts[0]);
    let networkBinary = 0;
    let ipBinary = 0;

    for (let i = 0; i < 4; i++) {
      networkBinary = (networkBinary << 8) | networkParts[i];
      ipBinary = (ipBinary << 8) | ipParts[i];
    }

    const maskBinary = (0xffffffff << (32 - maskBits)) >>> 0;
    return (networkBinary & maskBinary) === (ipBinary & maskBinary);
  } else {
    for (let i = 0; i < 4; i++) {
      if ((ipParts[i] & maskParts[i]) !== (networkParts[i] & maskParts[i])) {
        return false;
      }
    }
    return true;
  }
}

function ipBlocker(req, res, next) {
  const clientIp = req.ip.replace('::ffff:', ''); // IPv6からIPv4に変換

  for (const subnet of blockedSubnets) {
    if (isIpInSubnet(clientIp, subnet.network, subnet.mask)) {
      return res.status(403).send('アクセスが拒否されました。');
    }
  }
  next();
}

app.use(ipBlocker);

app.get('/', (req, res) => {
  res.send('アクセス許可されました。');
});

app.listen(3000, () => {
  console.log('サーバーがポート3000で起動しました。');
});

説明

  1. blockedSubnets配列に、ブロックするサブネットのリストをオブジェクトとして定義します。
  2. isIpInSubnet()関数は、与えられたIPアドレスが指定されたサブネット内にあるかどうかを判定します。
  3. ipBlocker()ミドルウェアは、リクエストのIPアドレスを取得し、blockedSubnetsリストと照合します。
  4. IPアドレスがブロックリストに含まれている場合、403エラーを返します。
  5. それ以外の場合、next()を呼び出して次のミドルウェアまたはルートハンドラに進みます。

iptablesまたはfirewalldを使用する

OSレベルでIPアドレスのフィルタリングを行う場合、iptables(Linux)またはfirewalldを使用できます。

  • firewalld
    firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" reject'
    firewall-cmd --reload
    
  • iptables
    iptables -A INPUT -s 192.168.1.0/24 -j DROP
    

これらのコマンドは、特定のIPアドレス範囲からのトラフィックをブロックします。

リバースプロキシを使用する

NginxやApacheなどのリバースプロキシを使用して、IPアドレスのフィルタリングを行うこともできます。

  • Apacheの設定例:
    <Location />
      Require not ip 192.168.1.0/24
      # ...
    </Location>
    
  • Nginxの設定例:
    location / {
      deny 192.168.1.0/24;
      # ...
    }
    

データベースを使用する

ブロックリストをデータベースに保存し、ミドルウェアでデータベースを照会する方法もあります。この方法では、ブロックリストを動的に更新できます。

// 例:データベースからブロックリストを取得
async function getBlockedSubnetsFromDB() {
  // データベースからブロックリストを取得するロジックを実装
  // 例:[{ network: '192.168.1.0', mask: '255.255.255.0' }, ...]
  return [{ network: '192.168.1.0', mask: '255.255.255.0' }];
}

async function ipBlocker(req, res, next) {
  const blockedSubnets = await getBlockedSubnetsFromDB();
  const clientIp = req.ip.replace('::ffff:', '');

  for (const subnet of blockedSubnets) {
    if (isIpInSubnet(clientIp, subnet.network, subnet.mask)) {
      return res.status(403).send('アクセスが拒否されました。');
    }
  }
  next();
}