
ポートスキャン
不要に公開されたポートは、攻撃者にとっての侵入口です。 データベースポート、開発用ポート、管理ポートの外部公開状況を検出し、 サーバーの攻撃面(Attack Surface)を可視化します。
チェック項目
4カテゴリ・15以上のポートを検査
基本ポート
外部公開リスク: 低SSH
通常公開Secure Shell。サーバーへのリモートアクセスに使用。公開自体は問題ないが、ブルートフォース攻撃の対象になりやすい。
HTTP
通常公開暗号化されていないWeb通信。HTTPS(443)へのリダイレクト用として使用されるべき。
HTTPS
通常公開暗号化されたWeb通信。Webサーバーの標準ポート。
データベースポート
外部公開リスク: 非常に高MySQL
非公開推奨MySQLデータベースのデフォルトポート。外部公開は極めて危険。直接接続によるデータ窃取やブルートフォース攻撃のリスク。
PostgreSQL
非公開推奨PostgreSQLのデフォルトポート。外部公開されると、認証情報のブルートフォースやSQLインジェクションの直接実行が可能に。
MongoDB
非公開推奨MongoDBのデフォルトポート。過去に認証なしで外部公開されたMongoDBインスタンスが大量にランサムウェア攻撃の被害に。
Redis
非公開推奨Redisのデフォルトポート。認証なしで外部公開されると、任意のコマンド実行やデータ窃取が可能。
開発用ポート
外部公開リスク: 高開発サーバー
非公開推奨Next.js、React、Express等の開発サーバーのデフォルトポート。本番環境で公開されるべきではない。
代替HTTP / Proxy
非公開推奨開発用HTTPサーバーやリバースプロキシのデフォルトポート。管理画面やテスト環境が露出するリスク。
代替HTTPS
非公開推奨代替のHTTPSポート。開発環境やテスト環境が外部に公開されている可能性。
Vite Dev Server
非公開推奨Viteの開発サーバーのデフォルトポート。HMRが有効なまま公開されると、ソースコードの露出やリモートコード実行のリスク。
管理・監視ポート
外部公開リスク: 高管理コンソール
非公開推奨Prometheus、Cockpit等の管理コンソールのデフォルトポート。内部メトリクスやシステム情報が露出。
代替SSH
非公開推奨SSHの代替ポート。セキュリティ対策として22から変更している場合があるが、外部スキャンで検出可能。
Jupyter Notebook
非公開推奨Jupyter Notebookのデフォルトポート。外部公開されると、サーバー上で任意のコードが実行可能。
脆弱性の背景
なぜポートスキャンが重要なのか
サーバー上で動作する各サービスは、特定のポート番号を通じてネットワークに公開されます。 本来外部からアクセスする必要のないサービス(データベース、キャッシュ、管理コンソール等)が インターネットに公開されていると、攻撃者にとって直接的な侵入口となります。
攻撃者は最初にポートスキャンを実行し、公開されているサービスとそのバージョンを特定します。 そこから既知の脆弱性を突いた攻撃、ブルートフォース攻撃、認証バイパスなどを試みます。
攻撃面(Attack Surface)の概念
攻撃面とは、攻撃者がシステムにアクセスできる全てのポイントの総称です。 公開ポートが多いほど攻撃面が広がり、セキュリティリスクが増大します。
2-3
最小限のポート公開
80, 443 のみ
4-6
要確認
不要なポートの確認推奨
7+
攻撃面が広い
即座に対応が必要
実際の被害事例
ポート公開による攻撃事例
MongoDB ランサムウェア攻撃(2017年)
認証なしで外部公開されたMongoDBインスタンスを対象とした大規模なランサムウェア攻撃が発生。28,000以上のデータベースが攻撃者によってデータを削除され、身代金を要求されました。ポート27017がファイアウォールで適切に制限されていれば防げた攻撃です。
Redis 無認証アクセスによるサーバー乗っ取り
ポート6379が外部公開され、認証なしでアクセス可能なRedisサーバーが多数発見されています。攻撃者はRedisのCONFIG SETコマンドを使用してSSH公開鍵を書き込み、サーバーへのroot権限でのアクセスを確立する手法が広く知られています。
Elasticsearch 大規模データ漏洩
ポート9200が外部公開されたElasticsearchクラスターから、10億件以上の個人情報が漏洩した事例が複数報告されています。メールアドレス、パスワード、社会保障番号などが認証なしで閲覧可能な状態でした。
検出メカニズム
Security Scannerの検出方法
TCP接続テスト
Node.jsのnetモジュールを使用して、対象ホストの各ポートに対してTCP接続を試行。短いタイムアウト設定で効率的にスキャンします。
ポート状態の判定
接続成功(open)、接続拒否(closed)、タイムアウト(filtered)の3つの状態を判定します。
サービスの推定
開いているポート番号から動作しているサービス(MySQL、PostgreSQL、Redis等)を推定します。
リスク評価
ポートの種類(データベース/開発用/管理用)と公開状態に基づいてリスクレベルを判定。データベースポートの公開は最高リスクとして報告。
改善提案の生成
検出された不要なポート公開に対して、ファイアウォール設定やセキュリティグループの修正方法を提案します。
修正方法
不要ポートの閉鎖方法
1. UFW(Ubuntu Firewall)
# UFW を有効化
sudo ufw enable
# 必要なポートのみ許可
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
# データベースポートはlocalhostのみに制限
sudo ufw deny 3306 # MySQL
sudo ufw deny 5432 # PostgreSQL
sudo ufw deny 27017 # MongoDB
sudo ufw deny 6379 # Redis
# 開発用ポートをブロック
sudo ufw deny 3000
sudo ufw deny 8080
# 現在のルールを確認
sudo ufw status verbose2. AWS Security Groups
# AWS CLI - Security Group の設定例
# Webサーバー用セキュリティグループ
aws ec2 create-security-group \
--group-name web-server-sg \
--description "Web server security group"
# HTTP/HTTPS のみ許可
aws ec2 authorize-security-group-ingress \
--group-name web-server-sg \
--protocol tcp --port 80 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress \
--group-name web-server-sg \
--protocol tcp --port 443 --cidr 0.0.0.0/0
# SSHは特定IPのみ許可
aws ec2 authorize-security-group-ingress \
--group-name web-server-sg \
--protocol tcp --port 22 --cidr 203.0.113.0/323. データベースのバインドアドレス設定
ファイアウォールに加え、データベース自体の設定でlocalhostのみリッスンするよう制限します。
# MySQL - /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
bind-address = 127.0.0.1 # localhostのみリッスン
# PostgreSQL - /etc/postgresql/15/main/postgresql.conf
listen_addresses = 'localhost' # localhostのみリッスン
# MongoDB - /etc/mongod.conf
net:
bindIp: 127.0.0.1 # localhostのみリッスン
# Redis - /etc/redis/redis.conf
bind 127.0.0.1
protected-mode yesマネージドサービスの活用
Supabase、PlanetScale、Neon等のマネージドデータベースサービスを使用すると、 ポート管理が不要になり、SSL接続が標準で提供されます。 自前でデータベースサーバーを運用する場合と比較して、セキュリティリスクを大幅に低減できます。