■nginxで読み込まれているモジュールの確認
# nginx -V
nginx version: nginx/1.12.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC)
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'
ちなみにnginx -Vは標準エラー出力
# nginx -V 2> /dev/null
# ←何も出力されない!
# nginx -V 2>&1 | tr ' ' '\n' | grep _module
--with-http_addition_module
--with-http_auth_request_module
--with-http_dav_module
・・・中略・・・
--with-http_v2_module
--with-mail_ssl_module
--with-stream_realip_module
--with-stream_ssl_module
--with-stream_ssl_preread_module
「--with-」を削除するときれいに読み込まれているモジュールが並ぶ
# nginx -V 2>&1 | tr - '\n' | grep _module | sed -e "s/^--with-//"
http_addition_module
http_auth_request_module
http_dav_module
http_flv_module
http_gunzip_module
http_gzip_static_module
http_mp4_module
http_random_index_module
http_realip_module
http_secure_link_module
http_slice_module
http_ssl_module
http_stub_status_module
http_sub_module
http_v2_module
mail_ssl_module
stream_realip_module
stream_ssl_module
stream_ssl_preread_module
【課題】
・上記の各モジュールの機能とnginxのコアコンポーネントとの関係を調べる
■Nginxの基本構文
・nginx.confのブロックと各ディレクティブ
# プロセス制御などを設定するmainコンテキスト
# (コアモジュールの設定)
#
events {
# 接続処理に関する設定
# (eventsモジュールの設定)
}
http {
# httpサーバの設定
# (httpモジュールの設定)
server {
# httpサーバごとの設定
location {
# URIごとの設定
}
}
server {
:
}
:
}
mail {
# メールプロキシ関連の設定
# (mailモジュールの設定)
}
【参照元】 Linux教科書 LPICレベル2 Version4.0 対応
・構文
・ディレクティブごとに書けるブロック(コンテキスト)が決まっている
→「Ngenx入門」の索引からディレクティブの説明ページを見る
・上位のブロックで定義された設定は、基本的に 下位(内部)のブロックにデフォルト値として引き継がれる
・includeディレクティブの箇所にインクルード先のテキストが埋め込まれる
・個々のディレクティブは、末尾にセミコロン (;)をつける
・「#」 から行末まで注釈となる
・location は、URLにマッチする。 つまり、location /admin/
は、http://www.pini.com/admin/
にマッチし、それ以外のこのサーバへのアクセスは location /
で処理される。 基本的には最長一致した location ブロックがヒットする。(更に 、複雑な一致則もある)
・正確には、コンテキストには以下の6種類がある。
- グローバル
- Http
- Server
- If
- Location
- Nested Location (入れ子になったLocation)
- If in location (Location内のIf)
- limit_except
継承では、必ず上位から下位に継承なされ、同位のものに継承が行われることや、 上位に影響することはない。
※Apache ではURLの他に、システム上のファイルやディレクトリもディレクティブの対象となるが、 nginx ではURL が常にディレクティブの対象となる。ただし、rootディレクティブは例外で、与えられたURLに対して、どのディレクトリからその対象を探すかという ことを定義する。
・下記の例では、
server { server_name hoge; root /home/pub; location /app { root /usr/www; } location /app2 { } } |
server ブロックに root /home/pub
があるので、 これがそれぞれの location ブロックに継承されるが、location /app
ブロックでは、これをオーバーライドして root /usr/www
に変更して いるので、location /app
の root は /usr/www
で、 一方、location /app2
では root は /home/pub
になる。
以上のことから、http://hoge/app/index.html
は /usr/www/app/index.html
にヒットし、
http://hoge/app2/index.html
は /home/pub/app2/index.html
にヒットする。
・設定のチェックは下記のコマンドでできる。
# nginx -t -c /etc/nginx/nginx.conf
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
(参照元:http://www2.matsue-ct.ac.jp/home/kanayama/text/nginx/node1.html)
※上記の「松江高専のnginxのテキスト」が非常にわかりやすい
■バージョンなどの隠蔽化
【参考:apacheの場合】
・バージョン情報の隠蔽
エラー画面に表示されるApacheのバージョン情報等を表示しない
ServerSignature Off
HTTP レスポンスヘッダに含まれる「Server:」の値にバージョンを表示しない
ServerTokens ProductOnly
※HTTP レスポンスヘッダに含まれる Server: の値に 「Apache 」とだけ表示し、バージョン情報や PHP 等読み込まれている一部モジュール情報を隠蔽
HTTP ヘッダーにPHP などのバージョンを表示しない
Header unset X-Powered-By
・ETag情報の隠蔽
FileETag MTime Size
※Etagとは、リソースに対してフィンガープリントのような識別子を生成し、それをサーバー・クライアント間で連絡し合うことでリソースが変更されたかどうか検知させるしくみ。レスポンスヘッダにEtagが含まれているとクライアントは次回のリクエストからヘッダにIf-None-Match
をつける。If-None-Match
を受けたサーバーは識別子が同一であればステータスコード:304
(
Not Modified)
を返し、コンテンツを返さない。304を受け取ったブラウザはブラウザキャッシュ内のコンテンツを表示することでネットワーク帯域を節約する。
このときEtagが異なれば新しいリソースとともに新しいEtagヘッダを返す。
※Etag脆弱性とは、「FileETag INode MTime Size」と指定した場合、WebサーバはEtagをファイルの inode, サイズ、最終修正時刻 (mtime) から作成 するために、ETagの値からコンテンツのinodeがばれてしまう可能性がある。
・ドキュメントルートのインデックスを無効にする
※インデックスページとはディレクトリー内のファイル一覧ページ
Options -Indexes
・.htaccess を有効化(All)としてよいか?
AllowOverride
・XST対策
※XST攻撃とはXSSとtraceメソッドを組み合わせた攻撃。ただし、ブラウザ側(Windows XP SP2以降、firefox1.5以降)で対策されて、現在XST攻撃可能なブラウザは存在しない。
TraceEnable Off
・XSS対策
Header set X-XSS-Protection "1; mode=block"
Header set X-Content-Type-Options nosniff
・httpoxy 対策
RequestHeader unset Proxy
JVNVU#91485132CGI ウェブサーバがヘッダ Proxy の値を環境変数 HTTP_PROXY に設定する脆弱性
・クリックジャッキング対策
Header append X-Frame-Options SAMEORIGIN
【nginxの場合】
とりあえずconfigのバックアップをしておく
・バージョン情報の隠蔽
- エラー画面に表示されるバージョン情報の隠蔽
[変更前]
nginx(192.168.2.7:80)にHTTPリクエストする
せ6> curl http://192.168.2.7/unko ←存在しないページをリクエストしてエラー画面を受け取る
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.12.0</center> ←バージョン情報が表示される
</body>
</html>
→httpディレクティブの中に下記を追記する
http {
:
server_tokens off; # <= 追加 ーーーーーーーーー①
:
}
# diff nginx.conf.org nginx.conf
30c30
<
---
> server_tokens off;
# systemctl reload nginx
[変更後]
せ6> curl http://192.168.2.7/unko
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center> ←バージョン情報が隠蔽された
</body>
</html>
- HTTP レスポンスヘッダにバージョン情報の隠蔽
[変更前]
せ6> curl -I http://192.168.2.7
HTTP/1.1 200 OK
Server: nginx/1.12.0 ←バージョン情報が表示される
Date: Sat, 10 Feb 2018 13:58:40 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Wed, 12 Apr 2017 15:23:46 GMT
Connection: keep-alive
ETag: "58ee4682-264"
Accept-Ranges: bytes
→上記の①で隠蔽される
[変更後]
せ6> curl -I http://192.168.2.7
HTTP/1.1 200 OK
Server: nginx ←バージョン情報が隠蔽された
Date: Sat, 10 Feb 2018 14:24:49 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Wed, 12 Apr 2017 15:23:46 GMT
Connection: keep-alive
ETag: "58ee4682-264"
Accept-Ranges: bytes
・PHP などのバージョンを表示させない
→PHPモジュールが読み込まれているか?
# nginx -V 2>&1 | tr - '\n' | grep _module | grep -i php
# ←PHPモジュールは読み込まれていない
※そもそもnginxでPHPを普通は実行しない。
※バックエンドPHPサーバ(apacheなど)で隠蔽するべき
・Etag情報の隠蔽
せ6> curl -I http://192.168.2.7
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 10 Feb 2018 14:24:49 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Wed, 12 Apr 2017 15:23:46 GMT
Connection: keep-alive
ETag: "58ee4682-264" ←Etag情報
Accept-Ranges: bytes
→コンテンツのmtimeを変更せず、inodeだけを変更してetagが変更されるか確認する
# cd /usr/share/nginx/html
# stat index.html
File: 'index.html'
Size: 612 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 57163 Links: 1 ←inode
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: system_u:object_r:httpd_sys_content_t:s0
Access: 2018-02-10 21:38:37.384475496 +0900
Modify: 2017-04-13 00:23:46.000000000 +0900 ←mtime
Change: 2018-02-10 18:25:18.987868486 +0900
Birth: -
# cp -p index.html index.html2
# stat index.html2
File: 'index.html2'
Size: 612 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 57120 Links: 1 ←inodeが変わった
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:httpd_sys_content_t:s0
Access: 2018-02-10 21:38:37.384475496 +0900
Modify: 2017-04-13 00:23:46.000000000 +0900 ←mtimeは変わらず
Change: 2018-02-11 00:42:54.916476107 +0900
Birth: -
# mv index.html2 index.html
mv: overwrite 'index.html'? y
# stat index.html
File: 'index.html'
Size: 612 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 57120 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:httpd_sys_content_t:s0
Access: 2018-02-10 21:38:37.384475496 +0900
Modify: 2017-04-13 00:23:46.000000000 +0900 ←mtimeは変わらず
Change: 2018-02-11 00:43:45.878801813 +0900
Birth: -
Etagを見てみる
せ6> curl -I http://192.168.2.7
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 10 Feb 2018 15:51:21 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Wed, 12 Apr 2017 15:23:46 GMT
Connection: keep-alive
ETag: "58ee4682-264" ←inodeを変更したのにEtagは変わらず
Accept-Ranges: bytes
→コンテンツのmtimeを変更して、inodeを変更せずにEtagが変更されるか確認する
# md5sum index.html
e3eb0a1df437f3f97a64aca5952c8ea0 index.html ←コンテンツ変更前のmd5チェックサム値
# echo a >> index.html
# vi index.html
→最下行をddで削除して保存
# md5sum index.html
e3eb0a1df437f3f97a64aca5952c8ea0 index.html ←コンテンツのデータブロックの内容は変化なし
# stat index.html
File: 'index.html'
Size: 612 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 57150 Links: 1 ←inodeが変わった
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:httpd_sys_content_t:s0
Access: 2018-02-11 00:59:32.513444573 +0900
Modify: 2018-02-11 00:59:21.289875599 +0900 ←mtimeが変わった
Change: 2018-02-11 00:59:21.291882855 +0900
Birth: -
せ6> curl -I http://192.168.2.7
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 10 Feb 2018 16:03:21 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sat, 10 Feb 2018 15:59:21 GMT
Connection: keep-alive
ETag: "5a7f16d9-264" ←データブロックの内容は変更してないのにmtimeを変更したらEtagが変わった。
Accept-Ranges: bytes
以上より、inodeだけ変更してもEtagは変更されないので、Etagからinodeを推測することはできないのでEtag脆弱性はないと思われる。
・ドキュメントルートのインデックスを無効にする
nginxはデフォルトでインデックスが無効になっている。
インデックスの有効/無効は下記のように設定する。
location / {
:
autoindex on; ←「autoindex」を書かないとデフォルトでoff。インデックス有効化はon
:
}
ドキュメントルートのindex.htmlを下記のようにrenameする。
# cp -p index.html index.html.hoge
この状態で「/」を取得してみる。
せ6> curl http://192.168.2.7/
<html>
<head><title>403 Forbidden</title></head> ←index.htmlが無いので403 Forbiddenになった。
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
autoindexをonにしてみる。
# diff default.conf.org default.conf
10a11
> autoindex on;
# systemctl reload nginx
この状態で「/」を取得してみる。
せ6> curl http://192.168.2.7/
<html>
<head><title>Index of /</title></head>
<body bgcolor="white">
<h1>Index of /</h1><hr><pre><a href="../">../</a>
<a href="50x.html">50x.html</a> 12-Apr-2017 15:23 537
<a href="index.html.hoge">index.html.hoge</a> 10-Feb-2018 16:06 612
</pre><hr></body>
</html>
→「/」のインデックスが表示された!
結論:デフォルトでインデックスページは非表示。代わりに403 Forbiddenが返る
・.htaccess を有効化(All)としてよいか?
nginxでも.htaccessを使えるが、AllowOverrideはないので考慮不要。
https://stackoverflow.com/questions/35705641/how-to-convert-apaches-allowoverride-all-to-nginx
https://qiita.com/hideji2/items/1421f9bff2a97a5e5794
そもそもnginxで.htaccessを使うとパフォーマンスがかなり落ちるらしい
http://mogile.web.fc2.com/nginx_wiki/nginx_wiki201705/start/topics/examples/likeapache-htaccess/
・XST攻撃対策
現在ではブラウザ側で対策されているので考慮不要
・httpoxy 対策
JVNVU#91485132CGI ウェブサーバがヘッダ Proxy の値を環境変数 HTTP_PROXY に設定する脆弱性
Nginx/FastCGI
PHPFPM や PHPPM などでヘッダ Proxy
をブロックするために次の設定を使用してください:
fastcgi_param HTTP_PROXY "";
Nginx with proxy_pass
Nginx で proxy_pass を使用している場合は次の設定を使用してください:
proxy_set_header Proxy "";
・XSS攻撃対策
- XSSフィルター機能有効化
add_header X-XSS-Protection "1; mode=block";
- Content-Security-Policy
Content Security Policy (CSP) は、クロスサイトスクリプティング (XSS) やデータインジェクション攻撃を含む、よく知られた種類の攻撃を検出して軽減することができる。
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ssl.google-analytics.com; img-src 'self' https://ssl.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com 'self' https://themes.googleusercontent.com; frame-src 'none' object-src 'none'";
・MIME タイプのセキュリティ リスクの軽減
X-Content-Type-Options レスポンスヘッダーの値に nosniff を設定して送信すると、Internet Explorer が MIME Sniffing 機能で content-type 宣言を回避するのを防止できる。
add_header X-Content-Type-Options nosniff;
・リクエストのサイズ制限
クライアントからのリクエストサイズが事前に見積もれるのであれば、リクエストボディ、リクエストヘッダの最大サイズの制限を設定する。リクエストボディの設定を1Kbに設定する場合は下記のようにする。
client_max_body_size 1k;
リクエストヘッダの設定を1Kbに設定する場合は下記のようにする。
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
・クリックジャッキング対策
――調査中ーー
・セキュリティテスト
Nginxセキュリティ設定に、ウェブサイトの脆弱性を確認する-Niktoを参考にnikto.plを導入し、確認する方法が乗ってたんご。