はじめに
「セキュリティが強化されたWindowsDefenderファイアウォール(以下ファイアウォール)」を設定する必要があったので調査したのですが、大変理解に苦労したのでまとめておきます。
環境と手法について
調査には Windows 10 を利用しました。systeminfo
の出力は以下の通り。
C:\> systeminfo
...
OS 名: Microsoft Windows 10 Pro
OS バージョン: 10.0.16299 N/A ビルド 16299
...
またファイアウォールの設定には PowerShell を使用しました。PowerShellのバージョンは以下の通り。
PS> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.16299.98
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.16299.98
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
設定したい内容について
主に受信するトラフィックの制御について考えます。制御方法については、接続元IPアドレスとローカルのポート番号でフィルタする方針です。IPsecは扱わないこととします。
ファイアウォールを扱うコマンドレット
PowerShell の良いところは、関連しそうなコマンドレットに心あたりが無くても、以下のように適当なキーワードで関連するコマンドレットの一覧を得られるところです。コマンドをワイルドカードで検索できるのが大変便利です。get-command
が冗長すぎると感じるのであれば、代わりに help
で同等の出力を得ることができます。
PS> get-command -name *firewall* | select name
Name
----
Copy-NetFirewallRule
Disable-NetFirewallRule
Enable-NetFirewallRule
Get-NetFirewallAddressFilter
Get-NetFirewallApplicationFilter
Get-NetFirewallInterfaceFilter
Get-NetFirewallInterfaceTypeFilter
Get-NetFirewallPortFilter
Get-NetFirewallProfile
Get-NetFirewallRule
Get-NetFirewallSecurityFilter
Get-NetFirewallServiceFilter
Get-NetFirewallSetting
New-NetFirewallRule
Remove-NetFirewallRule
Rename-NetFirewallRule
Set-NetFirewallAddressFilter
Set-NetFirewallApplicationFilter
Set-NetFirewallInterfaceFilter
Set-NetFirewallInterfaceTypeFilter
Set-NetFirewallPortFilter
Set-NetFirewallProfile
Set-NetFirewallRule
Set-NetFirewallSecurityFilter
Set-NetFirewallServiceFilter
Set-NetFirewallSetting
Show-NetFirewallRule
Firewall.cpl
ファイアウォールの規則について
Windowsのファイアウォールは、一般的なファイアウォールと同様に「受信の規則(Inbound)」と「送信の規則(Outbound)」という通信方向ごとにトラフィックを制御できます。これらの制御にはデフォルトの挙動が設定されており、受信は基本的にブロック、送信は全て許可となっています1。
受信の規則を「基本的に」ブロックとしたのは、既に規則が追加されている場合があるからです。一部の通信については、Windowsインストール時から許可されているので、思わぬセキュリティホールを残してしまわないように注意が必要です。一方、送信の規則については最初から追加されている規則は通信を許可する規則ばかりなので、特に要件が無い場合は気にすることはないと思います。
ファイアウォールの規則は、複数のフィルターを組み合わせたものが一つの規則を構成します。各フィルターは AND 条件であり、全てのフィルターにマッチしたトラフィックを許可またはブロックすることができます。利用できるフィルターは以下の 7 種類です。
- AddressFilter
- ServiceFilter
- ApplicationFilter
- InterfaceFilter
- InterfaceTypeFilter
- PortFilter
- SecurityFilter
特徴的な点としては、サービス単位やアプリケーション単位でトラフィックを制御できる点です。汎用的なネットワーク機器としてのファイアウォールには無い機能だと思います。
ファイアウォールの規則の確認
ファイアウォールの規則は、複数のフィルターの組み合わせにより構成される、という点を念頭に実際の設定を確認してみます。
ファイアウォールの規則を確認するコマンドレットは Get-NetFirewallRule
です。名前を指定しない場合は全ての規則が出力されます。
PS> Get-NetFirewallRule -Name Netlogon-TCP-RPC-In
Name : Netlogon-TCP-RPC-In
DisplayName : Netlogon サービス Authz (RPC)
Description : RPC/TCP 経由のリモート authz 要求を処理するための、NetLogon サービスの受信規則です。
DisplayGroup : Netlogon サービス
Group : @netlogon.dll,-1010
Enabled : False
Profile : Any
Platform : {}
Direction : Inbound
Action : Allow
EdgeTraversalPolicy : Block
LooseSourceMapping : False
LocalOnlyMapping : False
Owner :
PrimaryStatus : OK
Status : 規則は、ストアから正常に解析されました。 (65536)
EnforcementStatus : NotApplicable
PolicyStoreSource : PersistentStore
PolicyStoreSourceType : Local
見ての通りですが、これは規則の名前(DisplayName)や操作(Action)についての情報が含まれていますが、フィルターに関する情報が表示されていません(主にフィルタの情報が欲しいのに)。フィルタに関する情報を得るためには、この規則を更に別のコマンドレットに通す必要があります。例として PortFilter と ApplicationFilter を表示する場合を挙げます。
PS> $rule = Get-NetFirewallRule -Name Netlogon-TCP-RPC-In
PS>
PS> $rule | Get-NetFirewallPortFilter
Protocol : TCP
LocalPort : RPC
RemotePort : Any
IcmpType : Any
DynamicTarget : Any
PS> $rule | Get-NetFirewallApplicationFilter
Program : %SystemRoot%\System32\lsass.exe
Package :
何となく理解できるかと思うのですが、ファイアウォールに定義されている全ての規則(フィルター)を参照したいときは、少なくとも 「規則の数」×「フィルターの数(7)」
のコマンドレットを実行する必要があります。実際は簡単なスクリプトにするはずなので問題にはならないと思うものの面倒極まりないので、普段は Show-NetFirewallRule
コマンドレットを使うべきです。Show-NetFirewallRule
は、融通が効かないコマンドレットですがファイアウォールの規則を全量表示するいう点では役に立ちます。
更に考慮するのであれば、「名前を指定して実行」に「wf.msc」と入力して表示された画面で「一覧のエクスポート」をクリックし CSV ファイルに出力してから参照する方法を検討するべきです。その方が、機械的に比較しやすいフォーマットになると思われるのでおすすめです(手作業になってしまいますが)。
ファイアウォールの規則を作成・編集する
ファイアウォールの規則を新しく作成するには New-NetFirewallRule
を使います。既存の規則を編集したいときは Get-NetFirewallRule
で規則への参照を得ます。
New-NetFirewallRule
で規則を作成するときに最低限必要なパラメータは DisplayName
だけです。規則はデフォルトで「受信の規則」に「許可」で作成されます2。
この時、ブロックするルールを定義しようとして -Action Block
と指定しない方が賢明です。新しく作成された規則はデフォルトで RemoteAddress Any
のフィルターを持つので、コマンドレットを実行した直後に全てのリモート通信がブロックされてしまいます。リモート接続している際に、ブロックの規則を作成する必要に迫られた場合は -Enable False
を付けておく方が安全と思われます。
それでは、例として新しく規則「Test Rule」を作成してみます。
PS> $NewRule = New-NetFirewallRule -DisplayName "Test Rule" -Enable False
PS> $NewRule
Name : {f7f4a226-e800-48cf-832a-eb496fc93436}
DisplayName : Test Rule
Description :
DisplayGroup :
Group :
Enabled : True
Profile : Any
Platform : {}
Direction : Inbound
Action : Allow
EdgeTraversalPolicy : Block
LooseSourceMapping : False
LocalOnlyMapping : False
Owner :
PrimaryStatus : OK
Status : 規則は、ストアから正常に解析されました。 (65536)
EnforcementStatus : NotApplicable
PolicyStoreSource : PersistentStore
PolicyStoreSourceType : Local
この規則には何もフィルターが設定されていないので、トラフィックをフィルターするための条件を追加していく必要があります。例として Set-NetFirewallAddressFilter
を使用する場合を挙げます。
PS> $NewRule | Get-NetFirewallAddressFilter
LocalAddress : Any
RemoteAddress : Any
PS> $NewRule | Get-NetFirewallAddressFilter | Set-NetFirewallAddressFilter -RemoteAddress "10.10.10.10" -PassThru
LocalAddress : Any
RemoteAddress : 10.10.10.10
大変長いコマンドレットですが $NewRule
の AddressFilter に新しくリモートのIPアドレスをセットすることができました。セットする前に Get-NetFirewallAddressFilter
を挟む必要があることに注意が必要です。規則が持っている AddressFilter は明白(一つだけ)だと思ったのですが、PowerShell 的には違うようです。
余談ですが AddressFilter を select instanceid
すると、対応している規則を逆引きすることができました。つまり複数の AddressFilter の InstanceID
を特定の規則のIDにすると、「一つの規則に複数の AddressFilter」という状況が作れそうでした。その場合であれば Get-NetFirewallAddressFilter
を挟む必要があることは納得できます。 ただし実際にできるのか、そもそも有用なのかは分かりませんが。。。
PS> $NewRule | Get-NetFirewallAddressFilter | select InstanceID
InstanceID
----------
{f7f4a226-e800-48cf-832a-eb496fc93436}
PS> $NewRule | select ID
ID
--
{f7f4a226-e800-48cf-832a-eb496fc93436}
規則の優先順位
Linux の iptables
は「上の(先に定義された)ルールから順番に適用する」という優先順位がありました(確か)。一方で Windows のファイアウォールは、規則に指定された操作によって優先順位が異なります3。ただし、基本的には「許可よりブロックが優先」と覚えておくと良いと思います。「基本的にブロックだけど一部は許可したい」という場合は、許可する規則に「ブロックの規則より優先する」のオプションを有効にする必要があります。
終わりに
Windows のファイアウォールは構成が(Linuxと比べて)分かりづらくコマンドで設定する方法について長らく不勉強でした。今回調査したことで、大抵の要件は PowerShell で処理できることが分かったので、活用していきたいと思います。