よくあるNginxの設定ミスの例

よくあるNginxの設定ミスの例

Nginx は現在主流の Web サービスです。 以下に、最も一般的な誤った構成をいくつか示します。

ルートの場所が見つかりません

サーバー{
  ルート /etc/nginx;

  場所 /hello.txt {
    try_files $uri $uri/ =404;
    プロキシパス http://127.0.0.1:8080/;
  }
}

rootディレクティブは、Nginx ルート ディレクトリを指定します。 上記の例では、ルート ディレクトリは /etc/nginx であるため、そのディレクトリの下のファイルにアクセスできます。 上記の構成では、 /の場所 ( location / {...} ) はなく、/hello.txt の場所のみが指定されています。 したがって、ルート ディレクティブはグローバルに設定され、/ へのリクエストはローカル パス /etc/nginx に移動することになります。

GET /nginx.confのような単純なリクエストは、/etc/nginx/nginx.conf に保存されている Nginx 構成ファイルの内容を表示します。 ルートが /etc に設定されている場合、/nginx/nginx.conf への GET リクエストにより設定ファイルが表示されます。 場合によっては、他の構成ファイル、アクセス ログ、さらには HTTP 基本認証の暗号化された資格情報にアクセスできる可能性があります。

私たちが収集した約 50,000 個の Nginx 構成ファイルの中で、最も一般的なルート パスは次のとおりです。

オフバイスラッシュ

サーバー{
  80 default_server をリッスンします。

  サーバー名_;

  場所 /static {
    エイリアス /usr/share/nginx/static/;
  }

  場所 /api {
    proxy_pass http://apiserver/v1/;
  }
}

Off-by-slash 構成エラーでは、/ が欠落しているためにパスを 1 ステップ上に移動できる可能性があります。この手法は、Orange Tsai 氏の Blackhat 講演「Breaking Parser Logic!」で広く知られるようになりました。 この講演では、location ディレクティブのスラッシュが欠落していることと alias ディレクティブを組み合わせることで、Web アプリケーションのソース コードを読み取ることができるようになる方法を説明します。 あまり知られていないのは、proxy_pass などの他のディレクティブと組み合わせて使用​​することもできるということです。 何が起こっているのか、そしてなぜそれが機能するのかを分析してみましょう。

  場所 /api {
    proxy_pass http://apiserver/v1/;
  }

次の構成が Nginx サーバーにアクセスできる場合は、http://apiserver/v1/ の下のパスのみがアクセス可能であると想定できます。

http://server/api/user -> http://apiserver/v1//user

http://server/api/user にリクエストが行われると、Nginx はまず URL を正規化します。 次に、プレフィックス /api が URL と一致するかどうかを確認します。一致する場合は一致します。 プレフィックスは URL から削除され、/user パスが残ります。 このパスはproxy_pass URL に追加され、最終的な URL は http://apiserver/v1//user になります。 location ディレクティブがスラッシュで終わっておらず、 proxy_pass URL パスがスラッシュで終わっているため、URL に二重のスラッシュがあることに注意してください。 ほとんどの Web サーバーは、http://apiserver/v1//user ユーザーを http://apiserver/v1/user に正規化します。つまり、構成エラーがあっても、すべてが期待どおりに動作し、気付かれない可能性があります。

この誤った構成は、http://server/api../ を要求することによって悪用される可能性があり、これにより Nginx は http://apiserver/v1/../ に正規化された URL http://apiserver/ を要求することになります。 これが及ぼす影響は、この誤った構成を悪用することで何を達成できるかによって異なります。 たとえば、これにより、Apache サーバーのステータスが URL http://server/api../server-status 経由で公開される可能性があり、また、パブリックにアクセスできないようにしたいパスにアクセス可能になる可能性があります。

Nginx サーバーが誤って構成されていることを示す兆候の 1 つは、URL 内のスラッシュを削除しても、サーバーが同じ応答を返すことです。 たとえば、http://server/api/user と http://server/apiuser が同じ応答を返す場合、サーバーは脆弱である可能性があります。 これにより、次のリクエストが送信されます。

http://server/api/user -> http://apiserver/v1//user
http://server/apiuser -> http://apiserver/v1/user

安全でない変数の使用

一部のフレームワーク、スクリプト、および Nginx 構成では、Nginx に保存された変数が安全でない方法で使用されます。 これにより、XSS、HttpOnly 保護のバイパス、情報漏洩、場合によっては RCE などの問題が発生する可能性があります。

スクリプト名

