【実務・中級編】 DNSベースのマルウェア対策(DNSセキュリティ / Response Policy Zone: RPZ) – サイバーセキュリティとプライバシー保護実践ガイド

DNSは「最後の砦」だ。RPZでマルウェアの足元をすくう現場の戦術

ネットワークエンジニアとして現場を渡り歩いていると、完璧なセキュリティなんて幻想だと痛感する瞬間が多々ある。どれほど強固なファイアウォールを築いても、どれほど最新のEDR(Endpoint Detection and Response)を導入しても、攻撃者は常にその「隙間」を縫ってくる。

だが、忘れないでほしい。どんなに巧妙な攻撃であっても、標的となった端末が外部のC2(Command & Control)サーバーと通信するためには、必ず「名前解決」という手続きを経る必要がある。

今日解説するのは、この「DNS」という通信の根幹を逆手に取り、マルウェアの通信を未然に遮断するDNS RPZ(Response Policy Zone)の実装術だ。教科書的な理屈ではなく、泥臭いトラブルシューティングで培った「現場で効く」知見を共有しよう。

—

DNS SinkholeとRPZの正体

DNS Sinkhole(DNSシンクホール)とは、本来解決されるべき悪意あるドメインのIPアドレスを、セキュリティ機器が管理する「偽のIP(Sinkhole IP)」にすり替える手法だ。これにより、マルウェアは攻撃者のサーバーではなく、ログを監視するための「観測用サーバー」へ誘導される。

このSinkholeを動的に、かつ大規模に運用するための仕組みが「RPZ」だ。BINDやUnboundといったDNSサーバーが、特定のゾーンファイルを「ポリシー」として読み込み、再帰的なクエリに対して「このドメインは怪しいから応答を書き換えるぞ」という判断をリアルタイムで行う。

通信フローの裏側を覗く

1. 感染端末: 「悪意あるドメイン」の名前解決を要求(Aレコードクエリ)。
2. DNSサーバー(RPZ有効): クエリを受信し、キャッシュまたは上位DNSへ問い合わせる前に、RPZテーブルをルックアップ。
3. マッチング: ドメインがリストに存在すれば、あらかじめ定義されたルール(CNAMEで別のドメインへ飛ばす等)を適用。
4. 結果: 端末は攻撃者のサーバーではなく、安全な「Sinkhole」のアドレスを受け取る。マルウェアの通信は、ここで完全に遮断される。

—

BINDでの実装:現場の「設定ファイル」

理論はこれくらいにして、実際にBINDでRPZを設定してみよう。設定の肝は、ゾーンファイルに rpz という役割を持たせることだ。

named.conf への定義

# RPZ用ゾーンの定義
zone "rpz.security.local" {
    type master;
    file "/etc/bind/db.rpz.security.local";
    allow-query { none; }; # 再帰クエリを直接受け付けないように設定
};

options {
    # 再帰クエリ時にRPZを参照するように設定
    response-policy { zone "rpz.security.local"; };
};

ゾーンファイル db.rpz.security.local の記述

ここが攻撃者のドメインを封じ込める「檻」だ。

$TTL 60
@ IN SOA localhost. root.localhost. ( 1 60 60 60 60 )
  IN NS localhost.

; C2サーバーのドメインをSinkholeへ誘導
; CNAMEで自分自身やダミーのIPへ飛ばすのが定石
malicious-c2-domain.com CNAME .
another-threat.net      CNAME .

ここで CNAME . を指定すると、DNSクライアントは「そのドメインは存在しない(NXDOMAIN)」という応答を受け取る。攻撃者にとっては、DNSレベルで「通信が遮断された」という事実に気づきにくい、非常にスマートな拒絶方法だ。

—

現場のエンジニアへ:実装後のデバッグTips

RPZを導入した後、必ずぶち当たる壁がある。「誤検知(False Positive)」だ。業務システムが正規のAPI通信を行っている最中に、誤ってRPZが反応して通信が止まる。これだけは絶対に避けなければならない。

dig を使った検証手順

まずは、設定したドメインが正しくSinkholeへ誘導されているか、検証用端末から dig コマンドで確認しよう。

# 悪意あるドメインを問い合わせてみる
dig @127.0.0.1 malicious-c2-domain.com

# 正常に動作していれば、以下のように返ってくるはずだ
# ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 52345

もし意図通りに動かない場合は、tail -f /var/log/syslog(または named.run)を監視してほしい。BINDがRPZのゾーンファイルを読み込めていないか、文法ミスでゾーンを無視しているケースが多い。

API開発者が知るべきこと

Web APIの設計側としても、DNSレベルでの遮断が行われる可能性を考慮しておく必要がある。たとえば、Pythonで外部リソースを取得する際、DNS解決に失敗した場合の例外処理を丁寧に書くことだ。

import socket
import requests

def safe_request(url):
    try:
        # DNS解決を明示的に試みるなどのハンドリングを入れる
        return requests.get(url, timeout=5)
    except requests.exceptions.ConnectionError:
        # DNS解決エラー(NXDOMAIN等)をキャッチしてログに残す
        print(f"警告: DNSによる遮断または解決失敗を確認: {url}")
        return None

—

最後に:ネットワークを「守る」という心構え

RPZは魔法ではない。攻撃者は DoH (DNS over HTTPS) を使って、あなたの管理するDNSサーバーをバイパスしようと躍起になっている。

しかし、DNSレベルでの検知は、ネットワーク管理者が「今、誰が、どの悪意あるドメインと繋がろうとしているのか」を把握できる数少ないチャンスだ。このログは、セキュリティ運用において宝の山になる。

設定して終わりではない。定期的にフィードバックリスト(脅威インテリジェンス)を更新し、誤検知がないかログを眺める。そんな地味な作業の積み重ねこそが、エンタープライズのネットワークを真に堅牢なものにするのだ。

現場の戦友たちよ。今日のDNS設定が、明日の大規模なランサムウェア被害を防ぐかもしれない。そう信じて、手を動かそう。

コメント

タイトルとURLをコピーしました