NGINXセキュリティ設定の脆弱性診断による検証


### はじめに

Webサーバをサイバー攻撃から守るため、強固なセキュリティ設定が求められています。
NGINXセキュリティ設定に必要な項目を、脆弱性診断ツールなどを利用し検証しました。

### 関連用語のおさらい

#### NGINX(エンジンエックス)とは

Wikipediaから抜粋

https://ja.wikipedia.org/wiki/Nginx

- フリーかつオープンソースなWebサーバである
- 処理性能・高い並行性・メモリ使用量の小ささに焦点を当てて開発されている
- HTTP, HTTPS, SMTP, POP3, IMAPのリバースプロキシの機能を持つ
- ロードバランサ、HTTPキャッシュなどの機能も持つ

#### 脆弱性診断ツール(Vulnerability Scanner、略してVS)とは

Wikipediaから抜粋

https://ja.wikipedia.org/wiki/%E8%84%86%E5%BC%B1%E6%80%A7%E6%A4%9C%E6%9F%BB%E3%83%84%E3%83%BC%E3%83%AB

- コンピュータの安全性を試すためのプログラム群である
- コンピュータセキュリティ上で、様々な侵入に用いられる攻撃手段をシミュレーションする
- 大抵の場合はパッケージ化され、製品や試作ソフトウェアの評価に用いられる

### まず、NGINXのデフォルト設定のまま、脆弱性診断を行ってみます

今回はWeb脆弱性診断ツールとして、[OWASP ZAP](https://owasp.org/)を使用します。

- OWASP ZAPをインストール
    - 前提として、Java 8以降が必要です
    - 以下からダウンロードし、インストールします
        - https://www.zaproxy.org/download/

- OWASP ZAPを起動します

- 検証対象のWebサイトに向けて、スキャン実施します(`攻撃`ボタンをクリック)
    - すると、三つ脆弱性警告が報告されました(いずれも、セキュリティヘッダーが不足するとの警告)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/bd3f7f61-801a-66c1-cd2f-a10c500dc0fb.png)


### つぎに、NGINXのセキュリティ設定を行います(`nginx.conf`)

Red Hat Enterprise Linuxセキュリティガイドの`NGINXのセキュリティ保護`など参考にしながら、
`nginx.conf`にセキュリティ項目を追加していきます(設定後は、`nginx.conf`のリロードが必要)。

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/security_guide/sec-securing_nginx

#### 対策1. セキュリティ関連HTTPヘッダーを追加します

既知のWebアプリ脆弱性を緩和するためのヘッダーを追加します。

- `X-Frame-Options SAMEORIGIN`
    - 目的
        - クリックジャッキング攻撃を効果的に軽減します
    - 設定
        - `server`ブロックに`add_header X-Frame-Options SAMEORIGIN;`を追加します

- `X-Content-Type-Options nosniff`
    - 目的
        - 特定の古いブラウザーで MIME タイプのスニッフィングを防ぎます
    - 設定
        - `server`ブロックに`add_header X-Content-Type-Options nosniff;`を追加します

- `X-XSS-Protection`
    - 目的
        - クロスサイトスクリプティング(XSS)フィルタリングを有効にします
    - 設定
        - `server`ブロックに`add_header X-XSS-Protection "1; mode=block";`を追加します

- `Content-Security-Policy`
    - 目的
        - クロスサイトスクリプティング(XSS)やデータインジェクションなどの攻撃を軽減します
    - 設定
        - `server`ブロックに`add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'none'; form-action 'none'; " always;`を追加します

##### 設定が効いたか、再度脆弱性診断ツール`OWASP ZAP`でスキャンしてみます

今度は、アラートが発生せず、脆弱性診断結果OKになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/0816a7f7-e9fc-882f-f609-bbdd39e3885f.png)

#### 対策2. NGINXバージョンを隠蔽します

- 目的
    - 攻撃者がNGINXバージョンを検知し、バージョン特有の脆弱性を悪用することを防ぎます
- 設定
    - `http`ブロックに`server_tokens off;`を追加します
- 確認
    - バージョン情報が表示されなくなります(設定前: `Server: nginx/1.23.1`)
```
# curl -sI http://172.20.218.208 | grep Server
Server: nginx
```

#### 対策3. `Etag`を隠蔽します

- 目的
    - キャッシュの有効性確認をするために使われる`Etag`値が悪用されることを防ぎます
