Apacheをセキュアにする設定
※本記事ではApache=Apache HTTP Serverとします。
はじめに
もはやWebサービス、WebサイトにおいてHTTPS化はセキュリティ要件の前提として一般となっていて対応している人は多いと思う。しかし、せっかくHTTPSに対応したが、Webサーバーの設定がダメダメだと意味がなくなってしまう。そこで今回の記事でWebサーバーソフトウェアとして広く利用されているApacheの設定について自分なりにこうしたらいいんじゃないかというところをまとめておきたい。
メジャーな攻撃手法くらいはある程度対策しておこうというテンションで書いていくので不十分な点はあるかもしれないので、ご指摘をいただけると助かります。
また、小ネタ集的なニュアンスでセキュリティ対策ではない設定も同時にしていくので必要ない人は読み飛ばしていただけると幸いです。
設定ファイルについて
設定やっていく
不要な情報、設定の削除
デフォルトで用意されているwelcome.confなどはApacheの動作確認が完了次第必要なくなるため読み込み対象から外しておく。やり方は色々あるが、今回はファイル名を変更することで対応する。(Apacheの仕様上/etc/httpd/conf.f/*.conf
を設定ファイルとして読み込む記述がhttpd.confに書かれている)
# mv /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/welcome.conf.backup
# mv /etc/httpd/conf.d/autoindex.conf /etc/httpd/conf.d/autoindex.conf.backup
# mv /etc/httpd/conf.d/userdir.conf /etc/httpd/conf.d/userdir.conf.backup
# mv /etc/httpd/conf.modules.d/00-dav.conf /etc/httpd/conf.modules.d/00-dav.conf.backup
# mv /etc/httpd/conf.modules.d/01-cgi.conf /etc/httpd/conf.modules.d/01-cgi.conf.backup
httpd.confにCGIの設定があるので無効にしておく。
#ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
#<Directory "/var/www/cgi-bin">
#AllowOverride None
# Options None
# Order allow,deny
# Allow from all
#</Directory>
/etc/httd/conf.d/ssl.confの以下の記述をコメントアウトしておく
#<FilesMatch "\.(cgi|shtml|phtml|php)$">
# SSLOptions +StdEnvVars
#</FilesMatch>
#<Directory "/var/www/cgi-bin">
# SSLOptions +StdEnvVars
#</Directory>
CGIとは?
Webサーバ上でプログラムを動かすための仕組みだよ
CGIの設定ファイルを無効にする理由
アプリケーションのバックエンド開発をPHPで行い、Webサーバーとアプリケーションサーバーが同一であるという想定のためCGIの設定が必要ないと判断した。
え?CGI(Common Gateway Interface)ってWebサーバーでプログラムを実行するための仕組みじゃないの?無効にしたらダメじゃない?と考えた方は以下を参考にしてください。
そもそもPHPにはモジュール版、CGI版がある。で、Apacheをインストールした後、PHPをインストールするとPHP用のモジュールが一緒にインストールされる。そのためCGIの機能を利用せずにPHPを実行することができる。詳細は他の良記事に託します。
それぞれモジュール版、CGI版のメリット・デメリットやがあるので各自どちらを採用するかは検討が必要かなと。(例えば、Webサーバーとアプリケーションサーバーを分離したい場合CGIを利用するなど)
CGIにはセキュリティ脆弱性が指摘されていたり、パフォーマンスに問題(こちらはFPMで緩和されている)があったりして対策の必要があるかなという感じ。
モジュール版、CGI版どちらを有効にするかは、/conf.d/
配下のphp.confで出しわけが可能。
あるディレクトリ配下にあるリソースを配布するなどといった要求がない限りディレクトリ内のファイル一覧は隠蔽しておく方が良いので、非表示にしておく。また、シンボリックリンクをどうするか問題はあるが、今回はパフォーマンスの観点からシンボリックリンクは有効にしておく。(セキュリティの観点からは無効が望ましいので、要検討)
// <Directory>セクションで指定
Options -Indexes +FollowSymLinks
Apacheのバージョンを隠蔽することでバージョン毎の脆弱性をバレにくくする。WebサーバーソフトウェアとしてApacheを利用してることは隠せない(自分の知識ではそう思っている)ので、せめてもの設定として対応する。
# グローバル領域で指定する
ServerSignature Off
ServerTokens ProductOnly
Header always unset X-Powered-By
詳細気になる人向け
おまじない的な感じで以下3行は入れておいた方がいい。
- ServerSignature:"no"でApacheが出す画面にサーバー情報を出さない
- ServerTokens:"ProductOnly|Prod"でバージョン情報などを隠蔽する
- Header always unset X-Powered-By:PHPのバージョン情報を消す
暗号化アルゴリズム、周辺ライブラリの脆弱性対応
基本的な暗号化関数と様々なユーティリティ関数を実装しているオープンソースソフトウェアであるOpenSSlのバージョンを確認しておく。
OpenSSLについて
# openssl version
OpenSSL 1.0.2k-fips xx Xxx XXXX
OpenSSLのバージョンについて
- OpenSSL 1.0.2系は既にサポートが終了しており、脆弱性対応のみ行われている状態、TLS 1.3には対応できない。
- また、CentOS7のパッケージ管理コマンドとして利用されるyumでは、OpenSSL 1.1.1系、また3系のインストールができないため手動インストールが必要となる。
- Apacheのビルドも手動で行う必要がある。詳細は以下を参照。
HTTPSに対応することが一般になっているため、HSTS(常時SSL)の設定をする。具体的にはStrict-Transport-Security
ヘッダを追加する。max-age属性の単位は[s]。
// HTTPS通信用のVirtualHost内で宣言
<VirtualHost *:443>
...
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
...
</VirtualHost>
Headerディレクティブについて
レスポンスヘッダをごにょごにょできるもの。
This directive can replace, merge or remove HTTP response headers. The header is modified just after the content handler and output filters are run, allowing outgoing headers to be modified.
onsuccess
かalways
を指定することでヘッダの修正タイミングを調整する。
- onsuccess:ステータスコードが2XXの時、設定が有効
- always:いつでも有効
SSL/TLSにおける安全性の低い暗号化アルゴリズムを無効にしておく。暗号スイートの選択に関しては各自システムの要求によるが、今回は特にこだわりがないのでIPAが公開しているTLS暗号設定ガイドラインに準拠した設定をする。詳細は以下のスクラップを参照。
TLS 1.3について
暗号スイートの設定
# TLS 1.3
SSLCipherSuite TLSv1.3 "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256"
# TLS 1.2以前
SSLCipherSuite "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES256-CCM8:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-CCM:ECDHE-ECDSA-AES128-CCM8:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-CCM:DHE-RSA-AES256-CCM8:DHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-CCM:DHE-RSA-AES128-CCM8"
暗号スイートの有線順序の設定、プロトコルバージョンの設定も合わせて行なっておく。
# コメント外す
SSLHonorCipherOrder on
脆弱性が報告されているプロトコルはサポートしないようにする。なお、TLS暗号設定ガイドラインでの推奨セキュリティ型ではTLS 1.2以前のプロトコルはサポートしないことが推奨されている。
# TLS 1.3
SSLProtocol -all +TLSv1.2 +TLSv1.3
# TLS 1.2以前
SSLProtocol -all +TLSv1.2
OCSP staplingの有効化
OCSP Staplingについて
そもそもCOSPとは、Online Certificate Status Protocolの略で、SSLサーバ証明書が失効してないかをオンラインでチェックするプロトコル。オンラインで証明書の状態確認をするため通信ができない時確認ができなかったり、OCSPを要求するかはTLSサーバーに依存するためある時通信負荷が増えたりしてしまう。
OCSP Staplingとは、上記の問題点を解決するために、OSCPの応答をキャッシュしておくための仕組みであり、証明書を状態確認を効率的に行うための仕組みである。
# グローバル領域で宣言
SSLStaplingCache "shmcb:/var/run/apache2/stapling_cache(32768)"
# HTTPS通信用VirtualHostの中で宣言
<VirtualHost *:443>
...
SSLUseStapling on
...
</VirtualHost>
SSLセッションの再利用
SSL高速化のためにセッションを再利用できるようにセッションのキャッシュ保持期間を長くしておく。デフォルトは300(単位は[s]で指定するので5分)が設定されている。
SSLSessionCacheTimeout 3600
SSL/TLSプロトコルのデータ圧縮機能の脆弱性対応
2012年ごろにSSL/TLSによる暗号化を無効にする攻撃手法(CRIME攻撃)が見つけられたらしくSSL/TLSの圧縮機能は使うなという感じになっているらしい。Apache2.4.4以降のバージョンではデフォルトで無効になっている模様なので、バージョン次第では設定の必要はない。
SSL/TLS暗号を無効化する攻撃
CRIME攻撃と呼ばれ、タイミング攻撃と同じ原理で圧縮率から力技で解析していく手法。
SSLCompression off
メジャーな攻撃手法対策
XST攻撃
XST攻撃への対応としてTRACEメソッドを使用できなくしておく。こちらの徳丸浩さんのブログにもあるように、危険すぎるので今すぐに対応せよ!というような温度感ではないことが分かる。まあ不用意にHTTPメソッドを許可しておく必要もないので今回は無効にしておく。
TraceEnable off
クリックジャッキング
クリックジャッキング対策でX-Frame-Options
ヘッダを設定する。
クリックジャッキングについて
ブラウザが対応している前提で、自サーバーのコンテンツを他サイトに埋め込み(iframeなど)を可能にするかを設定できる。設定できる値として、DENY, SAMEORIGINがある。
X-Frame-Options
ヘッダを追加するにはmod_hadersモジュールを有効にしておく必要がある。
任意ディレクトリ内のファイルで特定文字列を検索する
UNIXではパイプによって各コマンド出力を別コマンドへの入力としてチェーンを繋げていくことができる。その特性を利用し、検索をする。
$ find target-directory -type f -print | xargs grep target-string
# find /etc/httpd -type f -print | xargs grep mod_headers
/etc/httpd/conf.modules.d/00-base.conf:LoadModule headers_module modules/mod_headers.so
mod_headersモジュールは既に読み込まれていたのでOKで、以下をsecurity.confに記載しておく。
Header always set X-Frame-Options “SAMEORIGIN”
XSS
XSS対策を設定しておく。
Header always set X-Content-Type-Options nosniff
※X-XSS-Protection
ヘッダについて、MDNの情報では既にChromeなどでは廃止されている模様、古いブラウザへの対応をするときは有効らしいが今回は指定しないでおく。
Dos
Dos攻撃対策をする。単純にTimeout時間の短縮やプロセス数、スレッド数を制限することでもある程度の対策にはなるが根本解決にはならないため、mod_evasiveやmod_dosdetector、fail2banなどのモジュールを利用することで極めて短期間での複数回アクセスを禁止する。簡単に導入できそうなのでmod_evasiveを今回採用する。(ちなみに、ある記事でfail2banのシェアが高いと書いていた)
タイムアウト時間がデフォルトは60[s]になっているので短くする(ドキュメント)
# vi /etc/httpd/conf/httpd.conf
Timeout 30
// epelリポジトリをインストールしておく
# yum install --enablerepo=epel mod_evasive
# systemctl restart httpd
mod_dosdetectorの設定
WAFの設定
SQLインジェクションなどの攻撃手法に対し有効であるWAFの設定をしていく。今回、簡単にインストール、利用ができそうなmod_securityというモジュールを設定してみる。
※こちらまだ設定をちゃんとしてないので後ほどまとめます。悪しからず。
Under Construction...
さくらのクラウド利用者へ小ネタ
先ほど記事を引用させていただいた得丸浩さんがCTOを務めているEGセキュアソリューションズ社さんが提供するWAFサービスを無償で利用可能!(ホスト型なので諸々のセットアップ作業は必要)
意図しないアクセスの防止
IPアドレス、逆引きアドレスからのアクセスを無効にするためダミーのVirtualHostを設定しておく。
Apacheの公式ドキュメントに以下のような記述があり、仕様としてマッチしない場合は最初のVirtualHostセクションによってアクセス処理されることが分かる。
アスタリスクはすべてのアドレスにマッチしますので、主サーバーは リクエストを扱いません。www.example.com は 最初にあるため、優先順位は一番高くなり、default もしくは primary のサーバと考えることができます。つまり、リクエストが どの ServerName ディレクティブにもマッチしない場合、 一番最初の VirtualHost により扱われます。
そのため、必ず404を返すようなサイトとしてホストを設定することで、意図しないアクセスに404を返すことができるが、403を返してしまうらしく少し工夫が必要な模様?
<VirtualHost *:80>
SeverName dummy.example.com
Redirect 404 /
</VirtualHost>
...
<VirtualHost *:443>
SeverName dummy.example.com
Redirect 404 /
</VirtualHost>
...
無駄にサーバー負荷を増やさないために、別ドメインでの静的リソースへの直リンクを禁止する。
SetEnvIf Referer domain mydomain
<FilesMatch "\.(gif|jpe?g|png|css|js|svg|ico)$">
Require all denied
Require env mydomain
</FilesMatch>
<Files>と<FilesMatch>の違い
- Files、FilesMatchは両方<Directory>と同じくディレクティブの適用範囲を指定する
- Filesセクションはファイル名や正規表現を引数に渡せる
- ただし正規表現はFilesMatchを利用することが推奨されている
- FilesMatchセクションは正規表現での指定のみ有効
サーバー負荷を増やさないという観点ではIPアドレスでの逆引き禁止することも考えられる。HostnameLookupsディレクティブと言うものがあり、IPアドレスでアクセスされた時に名前解決を行うかを設定する。2.2系ではhttpd.confに記述されていた模様だが、2.4系ではデフォルトでoffに設定されているので追加で設定の必要はない。
アクセスログの設定
アクセスログが大変なことになるので静的リソースへのアクセスはログに残さない。
# グローバル領域で宣言
SetEnvIf Request_URI "\.(gif|jpe?g|png|css|js|svg|ico)$" nolog
CustomLog logs/domain.access_log combined env=!nolog
プロセス実行ユーザーの変更
httpdをインストールする際にapacheというユーザーが作成されるが、割と権限を持ってしまっているのでwwwとか任意の最小権限のみを持つユーザーに変更しておく方が良いケースがある。システムの要求次第で判断して設定をしておきたい。
考慮事項
"X-"系ヘッダについては、MDNの方で非推奨(Non-Standard)、廃止(Deprecated)されていないのであれば利用するという方針で設定を進めた。
また、セキュリティ対策の設定をするとパフォーマンスとのトレードオフになるケースが多いためシステム要求、要件に合わせて設定を調整したい。が、よほどパフォーマンスが厳密に求められる場合以外は、セキュリティを優先すべきだと考える。なぜなら、システムは「安全に利用できる」ことが保証されることが前提にあるから。
また、他の記事でも言及されているが、こちらでA評価を取得できることを目指しておきたい。(ここでA評価だったからと言って安全であるとは言えない)
参考資料
Discussion