RitoLabo

Apache2.4セキュリティ「mod_headersモジュールでX-Frame-Optionsレスポンスヘッダの設定を行いクリックジャッキング攻撃対策を行う」

  • 公開:
  • カテゴリ: linux Apache
  • タグ: Linux,CentOS,Apache,Security,httpd,2.4,7.2,Clickjacking,X-Frame-Options,mod_headers

「セキュリティ対策とは、常に小さな事の積み重ねである」
どなたの名言でもありませんが、激しく同意している今日この頃。

べつにしてもしなくてもどっちでもまあいい。程度のレベルなら、ひとまずやっておくのがWEBサーバーのセキュリティ対策だと思っています。

という事で今回は、クリックジャッキング対策として、X-Frame-Optionsレスポンスヘッダの設定を行います。

アジェンダ
  1. クリックジャッキング攻撃
  2. X-Frame-Options HTTP レスポンスヘッダ
  3. 現状確認と準備
  4. Apache mod_headersモジュールの有効化
  5. X-Frame-Optionsレスポンスヘッダを設定する
    1. 現在の設定確認
    2. X-Frame-Options HTTPレスポンスヘッダ設定
  6. 動作確認

クリックジャッキング攻撃

クリックジャッキング攻撃とは、悪意のあるユーザがiframeに別のサイトへのリンクなどを仕込み、気づかれない(見えない)ようにして攻撃対象のサイトへそれを表示させ、訪問者にその部分をクリックさせる事で、意図しないサイトへ強制的に誘導してしまう攻撃手法の事。

X-Frame-Options HTTP レスポンスヘッダ

X-Frame-Options HTTPレスポンスヘッダとは、外部サイトからの、HTMLのiframeタグの読み込み許可範囲を設定できるもの。設定出来る値は以下の3つです。

DENY
問答無用で全てのiframeタグが無効となる
SAMEORIGIN
同一オリジンのものであればiframeが有効となる。
オリジン=同一ドメインであっても、httpとhttpsであれば無効となる
ALLOW-FROM uri
指定したドメインのみ有効となる(1件のみ)
例)ALLOW-FROM example.com

現状確認と準備

今回はWEBサーバを2台用意して確認してみます。現状では何も制限をおこなっていないので、どこの外部サイトからであってもiframeで読み込みが可能なはずです。

1号機
CentOS 7.2
Apache 2.4
192.168.33.20
http://apache-practice.com/
2号機
CentOS 7.2
Apache 2.4
192.168.33.21
http://apache-practice-master.com/

まずは1号機のページを用意します。HTMLで簡単なページを作ります。

# 1号機のルートディレクトリに移動
cd /var/www/html

# index.html を作成
vim index.html

# index.htmlに記述したのソースコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<h1>Hello World!</h1>
<p>こちらは検証1号機です</p>
</body>
</html>

ブラウザから確認するとこんな感じになります。

x-frame-potions_検証1号機ページ

続いて2号機。こちらもHTMLで簡単なページを作ります。

# 2号機のルートディレクトリに移動
cd /var/www/html

# index.html を作成
vim index.html

# index.htmlに記述したのソースコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<h1>hoge hoge hoge</h1>
<p>こちらは検証2号機です</p>
</body>
</html>

ブラウザから確認するとこんな感じになります。

x-frame-potions_検証2号機ページ

ではここから、2号機で1号機のページをiframeで読み込んでみます。2号機のページにiframeを追記します。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<h1>hoge hoge hoge</h1>
<p>こちらは検証2号機です</p>

<iframe src="http://192.168.33.20/" width=800 height=600></iframe>

</body>
</html>

ブラウザから確認するとこんな感じになります。

x-frame-potions_2号機から1号機を読み込み_対策前

2号機のページからiframeで1号機のページが表示されました。

Apache mod_headersモジュールの有効化

X-Frame-Optionsレスポンスヘッダの設定の為には、Apacheのmod_headersモジュールを有効にする必要があります。

Apache2.4の場合は既に導入・有効化されているので、有効確認を行います。

ファイル設置箇所
/etc/httpd/conf.modules.d
ファイル名
00-base.conf

00-base.confを開き、mod_headersモジュールの存在と有効化を確認します。

# vimコマンドで00-base.confを開く
vim /etc/httpd/conf.modules.d/00-base.conf

# 以下の記述があればOK。コメントアウトされている場合は外す。
LoadModule headers_module modules/mod_headers.so

LoadModule headers_module modules/mod_headers.soの記述があれば導入はされています。もしコメントアウトされていた場合は外してください。

コメントアウトされていて、外した場合はApacheを再起動します。