構成は次のとおりです。

  場所 ~ \.php$ {
    fastcgi_params を含めます。
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    127.0.0.1:9000; をデフォルトとして設定します。
  }

主な問題は、ファイルがディスク上に存在しない場合でも、Nginx が .php で終わるすべての URL を PHP インタープリターに送信することです。 これは、Nginx が作成した「落とし穴とよくある間違い」ドキュメントに記載されている、Nginx の多くの誤った構成の 1 つです。

PHP スクリプトが SCRIPT_NAME に基づいてベース URL を定義しようとすると、XSS が発生します。

<?php

if(basename($_SERVER['SCRIPT_NAME']) ==
ベース名($_SERVER['SCRIPT_FILENAME']))
 dirnameをエコーし​​ます($_SERVER['SCRIPT_NAME']);

?>

GET /index.php/<script>アラート(1)</script>/index.php
SCRIPT_NAME = /index.php/<script>alert(1)</script>/index.php

$uri を使用すると CRLF インジェクションが発生する可能性があります

Nginx 変数に関連するもう 1 つの誤った構成は、$request_uri の代わりに $uri または $document_uri を使用することです。 $uri と $document_uri には正規化された URI が含まれており、Nginx での正規化には URI の URL デコードが含まれます。 Volema は、Nginx 構成でリダイレクトを作成すると、多くの場合 $uri を使用して CRLF インジェクションが発生する可能性があることを発見しました。

脆弱な Nginx 構成の例は次のとおりです。

位置 / {
 302 https://example.com$uri を返します。
}

