スマート電球がネットワークの弱点になるとき
深夜にサーバーがSSHブルートフォース攻撃を受けたあと、ネットワーク全体の監査を始めた。脅威は外から来ると思っていた。しかし、すでに内側にいた。
自宅のネットワークにはスマートTV、IPカメラ3台、スマートプラグ数個、NASがあり、すべてワークステーションとHomeLabサーバーと同じサブネット上にあった。それぞれが潜在的な侵入の踏み台になりうる。カメラハブが1台でも侵害されれば、内部からスキャンする攻撃者はすべてに到達できる。止めるファイアウォールはない。
HomeLabを運用していたり、スマートホームのガジェットを少し持っているだけでも、この穴はまだ塞がれていないかもしれない。実際の対処法を説明する。
IoTデバイスがこれほど簡単に侵害される理由
根本原因は驚くほど単純だ。IoTデバイスは低コストで素早く出荷するために作られており、利益率が薄く締め切りが迫ると、セキュリティが削られる。
- 誰も変えないデフォルト認証情報:Shodanで検索すると、購入から数年経っても
admin:adminで動いているカメラが数万台見つかる。認証情報を完全にハードコードしているブランドもある。 - 一度もアップデートされないファームウェア:初期設定後に管理パネルを開くユーザーはほとんどいない。パッチは存在するが、誰もインストールしない。
- アウトバウンドフィルタリングなし:侵害されたデバイスは、C2サーバーへの通信、データ漏洩、内部ネットワークのスキャンを行う可能性がある。デフォルトのルーター設定ではこれを一切ブロックしない。
- フラットなネットワーク構成:すべてのデバイスが同じサブネットを共有していると、ラテラルムーブメントが容易になる。1つの侵害が内部への完全なアクセスを意味する。
最悪なのは、気づかないことだ。2016年のMiraiボットネットは、静かに60万台以上のデバイスに感染し、DDoS軍に動員した。ISPがトラフィックを検知するまで、所有者は何も知らなかった。現代の亜種も同じことをしており、バックグラウンドで暗号通貨マイナーや認証情報窃取ツールを静かに動かしている。
3つのアプローチと、そのうち2つが不十分な理由
オプション1:デフォルトパスワードを変えるだけ
必要だが十分ではない。最も基本的なクレデンシャルスタッフィング攻撃は防げる。しかし、ファームウェアの脆弱性、ラテラルムーブメント、不正なアウトバウンド通信はまったく対処できていない。玄関の鍵をかけながら、すべての窓を開け放っているようなものだ。
オプション2:セグメンテーションなしのファイアウォールルール
中級ルーターなら、フラットネットワーク上のデバイス間にACLルールを作れることが多い。スマートTVがNASに直接アクセスするのをブロックできる——ないよりはマシだ。しかし、共有サブネット上でデバイスごとのルールを管理するとすぐに複雑になる。1つの設定ミスがサイレントに分離を破壊し、デバイス間のトラフィックパターンへの可視性がまったく失われる。
オプション3:VLANセグメンテーション + アウトバウンドフィルタリング + ファームウェア監視
このアプローチは3つの制御を組み合わせる。IoTデバイスを専用VLANに分離し、アウトバウンドトラフィックをデバイスが実際に必要なものだけに制限し、ファームウェアバージョンチェックを自動化する。マネージドスイッチとVLANをサポートするルーター——pfSense、OPNsense、またはUniFiゲートウェイなど——が必要だ。メリットは明確だ:何が何と通信しているかが正確にわかり、1つのレイヤーを突破しても次のレイヤーに当たる。
オプション3はあらゆる指標——分離、可視性、スケーラビリティ——で優れている。構築方法を説明する。
多層防御のIoTセキュリティ構成
ステップ1:IoT VLANの作成と分離
pfSense(またはOPNsense——概念は同じ)を使って、IoTトラフィック用の新しいVLANを作成する。VLANタグ20とサブネット 192.168.20.0/24 を使用する。
# pfSense: Interfaces → Assignments → VLANs → Add
# VLANタグ: 20
# 親インターフェース: LANポート(例: igb1)
# 説明: IoT_VLAN
インターフェースを割り当て、192.168.20.0/24 のDHCPを設定し、ファイアウォールルールを追加する。2つのルールで機能する:
# pfSense ファイアウォールルール — IoT_VLANインターフェース
# ルール1: IoT → LANをブロック(メインの 192.168.1.0/24)
# アクション: Block | 送信元: IoT_VLAN net | 宛先: LAN net
# ルール2: IoT → インターネットのみ許可
# アクション: Pass | 送信元: IoT_VLAN net | 宛先: !RFC1918
# pfSense組み込みのRFC1918エイリアスは 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16 をカバー
マネージドスイッチで、IoTデバイスのポートをVLAN 20にタグ付けする:
# マネージドスイッチのCLI(Cisco IOSスタイル——ベンダーにより構文が異なる)
vlan database
vlan 20 name IoT
interface range GigabitEthernet0/5-8
switchport mode access
switchport access vlan 20
Wi-Fiは、VLAN 20にマッピングされた専用SSIDを作成する。UniFiの場合、Networks → Create New Network → VLAN Onlyで設定し、新しいワイヤレスネットワークに割り当てる。IoTデバイスはそのSSIDに接続し、メインLANには見えない。
ステップ2:ファームウェアバージョン監視の自動化
手動チェックは機能しない——1週間で忘れる。デバイスAPIにバージョン情報をポーリングして変化を通知するスクリプトは、セットアップに1時間かかるだけで、その後はずっと動き続ける。
import requests
import smtplib
from email.mime.text import MIMEText
# ファームウェアを意図的に更新した際はこのdictを更新すること
KNOWN_VERSIONS = {
"camera_livingroom": "2.4.1",
"smart_tv": "1.8.0",
}
def check_firmware(device_name, device_url, known_version):
try:
# verify=False は意図的——LANデバイスは自己署名証明書を使うことが多い
resp = requests.get(device_url, timeout=5, verify=False)
data = resp.json()
live_version = data.get("firmware_version", "unknown")
if live_version != known_version:
return f"[ALERT] {device_name}: {known_version} → {live_version}"
return None
except Exception as e:
return f"[ERROR] {device_name}: チェック失敗 ({e})"
def send_email_alert(alerts, smtp_host, smtp_port, username, password, to_addr):
body = "\n".join(alerts)
msg = MIMEText(body)
msg["Subject"] = "ファームウェアバージョンの変更を検出"
msg["From"] = username
msg["To"] = to_addr
with smtplib.SMTP_SSL(smtp_host, smtp_port) as server:
server.login(username, password)
server.sendmail(username, to_addr, msg.as_string())
if __name__ == "__main__":
# 各デバイスの実際のAPIパスに合わせてエンドポイントを調整すること
devices = [
("camera_livingroom", "http://192.168.20.5/api/version", KNOWN_VERSIONS["camera_livingroom"]),
("smart_tv", "http://192.168.20.10/status", KNOWN_VERSIONS["smart_tv"]),
]
alerts = [check_firmware(n, u, v) for n, u, v in devices]
alerts = [a for a in alerts if a]
if alerts:
print("\n".join(alerts))
# メールアラートを有効にする場合はコメントを外す:
# send_email_alert(alerts, "smtp.gmail.com", 465, "[email protected]", "app_password", "[email protected]")
毎日のcronジョブとしてスケジュールする:
crontab -e
# この行を追加:
0 8 * * * /usr/bin/python3 /home/user/scripts/check_firmware.py >> /var/log/firmware_check.log 2>&1
すべてのデバイスがきれいなAPIを提供しているわけではない——WebUIをスクレイピングする必要があるものや、メーカーのリリースページを手動で確認する必要があるものもある。一度設定するのは面倒だが、その後は自動で動く。
ステップ3:不審なアウトバウンド接続の検出
VLANの分離はラテラルムーブメントを防ぐが、IoTデバイスはまだインターネットに接続する。侵害されたデバイスは、ポート4444のC2サーバーにビーコンを送ったり、見慣れないクラウドIPにデータを漏洩させたり、正規のトラフィックとはまるで違う深夜3時のDNSクエリを実行したりする可能性がある。2つの方法でこれを検出できる。
方法A——Pi-holeによるDNSシンクホール:IoT VLANのDHCP DNSをPi-holeインスタンスに向ける。既知の悪意あるドメインへのクエリは自動的にブロックされ、ログに記録される。
# pfSenseのIoT_VLAN DHCPサーバーの設定:
# DNSサーバー1: 192.168.20.2 (IoTセグメント上のPi-hole IP)
# Pi-holeでクエリログをリアルタイム監視するには:
pihole -t
# または統計ダッシュボードを開く:
pihole -c
方法B——パケットキャプチャによるベースライン:新しいデバイスを追加した後、監視ホストで24〜48時間 tcpdump を実行する。デバイスが通常どこに接続するかの全体像を把握できる。将来の異常はそのベースラインに対して明確に目立つ。
# IoTのアウトバウンドトラフィックをキャプチャ(3つのRFC1918範囲をすべてカバー)
sudo tcpdump -i eth0 -nn \
'src net 192.168.20.0/24 and dst net not (192.168.0.0/16 or 10.0.0.0/8 or 172.16.0.0/12)' \
-w /tmp/iot_baseline.pcap
# キャプチャ後、宛先IPを頻度でまとめる:
# tcpdump -nn の出力では、フィールド5が宛先IP:ポート
tcpdump -r /tmp/iot_baseline.pcap -nn \
| awk '{print $5}' | cut -d. -f1-4 \
| sort | uniq -c | sort -rn | head -20
深夜3時にポート4444で不明なIPに接続しているカメラは、ファームウェアの更新をチェックしているわけではない。不審なものはブロックするかどうか判断する前に、VirusTotalやAbuseIPDBで確認すること。
新しいIoTデバイスごとに使うチェックリスト
インフラが整えば、新しいデバイスの追加には10分もかからない:
- どのネットワークにも接続する前にデフォルト認証情報を変更する——可能であればオフラインで。
- IoT SSID(VLAN 20)に接続する——メインLANには絶対に接続しない。
- デバイスの現在のファームウェアバージョンを監視スクリプトに追加する。
- 24時間Pi-holeのログを監視し、不審なドメインをすぐにブロックする。
- アウトバウンドルールを厳しくする:ほとんどのデバイスはポート80と443だけが必要だ。それ以外はすべてVLANファイアウォールレベルでロックする。
初期セットアップには数時間かかる。その後は新しいデバイスを追加するたびに数分で済む——ガジェットが増えるほど積み重なっていく。
あの深夜のSSH事件の後では、事前に数時間かけるほうが、深夜2時にアクティブな侵害に対処するよりずっとましだと思う。
本当の教訓はこうだ:IoTセキュリティとは、すべてのデバイスが正しく動作すると信頼することではない。メーカーのファームウェアの決定は変えられない。1つのデバイスが失敗したとき、被害がHomeLab全体に広がらずに単一のVLAN内に留まるよう、ネットワークを設計することだ。それこそがセグメンテーションが本当にもたらすものだ。