# Apacheの再起動
apachectl restart

X-Frame-Optionsレスポンスヘッダを設定する

ここからいよいよ、X-Frame-Optionsレスポンスヘッダを設定していきます。

現在の設定確認

まずは、設定前のレスポンスヘッダを確認します。2号機のWEBサーバから、1号機に向けて以下のcurlコマンドを叩きます。

# 2号機のWEBサーバから、curlコマンドで1号機にアクセスする
curl -v -X GET http://192.168.33.20/

# 実行結果
[demo@localhost ~]# curl -v -X GET http://192.168.33.20/

* About to connect() to 192.168.33.20 port 80 (#0)
* Trying 192.168.33.20...
* Connected to 192.168.33.20 (192.168.33.20) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.33.20
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 22 Aug 2017 01:48:16 GMT
< Server: Apache
< Last-Modified: Tue, 22 Aug 2017 01:14:55 GMT
< ETag: "v5-8295d52fq1k32"
< Accept-Ranges: bytes
< Content-Length: 177
< Content-Type: text/html; charset=UTF-8
<
<!DOCTYPE html>
<html lang="ja">
<head
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<h1>Hello World!</h1>
<p>こちらは検証1号機です</p>
</body>
</html>
* Connection #0 to host 192.168.33.20 left intact

「X-Frame-Options」の記載が無いので、X-Frame-Options HTTPレスポンスヘッダは未設定である事が確認出来ます。

X-Frame-Options HTTPレスポンスヘッダ設定

X-Frame-Optionsの設定ですが、confファイルに記述する事で設定できます。ここでは、httpd.confに記述します。

ファイル設置箇所
/etc/httpd/conf
ファイル名
httpd.conf

httpd.confを開いて、以下を記述します。場所は大方どこでも大丈夫ですが、httpd.confにオリジナル設定を記述する場合には、後で見返してわかりやすいように、下の方にまとめておくと良いと思います。

# vimコマンドでhttpd.confを開く
vim /etc/httpd/conf/httpd.conf

# httpd.conf に以下を追記する
# X-Frame-Options Setting
Header append X-FRAME-OPTIONS "DENY"

「DENY」と記述しているところは、上記X-Frame-Options HTTP レスポンスヘッダの項で説明した3つのどれかを指定してください。今回はデモなので、一撃一刀両断のDENY氏をアサインしました。

Apacheを再起動します。

# Apacheの再起動
systemctl restart httpd.service

ちなみにこの前に記述したApacheの再起動コマンドと違っていますが、ただの気まぐれです。再起動コマンドはいくつか存在しているので、自分の好きなコマンドで叩いてください。

動作確認

設定が出来たので、改めてレスポンスヘッダを確認してみます。先ほどと同じように、2号機のWEBサーバから、1号機に向けて以下のcurlコマンドを叩きます。

# 2号機のWEBサーバから、curlコマンドで1号機にアクセスする
curl -v -X GET http://192.168.33.20/

# 実行結果
[demo@localhost ~]# curl -v -X GET http://192.168.33.20/

* About to connect() to 192.168.33.20 port 80 (#0)
* Trying 192.168.33.20...
* Connected to 192.168.33.20 (192.168.33.20) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.33.20
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 22 Aug 2017 01:49:38 GMT
< Server: Apache
< Last-Modified: Tue, 22 Aug 2017 01:14:55 GMT
< ETag: "b1-5574d52bc1b18"
< Accept-Ranges: bytes
< Content-Length: 177
<
X-FRAME-OPTIONS: DENY
< Content-Type: text/html; charset=UTF-8
<
<!DOCTYPE html>
<html lang=
"ja">
<head
<meta charset=
"UTF-8">
<title>title</title>
</head>
<body>
<h1>Hello World!</h1>
<p>こちらは検証1号機です</p>
</body>
</html>
* Connection #0 to host 192.168.33.20 left intact

「X-FRAME-OPTIONS: DENY」の表示が確認出来ました。これで設定は完了です。

ブラウザから2号機にアクセスして確認してみましょう。

x-frame-potions_2号機から1号機を読み込み_対策後

X-Frame-Options HTTPレスポンスヘッダをDENYにしたことにより、外部ドメインである2号機から1号機のコンテンツは読み込まれなくなりました。

また、Google Chromeのデベロッパーツールからみると、それぞれ、X-FRAME-OPTIONSが効いている事がわかります。

1号機(読み込まれる側)
x-frame-potions_対策後_1号機_header
2号機(読み込んだ側)
x-frame-potions_対策後_2号機_header

以上でX-FRAME-OPTIONS HTTPレスポンスヘッダの設定は完了です。