カフェの片隅、あるいは旅先のホテルのロビー。愛用のラップバックを開き、信頼できる個人向けVPNのスイッチを「オン」にする。画面の端に緑色のアイコンが点灯し、「おめでとうございます、あなたの接続は保護されています」と表示される。これで周囲の怪しいフリーWi-Fiの電波をスニッフィングされようとも、トラフィックはすべて暗号化されたトンネルを駆け巡る……。
――本当に、そう言い切れるだろうか?
Web APIの設計やインフラの根幹を支える私たちエンジニアこそ、この「安全神話」の裏側にある残酷な現実を知っておく必要がある。VPNのセッションが確立され、パケットのペイロードがAESやChaCha20で堅牢に保護されていとも簡単に世界中へルーティングされている裏で、DNS(Domain Name System)の名前解決リクエストだけが、何の保護もなくISP(インターネットサービスプロバイダー)のデフォルトサーバーへダダ漏れになっていたとしたらどうだろう。
今回は、インフラエンジニアや開発者なら絶対に押さえておかなければならない「DNSリーク(DNS Leak)」のメカニズム、そしてそれがなぜ発生するのか、パケットの挙動やOSのルーティング仕様を踏まえて徹底的に解説しよう。
—
1. なぜ「VPN接続中」にDNSが漏洩するのか?
「VPNを使っているのに、なぜDNSが漏れるのか」という疑問の答えは、OSのネットワークスタックと名前解決の優先順位(プライオリティ)にある。
私たちがブラウザで api.example.com と叩いたとき、OSはまずそのドメイン名に対応するIPアドレスを知るためにDNSクエリを飛ばさなければならない。通常、VPNクライアントソフト(OpenVPNやWireGuardベースのアプリなど)は、接続時に仮想ネットワークアダプター(TUN/TAPインターフェース)を生成し、OSのDNSサーバー設定を「VPNプロバイダーが指定するセキュアなDNSサーバー(例: 10.8.0.1 や Cloudflareの 1.1.1.1 など)」に書き換える。
しかし、以下のようなクライアント側の設定不備やOSの挙動により、この仕組みが破綻する。
1. マルチホーム環境におけるスプリットトンネルやDNSのルーティング競合
物理インターフェース(Wi-Fiや有線LAN)と仮想インターフェース(VPN)が同時に存在するとき、OSのDNSリゾルバがどちらのインターフェースへクエリを投げるべきか迷う、あるいは物理側のDHCPから降ってきたルーターのローカルIP(例: 192.168.1.1)を優先してしまう現象。
2. Windowsの「Smart Multi-Homed Name Resolution」の悪戯
Windows 10/11には、名前解決のスピードを上げるために複数のDNSサーバーに対して同時にクエリを飛ばし、最初に応答があったものを採用する機能がある。これが原因で、VPN側のDNSが遅延した瞬間にISP側のDNSへ平文のクエリが到達してしまう。
3. IPv6の有効化によるデュアルスタックの盲点
IPv4のVPNトンネルは完璧にはってあるのに、IPv6のトラフィックが非カプセル化のままISPのIPv6 DNSサーバーへ直行してしまう(いわゆるIPv6 DNSリーク)。
—
2. 通信フローの裏側:パケットはどこで道を間違えるのか
ここで、DNSリークが発生しているときのパケットの足取りを、典型的なシーケンスとして追ってみよう。
[Client App] [OS Network Stack] [Physical NIC (Wi-Fi)] [ISP DNS Server]
│ │ │ │
│── 1. Resolve api.example ────▶│ │ │
│ │── 2. Select DNS Server ──────▶│ │
│ │ (※設定ミスでISP側を選択) │ │
│ │ │── 3. UDP/53 (Plaintext) ─▶│
│ │ │ (パケットが暗号化されず │
│ │ │ そのまま外へ流出!) │
本来あるべき姿は、ステップ2の段階でVPNの仮想インターフェースを経由し、トンネル内で暗号化されてVPNサーバー側のリゾルバへ向かうべきなのだ。しかし、OSのルーティングテーブルやインターフェースのメトリック(優先度)が適切に設定されていないと、ステップ3のように物理NICからISPのDNSへダイレクトに突き抜けてしまう。
—
3. 実践:自分の環境でDNSリークを検知・検証する
インフラの現場で「本当にセキュアにルーティングされているか」を検証するためには、単にWebの診断サイトを見るだけでは不十分だ。CLIから確実にトラフィックと名前解決の挙動を追うスキルが求められる。
PythonによるDNSリーク簡易チェッカーの作成
例えば、Pythonの dnspython ライブラリ(pip install dnspython)を使い、現在どのDNSサーバーを経由して名前解決が行われているかをプログラムから確認するスクリプトを書くことができる。
import dns.resolver
import requests
def check_dns_and_ip():
# 1. 現在の外部グローバルIPアドレスを外部API経由で取得
try:
ip_response = requests.get("https://api.ipify.org?format=json", timeout=5)
current_ip = ip_response.json().get("ip")
except Exception as e:
current_ip = f"取得失敗: {e}"
# 2. テスト用ドメインの名前解決を実行(OSのデフォルトリゾルバを使用)
resolver = dns.resolver.Resolver()
try:
answers = resolver.resolve("whoami.akamai.net", "A")
resolved_ips = [str(rdata) for rdata in answers]
except Exception as e:
resolved_ips = [f"名前解決失敗: {e}"]
print("=== VPN & DNS 健全性チェックレポート ===")
print(f"現在のグローバルIP : {current_ip}")
print(f"名前解決されたIP(s) : {resolved_ips}")
print("----------------------------------------")
print("【確認のポイント】")
print("グローバルIPがVPNサーバーのものであっても、名前解決されたIPが")
print("契約しているISP(ドコモ光、NURO、So-net等)の管理下にある場合、")
print("DNSリークが発生しています。")
if __name__ == "__main__":
check_dns_and_ip()
このスクリプトを実行し、返ってきたIPアドレスの所有者(ASN)を調べてほしい。もしIPアドレス自体はVPNのものであっても、名前解決の応答元がISPのものであれば、あなたの閲覧履歴やアクセスしようとしているAPIのエンドポイントはISPにすべて丸見え状態になっている。
—
4. エンジニアが講じるべき決定的な対策
DNSリークを防ぐためには、クライアント側のOS設定やVPNクライアントのチューニングが不可欠だ。現場で即座に実施すべき対策をまとめる。
① ネットワークインターフェースのメトリック(優先度)の調整
複数のネットワークアダプターがある場合、VPN用の仮想アダプターのインターフェースメトリックを物理NICよりも小さく(優先度を高く)設定する。
Linux(NetworkManager等)やWindowsのネットワークアダプタープロパティから、自動メトリックをオフにし、VPN側に 1 などの低い数値を割り当てる。
② パブリックセキュアDNSのハードコードと「フォールバック」の無効化
VPNクライアントの接続設定(OpenVPNの .ovpn ファイルなど)において、明示的にDNSサーバーを指定し、かつローカルのフォールバックを禁止するディレクティブを記述する。
# OpenVPN設定ファイルの記述例
# 接続時にクライアントのDNSを強制的にセキュアなものに書き換える
dhcp-option DNS 1.1.1.1
dhcp-option DNS 8.8.8.8
# クライアント側でOSが自動的にローカルDNSを混ぜるのをブロックする
block-outside-dns
※特に block-outside-dns は、Windows環境におけるDNSリークを防ぐためのOpenVPNの強力な機能であり、実務のVPN構築では必須のパラメータとなる。
③ IPv6の適切なハンドリング
IPv6を使わない環境であれば、OSレベルでIPv6を完全に無効化するか、VPNプロバイダーがネイティブなIPv6リークプロテクション(IPv6トラフィックをトンネル内に強制カプセル化、または非対応ならブロックする機能)を備えているものを選定すること。
—
まとめ:セキュアなネットワークは細部に宿る
個人向けVPNは、単に「スイッチを入れれば魔法のように匿名化される」というおもちゃではない。その実態は、OSのルーティングテーブル、仮想インターフェース、そしてDNSの解決パスという泥臭いインフラストラクチャの上に成り立っている。
Web APIの開発やインフラの運用において、エンドポイントの秘匿性やプライバシーを守る意識を持つエンジニアであれば、「VPNをつけているから安心」ではなく、「DNSリークが起きていないことをパケットとコードで証明できる」状態を目指してほしい。
さあ、あなたのラップトップのネットワークスタックは、今この瞬間も本当に守られているか? dig コマンドやパケットキャプチャを開いて、自分の手で確かめてみるとしよう。
コメント