- 設定
    - `http`ブロックに`etag off;`を追加します
- 確認
    - レスポンスに`Etag`の値が含まれなくなります

#### 対策4. 不要なHTTPメソッドを無効にします

- 目的
    - HTTPメソッドが攻撃者に悪用されることを防ぐ
- 設定(GET、POSTメソッドのみ許可する例)
```
if ( $request_method !~ ^(GET|POST)$ ) {
    return 403;
}
```
- 確認

\- 許可されていないPUTメソッドでリクエストを発行すると拒否されます
```
# curl -XPUT http://172.20.218.208
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.23.1</center>
</body>
</html>
```

#### 対策5. 使用しないNGINXモジュールを削除します

- 目的
    - 攻撃者による悪用を防ぐため、使用しないモジュールを削除します
- 設定(例: 使用しない`ngx_http_xxx.so`モジュールをコメントアウトするか削除)
```
# load_module modules/ngx_http_xxx.so;
```
- 確認
    - 当該モジュールの機能が使用できないことを確認

#### 対策6. 特定ヘッダーが含まれているリクエストのみ許可します

- 目的
    - 特定のヘッダーが含まれていないリクエストを拒否し、セキュリティを向上します
- 設定(例: カスタムヘッダー `X-My-Header` を含まないリクエストを拒否)
```
if ($http_x_my_header = "") {
    return 403;
}
```
- 確認

\- カスタムヘッダー`X-My-Header`を含まないリクエストは拒否されます
```
# curl http://172.20.218.208
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.23.1</center>
</body>
</html>
```
\- カスタムヘッダー`X-My-Header`を含むリクエストは許可されます
```
# curl -H "X-My-Header: test" http://172.20.218.208
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
... ...
<body>
<h1>Welcome to nginx!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```

#### 対策7. クライアントバッファサイズを制限します

- 目的
    - バッファオーバーフロー攻撃を防ぐため、クライアントバッファサイズを制限します
- 設定(例: ボディサイズが4KBを超えたら拒否)
```
client_body_buffer_size  1K;
client_header_buffer_size 1k;
client_max_body_size 4k;
large_client_header_buffers 2 1k;
```
- 確認
    - 準備1: NGINXでは、スタティックページでPOSTが使用できません
        - `server`ブロックに`error_page  405 =200 $uri;`を追加し、一時的にPOSTを許可します
    - 準備2: POSTボディに使用するJSONファイルを二つ用意します
        - `small.json`: 1KB
        - `large.json`: 8KB

\- 4KB未満のJSONファイルをPOSTすると許可されます
```
# curl -XPOST -H "X-My-Header: test" -H "accept: application/json" -H "Content-
Type: application/json" -d @small.json http://172.20.218.208
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
... ...
<body>
<h1>Welcome to nginx!</h1>
</body>
</html>
```
\- 4KBを超えるJSONファイルをPOSTすると拒否されます
```
# curl -XPOST -H "X-My-Header: test" -H "accept: application/json" -H "Content-
Type: application/json" -d @body.json http://172.20.218.208
<html>
<head><title>413 Request Entity Too Large</title></head>
<body>
<center><h1>413 Request Entity Too Large</h1></center>
<hr><center>nginx/1.23.1</center>
</body>
</html>
```

#### 対策8. 特定のユーザエージェントのみ許可します

- 目的
    - 特定のユーザエージェントからのリクエストのみ許可します
- 設定(例: `curl`コマンド経由のリクエストのみ許可)
```
if ($http_user_agent !~ ^curl.*) {
    return 403;
}
```
- 確認

\- `curl`コマンドで発行したリクエストは許可されます
```
# curl -H "X-My-Header: test" http://172.20.218.208
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
... ...
<body>
<h1>Welcome to nginx!</h1>
</body>
</html>
```

\- ブラウザからWebサイトにアクセスすると`403 Forbidden`が発生します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/f087438a-e840-7b0c-91ae-f58379197266.png)


#### 対策9. HTTPSプロトコル(SSL通信)を使用します

- 目的
    - NGINX Webサーバが提供するデータおよびその通信経路を保護します
- 設定
    - SSL設定を行います
- 確認
    - https接続が可能か確認します

### おわりに

NGINXのセキュリティ設定を検証してみました。
セキュリティチェックに、脆弱性診断ツールなど使用しました。
ご参考になりましたら幸いです。