HTTP リクエストの改行文字は\r (キャリッジ リターン) と\n (ライン フィード) です。 改行文字を URL エンコードすると、次の文字%0d%0aが表現されます。 これらの文字がサーバーへの誤って構成されたリクエストに含まれている場合 (たとえば、http://localhost/%0d%0aDetectify:%20clrf)、URL デコード後の$uri変数に改行文字が含まれるため、サーバーは Detectify という名前の新しいヘッダーで応答します。

HTTP/1.1 302 一時的に移動しました
サーバー: nginx/1.19.3
コンテンツタイプ: text/html
コンテンツの長さ: 145
接続: キープアライブ
場所: https://example.com/
検出: clrf

任意の変数

場合によっては、ユーザー提供のデータを Nginx 変数として扱うことができます。 なぜこのようなことが起こるのかは明らかではありませんが、この H1 レポートに示されているように、これは珍しいことではなく、テストも容易ではありません。 エラー メッセージを検索すると、SSI フィルター モジュールで見つかることがわかります。つまり、これは SSI が原因であることがわかります。

テスト方法は次のとおりです。

$ curl -H 'Referer: bar' http://localhost/foo$http_referer | grep 'foobar'

生のバックエンド応答の読み取り

Nginx のproxy_passを使用すると、バックエンドによって作成されたエラーと HTTP ヘッダーをインターセプトできます。 これは、内部エラー メッセージとヘッダーを非表示にして、Nginx で処理できるようにする場合に便利です。 バックエンドがリクエストに応答できない場合、Nginx は自動的にカスタム エラー ページを提供します。 しかし、Nginx がこれが HTTP 応答であることを理解しない場合はどうなるでしょうか?

クライアントが無効な HTTP リクエストを Nginx に送信した場合、リクエストはそのままバックエンドに転送され、バックエンドは元のコンテンツで応答します。 Nginx は無効な HTTP 応答を理解できず、クライアントに転送します。 次のような uWSGI アプリケーションを想像してください。

defアプリケーション(environ、start_response):
 start_response('500 エラー', [('コンテンツタイプ',
'text/html'),('シークレットヘッダー','シークレット情報')])
 return [b"秘密情報なので、表示しないでください!"]

Nginx の設定は次のとおりです。

http {
 エラーページ 500 /html/error.html;
 proxy_intercept_errors がオン;
 proxy_hide_header シークレットヘッダー;
}

proxy_intercept_errors は、バックエンドの応答ステータスが 300 より大きい場合にカスタム応答を提供します。上記の uWSGI アプリケーションでは、500 エラーを送信しますが、これは Nginx によってインターセプトされます。

proxy_hide_header: 指定された HTTP ヘッダーをクライアントから非表示にできます。

通常の GET リクエストを送信すると、Nginx は次を返します。

HTTP/1.1 500 内部サーバーエラー
サーバー: nginx/1.10.3
コンテンツタイプ: text/html
コンテンツの長さ: 34
接続: 閉じる

ただし、次のような無効な HTTP リクエストを送信した場合、

GET /? XTTP/1.1
ホスト: 127.0.0.1
接続: 閉じる

次のような返答が届きます。

XTTP/1.1 500 エラー
コンテンツタイプ: text/html
シークレットヘッダー: secret-info

秘密情報なので、見られてはいけません!

merge_slashes がオフに設定されています

デフォルトでは、 merge_slashesディレクティブはonに設定されています。これは、2 つ以上のスラッシュを 1 つに圧縮するメカニズムであり、 ////になります。 Nginx がリバース プロキシとして使用されており、プロキシされたアプリケーションがローカル ファイルのインクルードに対して脆弱な場合、リクエストで余分なスラッシュを使用すると、悪用される余地が生じる可能性があります。 Danny Robinson 氏と Rotem Bar 氏がこれについて詳しく説明しています。

上記は、よくある Nginx の誤った設定の詳細です。Nginx の誤った設定の詳細については、123WORDPRESS.COM にアクセスして、その他の関連記事をご覧ください。

以下もご興味があるかもしれません:
  • nginxリバースプロキシサービスは、設定ファイルのエラーによりリソースにアクセスするときに404エラーを引き起こします。
  • 404 エラー ページをリダイレクトするように NGINX サーバーを構成する方法
  • Nginx キャッシュとエラーページの設定
  • Nginx サーバーでよくあるアップロードおよび接続エラーを解決するために設定を変更します
  • Nginx サーバーで 404 エラー ページを構成する際に注意すべき点
  • Nginx サーバーの 414 および 504 エラーの構成ソリューション
  • Nginx の worker_connections 設定が低すぎるため、500 エラーが発生します
  • Nginx で PHP-FPM を使用するときに PHP エラー ログを構成する方法
  • NGINX で 404 エラー ページを構成する方法

<<:  角丸四角形の HTML+CSS 実装コード

>>:  MySQL で固定されていない位置から文字列要素を抽出する方法

推薦する

トリガーメソッドを使用して、ファイルタイプの入力をクリックせずにポップアップファイル選択ダイアログボックスを実現します。

トリガー メソッドを使用できます。JavaScript にはネイティブのトリガー関数はありません。自...

CocosCreator Huarongdaoデジタルパズルの詳しい説明

目次序文文章1. パネル2. 華容島ソリューション3. コード4. 注記序文華容路とは何ですか? 誰...

Reactコンポーネントのライフサイクルの詳細な説明

目次1.ライフサイクルとは何か2. 読み込みプロセス1.コンストラクタ2. レンダリング3. コンポ...

ウェブフォームデザインのための5つの実用的なヒント

1. フォームテキスト入力のモバイル選択: テキスト入力フィールドにプロンプ​​トが追加されている場...

Nginx フォワード プロキシとリバース プロキシ、および負荷分散機能の構成コード例

この記事は主に、Nginx のフォワード プロキシとリバース プロキシ、および負荷分散機能の設定コー...

すべてのブラウザとの完全な互換性を実現するために最適なプリセットを選択してください

各ブラウザの select タグのプロパティと各ブラウザのサポートが多少異なるため、各ブラウザでの選...

Blazor における CSS 分離の問題

1. 環境VS 2019 16.9.0 プレビュー 1.0 .NET SDK 5.0.100 2. ...

SSHのssh-keygenコマンドの基本的な使い方の詳細な説明

SSH 公開鍵認証は、SSH 認証方式の 1 つです。 SSH パスワードフリーのログインは公開鍵認...

MySQLの論理アーキテクチャに関する深い理解

MySQL は現在、ほとんどの企業や事業体で使用されているデータベースです。MySQL が使用される...

Mysql トランザクション分離レベルの読み取りコミットの詳細な説明

MySQL トランザクション分離レベルを表示する mysql> '%isolation...

Ubuntu でディスク容量不足により MySQL が起動しない場合の解決策

序文最近、データベースのテーブルに 2 つのフィールドを追加しました。その後、ディスク容量不足のよう...

Linux の Makefile とは何ですか? どのように機能しますか?

この便利なツールでプログラムをより効率的に実行およびコンパイルしますMakefile は自動コンパイ...

パーティクルダイナミックボタン効果を実現するCSS

オリジナルリンクhttps://github.com/XboxYan/no…ボタンは、おそらく We...

LinkedIn がウェブサイト閲覧を簡素化するためにリニューアル

ビジネス ソーシャル ネットワーキング サイト LinkedIn は最近、ナビゲーション バーとユー...