IPv6のセキュリティを強化する

今日は、IPv6インターネットに接続した時のセキュリティ上の懸念への対策について解説します。

記事一覧

パケットフィルタリング

IPv6には「NATが無い」ことがメリットとして語られることが多々ありますが(*1)、NATが無いことにはデメリットもついてきます。それは、NAT配下では自然と禁止されていた外部から内部ネットワークへのアクセスが可能になってしまうことです。

しかし、内向きのアクセスをブロックする手段はNATだけではありません。IPv6では、NAT相当のセキュリティはパケットフィルタを使って実現することが推奨されています。以下、具体的な設定を見てゆきましょう。

まず、LANからインターネット方向の通信は許可し、逆方向の通信は禁止するフィルタを書いてみます。

filter6 add OUTGOING interface pppoe0 direction out action pass state enable
filter6 add BLOCK_IN interface pppoe0 direction in action block

OUTGOINGが外向きの通信を許し、BLOCK_INが内向きの通信を禁止するフィルタです。単純に内向きの通信をすべて禁止してしまうとTCPの通信が成立しませんから、OUTGOING には state enable パラメータを指定してステートフルインスペクションを有効にしておきます。これによって、

となります。TCP以外のプロトコルでも、UDPやICMP(ping)も同様に内→外方向のセッションが確立済みの場合だけ、応答パケットが入ってこれるようになります。

なお、上記の例はNGN IPv6にPPPoE接続で接続している環境を想定しています。L2TP IPv6接続を利用している場合は interface pppoe0 を interface ppp0と読み替えてください。

さて、せっかくアドレスが豊富にあるIPv6で接続しているのですから、LAN内にサーバホストを置きたくなることもあるかと思います。さきのフィルタでは内向きのTCP通信はすべて禁止されてしまいますので、明示的に通す設定を入れてみましょう。LAN内に 2001:db8::80 というアドレスのウェブサーバがあるものとして、そこへのアクセスを許可します。

filter6 add PASS_HTTPD interface pppoe0 direction in protocol tcp \
    dst 2001:db8::80 dstport 80 action pass top
    (実際には \ を省いて一行で入力してください)

この設定の意味は、

  1. protocol tcp でTCPプロトコルのみを指定
  2. dst 2001:db8::80 で2001:db8::80宛ての通信を指定
  3. dstport 80 で宛先ポート80番(HTTP)を指定
  4. top でフィルタのリストの先頭に追加

となります。

最後の top がなぜ必要かはちょっとわかりにくいので補足します。SEILのパケットフィルタ(filter6)はいちばん最初の設定から順番に評価され、一致したものが見つかったところでそのフィルタが適用されます。top を指定しない場合はfilter6の設定のいちばん最後に追加されるため、PASS_HTTPDフィルタより先にBLOCK_INフィルタが適用されてパケットがブロックされてしまいます。そのため top を指定して、既存のフィルタより前に設定を足してやる必要があります。なお、投入したフィルタの順番がどうなっているかは show config filter6 コマンドで確認してください。

filter6コマンドでは、他にもさまざま条件が設定できます。コマンドリファレンスのfilter6コマンドの項を参考に試してみてください。

Unicast RPF

ネットワーク機器やサーバのアクセス制御では、「ソースアドレスがこれこれの場合」や「ソースアドレスがこれこれのネットワークに属している場合」といった条件を設定することがままあります。しかし、このようなアドレスベースのアクセス制御はIPアドレスを偽装されると回避されてしまいます。

ソースIPアドレスの偽装の対策としては、信用できるネットワーク(LAN)と信用できないネットワーク(Internet)の境界となるルータで偽装パケットを叩き落とすことが基本です。SEILではfilter6コマンドでそのような設定が可能ですが、Unicast RPF機能を使うともっとかんたんに設定できます。

Unicast RPFは、ルーティングの設定に応じてパケットフィルタリングを行う仕組みです。ルータは静的ルーティングや動的ルーティングプロトコルを使って「これこれのアドレスはこのインタフェースまたは次ホップルータの先にある」というネットワークの構成を表す経路表(ルーティングテーブル)を構築します。その上で、各パケットのディスティネーションアドレスを経路表に照し合わせつつパケットを転送してゆきます。

ここで構築された経路表をソースIPアドレスの偽装のチェックに使ってしまおうというのがUnicast RPFのアイデアです。たとえば、以下のようなネットワークがあったとします。

この時、SEILの経路表は

となっています。

この状態でPPPoE0から「ソースIPアドレスが2001:db8:1000::dead:beef」というパケットが入ってくることは通常ありえません。すなわち、もしそのようなパケットが入ってきた場合にはソースIPアドレスが詐称されているのであろうと判断し、そのパケットは叩き落としてしまって良いでしょう。もう少し具体的な言葉に直すと、「入力パケットのソースIPアドレスを経路表で探索し、得られた出力インタフェースとパケットが入ってきたインタフェースが一致しない場合は詐称と判断する」のがUnicast RPFです。

IPv6 Unicast RPF機能の設定自体はかんたんで、以下の一行だけです。

option ipv6 unicast-rpf strict logging on

もし詐称されたパケットが入ってきたら、そのパケットを叩き落としつつ(unicast-rpf strict)、ログに詐称されたパケットのソースIPアドレスと入ってきたインタフェースを出力します(logging on)。

なお、ルーティングを元にパケットフィルタリングを行うUnicast RPFには弱点もあります。たとえば、非対称経路があったり、ポリシールーティングなどの特殊なルーティングを行っている場合です。その場合、経路表とは矛盾したように見える正規のパケットが入ってくる可能性がありますから、Unicast RPFで期待通りのフィルタリングが行えないことがあります。

続きは...

最後に、SEILのコンフィグをTELNETではなくSSH経由で行う方法を... と思いましたが、記事が予想より長くなってしまったのでこちらは後日掲載します。

*1: ちなみに「IPv6にNATが無い」というのは実は誤りです。IETFではIPv6 NATの標準化作業が進行中ですし、SEILにもIPv6 NAT機能(nat6コマンド)が搭載されています。