PowerShellでWebサーバーのセキュリティ対策を自動化した話
PowerShellでWebサーバーのセキュリティ対策を自動化した
旧サーバーで実施したセキュリティ対策を新しく構築するサーバー(2台)でも実施する必要があった.
対策を手で2台もやるのはめんどくさい大変なのでスクリプトで自動化した.
実現したこと
- SSL証明書をインポートし, HTTPS通信を有効にする.
- レジストリを編集し, 脆弱な暗号化方式を無効にする.
- セキュリティ診断対応済みの設定ファイルをIISのルートディレクトリに配備し, 以下の脆弱性を解消する.
- urlscanをインストールし, 推奨されないHTTPメソッドを無効にする.
スクリプト
構成
ResolveVulnerability ┣Functions ┃┣Deploy-WebConfig.ps1 ┃┣Disable-Encryption.ps1 ┃┣Enable-SSL.ps1 ┃┣Install-UrlScan.ps1 ┃┣Remove-IISDefaultItems.ps1 ┃┗Restart-IIS.ps1 ┣Certificate ┃┗certificate.pfx ┣Config ┃┣UrlScan.ini ┃┗web.config ┣Installer ┃┗urlscan_v31_x64.msi ┗Script ┣Config.ps1 ┣Index.ps1 ┗Resolve-Vulnerability.ps1
実行方法
管理者権限でPowerShellを起動して下記コマンドを実行するだけ.
Set-Location C:\ResolveVulnerability .\Resolve-Vulnerability.ps1
ただ, インポートするSSL証明書は事前に用意してね.
中身
Resolve-Vulnerability.ps1でFunctions内の関数を呼ぶ感じ. Resolve-Vulnerability.ps1ではIndex.ps1を読み込む.
Resolve-Vulnerability.ps1
. ("{0}/Index.ps1" -f (Split-Path $MyInvocation.MyCommand.Path -Parent)) # SSL証明書をインポートし, https通信を有効にする Enable-SSL -CertPath $CertPath -CertPass $CertPass -TargetSite $TargetSite # 脆弱な暗号化方式を無効化する # Protocols Disable-Encryption -Key $SSL2Server Disable-Encryption -Key $SSL2Client Disable-Encryption -Key $SSL3Server Disable-Encryption -Key $SSL3Client # Cipher Disable-Encryption -Key $CiphersNULL Disable-Encryption -Key $DES Disable-Encryption -Key $RC2_40 Disable-Encryption -Key $RC2_56 Disable-Encryption -Key $RC2_128 Disable-Encryption -Key $RC4_40 Disable-Encryption -Key $RC4_56 Disable-Encryption -Key $RC4_128 Disable-Encryption -Key $RC4_64 Disable-Encryption -Key $3DES # Hashes Disable-Encryption -Key $MD5 # KeyExchangeAlgorithms Disable-Encryption -Key $DiffieHellman # レジストリの設定を有効にするためIISを再起動する Restart-IIS $IISSvcName <# IISのルートディレクトリにWeb.configを配備することで下記セキュリティ対策を実施する ・セキュリティ上推奨されるHTTPヘッダーを付加する ・規定のドキュメントを無効にする(デフォルトのページが非表示になる) ・ディレクトリリスティングを無効にする #> Deploy-WebConfig -WebConfigSrc $WebConfigSrc -IISRoot $IISRoot -WebConfigFile $WebConfigFile # デフォルトのiisページを消す Remove-IISDefaultItems $IISDefaultItems # urlscanインストールして設定ファイル置換する Install-UrlScan -UrlScanInstaller $UrlScanInstaller -UrlScanConfigSrc $UrlScanConfigSrc -UrlScanConfigDst $UrlScanConfigDst -UrlScanConfigFile $UrlScanConfigFile
Index.ps1ではConfig.ps1とFunctions内のスクリプトを一括で読み込む.
Index.ps1
Set-Variable -Name BVIndexRoot -Value (Split-Path $MyInvocation.MyCommand.Path -Parent) -Option Constant # 設定ファイル . ("{0}\Config.ps1" -f $BVIndexRoot) # 関数 Set-Variable -Name BVFunctionsRoot -Value ("{0}\Functions" -f $BVIndexRoot) -Option Constant Get-ChildItem -Path $BVFunctionsRoot | ForEach-Object { . ("{0}\{1}" -f $BVFunctionsRoot, $_)}
Config.ps1に設定をまとめる.
Config.ps1
# スクリプトのパス Set-Variable -Name RVConfRoot -Value (Split-Path $MyInvocation.MyCommand.Path -Parent) -Option Constant #-- 証明書インポート/HTTPS有効 start --# # 証明書のパス Set-Variable -Name CertPath -Value ("{0}\Certificate\certificate.pfx" -f $RVConfRoot) -Option Constant # 証明書のパスワード Set-Variable -Name CertPass -Value "1qwertyuiop@" -Option Constant # HTTPS通信の対象サイト Set-Variable -Name TargetSite -Value "Default Web Site" -Option Constant #-- 証明書インストール/HTTPS有効 end --# #-- 脆弱性のある暗号化方式対策 start --# # Protocols Set-Variable -Name SSL2Server -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server' -Option Constant Set-Variable -Name SSL2Client -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client' -Option Constant Set-Variable -Name SSL3Server -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server' -Option Constant Set-Variable -Name SSL3Client -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client' -Option Constant # Ciphers Set-Variable -Name CiphersNULL -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\NULL' -Option Constant Set-Variable -Name DES -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\DES 56\56' -Option Constant Set-Variable -Name RC2_40 -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC2 40/128' -Option Constant Set-Variable -Name RC2_56 -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC2 56/128' -Option Constant Set-Variable -Name RC2_128 -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC2 128/128' -Option Constant Set-Variable -Name RC4_40 -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 40/128' -Option Constant Set-Variable -Name RC4_56 -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 56/128' -Option Constant Set-Variable -Name RC4_128 -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 128/128' -Option Constant Set-Variable -Name RC4_64 -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 64/128' -Option Constant Set-Variable -Name 3DES -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\Triple DES 168' -Option Constant # Hashes Set-Variable -Name MD5 -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes\MD5' -Option Constant # KeyExchangeAlgorithms Set-Variable -Name DiffieHellman -Value 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman' -Option Constant #-- 脆弱性のある暗号化方式対策 end --# #-- IISサービス設定 start --# # IISサービス名 Set-Variable -Name IISSvcName -Value 'W3SVC' -Option Constant #-- IISサービス設定 end --# #-- Web.config配置設定 start --# # セキュリティ上推奨されるHTTPヘッダーを追加するWeb.configのディレクトリ Set-Variable -Name WebConfigSrc -Value ('{0}\Config' -f $RVConfRoot) -Option Constant # セキュリティ上推奨されるHTTPヘッダーを追加するWeb.config Set-Variable -Name WebConfigFile -Value 'web.config' -Option Constant # IISのルートディレクトリ Set-Variable -Name IISRoot -Value 'C:\inetpub\wwwroot' -Option Constant #-- Web.config配置設定 end --# #-- 削除するIISデフォルトアイテム start --# # IISのデフォルトアイテム一覧 $IISDefaultItems = @(('{0}\iis-85.png' -f $IISRoot), ('{0}\iisstart.htm' -f $IISRoot)) Set-Variable IISDefaultItems -Option ReadOnly #-- 削除するIISデフォルトアイテム end --# #-- Web.config配置設定 start --# # urlscanのインストーラー Set-Variable -Name UrlScanInstaller -Value ('{0}\Installer\urlscan_v31_x64.msi' -f $RVConfRoot) -Option Constant # UrlScan設定ファイルのディレクトリ Set-Variable -Name UrlScanConfigSrc -Value ('{0}\Config' -f $RVConfRoot) -Option Constant # UrlScan設定ファイルの配置先 Set-Variable -Name UrlScanConfigDst -Value 'C:\Windows\System32\inetsrv\urlscan' -Option Constant # UrlScan設定ファイル Set-Variable -Name UrlScanConfigFile -Value 'UrlScan.ini' -Option Constant #-- Web.config配置設定 end --#
あとは関数たち.
Deploy-WebConfig.ps1ではIISのルートディレクトリにセキュリティ診断対策を施した設定ファイルを置くだけ.
Deploy-WebConfig.ps1
function Deploy-WebConfig() { <# .SYNOPSIS Web.configを配備します. .DESCRIPTION IISのルートディレクトリにセキュリティ上推奨されるHTTPヘッダーを付加するようになります. 規定のドキュメントを無効にします. #> Param( $WebConfigSrc, $IISRoot, $WebConfigFile ) Robocopy.exe $WebConfigSrc $IISRoot $WebConfigFile }
Disable-Encryption.ps1ではレジストリを弄って脆弱性のある暗号化方式を無効にする.
Disable-Encryption.ps1
function Disable-Encryption() { <# .SYNOPSIS 指定したキーの暗号化を無効化します. #> Param( $Key ) New-Item $Key -Force New-ItemProperty -path $Key -name Enabled -value 0 –PropertyType DWORD if($Key.Contains("SSL")){ # SSLはDisabledByDefaultも設定する New-ItemProperty -path $Key -name DisabledByDefault -value 1 –PropertyType DWORD } }
Enable-SSL.ps1ではSSL証明書をインポートしてHTTPSの443にバインドする.
Enable-SSL.ps1
function Enable-SSL(){ <# .SYNOPSIS SSL証明書をインポートし, https通信を有効にします. #> Param( $CertPath, $CertPass, $TargetSite ) # 証明書をインポートする $cert = Import-PfxCertificate -Filepath $CertPath -Password (ConvertTo-SecureString $CertPass -AsPlainText -Force) -CertStoreLocation "Cert:\LocalMachine\My" -Exportable # IISに443httpsバインドを作成する New-WebBinding -Name $TargetSite -IP "*" -Port 443 -Protocol https # httpsバインドを取得し証明書を設定する $httpsBinding = Get-WebBinding -Protocol https $httpsBinding.AddSslCertificate($cert.GetCertHashString(),"my") }
Install-UrlScan.ps1ではUrlScanをインストールして, 設定ファイルを置き換える.
Install-UrlScan.ps1
function Install-UrlScan() { <# .SYNOPSIS urlscanをインストールしセキュリティ対策を施した設定ファイルに置き換えます. #> Param( $UrlScanInstaller, $UrlScanConfigSrc, $UrlScanConfigDst, $UrlScanConfigFile ) $process = Start-Process -FilePath "msiexec.exe" -ArgumentList ("/i {0} /passive" -f $UrlScanInstaller) -Verb runas -PassThru Wait-Process -Id ($process.Id) Rename-Item -Path ("{0}\{1}" -f $UrlScanConfigDst, $UrlScanConfigFile) -NewName ("_{0}" -f $UrlScanConfigFile) -Force Robocopy.exe $UrlScanConfigSrc $UrlScanConfigDst $UrlScanConfigFile }
Remove-IISDefaultItems.ps1ではIISをインストールした際にデフォルトで置かれているアイテムを削除する.
Remove-IISDefaultItems.ps1
function Remove-IISDefaultItems() { <# .SYNOPSIS IISのデフォルトページや画像を削除します. #> Param( $Items ) foreach($item in $Items) { if(Test-Path $item){ Remove-Item -Path $item -Force } } }
Restart-IIS.ps1ではIISを再起動する. わざわざ関数にしなくても
Restart-IIS.ps1
function Restart-IIS() { <# .SYNOPSIS IISを再起動します. #> Param( $SvcName ) Restart-Service $SvcName }
Web.configの中身
- defaultDocumentで規定のドキュメントを無効にする(本番環境にデフォルトのページはいらない).
- directoryBrowseでディレクトリリスティング(ブラウザにディレクトリ構造見せちゃうヤツ)を無効にする.
- customHeadersで推奨されるHTTPヘッダーを追加する.
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.web> <httpRuntime enableVersionHeader="false" /> </system.web> <system.webServer> <defaultDocument enabled="false" /> <directoryBrowse enabled="false" /> <httpProtocol> <customHeaders> <clear/> <remove name="X-Powered-By"/> <add name="X-XSS-Protection" value="1; mode=block"/> <add name="X-Frame-Options" value="DENY"/> <add name="X-Content-Type-Options" value="nosniff"/> </customHeaders> </httpProtocol> </system.webServer> </configuration>
UrlScan.iniの中身
- OPTIONSを明示的に無効にする(Webサーバーが許可しているメソッドが表示されちゃうからね).
[AllowVerbs] ; ; The verbs (aka HTTP methods) listed here are those commonly ; processed by a typical IIS server. ; ; Note that these entries are effective if "UseAllowVerbs=1" ; is set in the [Options] section above. ; GET HEAD POST [DenyVerbs] ; ; The verbs (aka HTTP methods) listed here are used for publishing ; content to an IIS server via WebDAV. ; ; Note that these entries are effective if "UseAllowVerbs=0" ; is set in the [Options] section above. ; PROPFIND PROPPATCH MKCOL DELETE COPY MOVE LOCK UNLOCK SEARCH PUT OPTIONS