- 締切済み
httpd.confに関して
apacheのhttpd.confに関して質問させていただきます。 ErrorDocumentで、自作したカスタムのエラーページを 表示できると思うのですが、 ・ErrorDocument エラーコード "文字列" は文字列がちゃんと表示されますが、 ・ErrorDocument エラーコード /~/~/~.html の場合は、デフォルトのエラーページが表示されてしまいます。 VirtualHosat内でも同じ動きです。 なぜデフォルトが出てしまうのかご意見よろしくお願いいたします。
- みんなの回答 (12)
- 専門家の回答
みんなの回答
>(1)URLのドメインのあとのどこかに%をつけて叩く >がカスタムエラーページを表示できるので、 >カスタムのエラーページが表示されていいと思うのですが。 %の件は、相対パスの一部がフォーマットエラーだから、 Host:は信頼してもいいけど、 POSTのBodyをheaderに結合すると、リクエストヘッダ自体が長くなりすぎて、リクエスト全体が信頼できないと判断しているようですね 今回の件はバッファオーバーフロー攻撃と判断されてもおかしくない状態なので、 クラッカーに対して真面目にErrorDocumentを返すと、余計な情報を提供してしまうので、読み込まれないのではないでしょうか? 基本的に、BadRequestは、リクエストが不正な攻撃のケースもあるので、 セキュリティの都合上、任意のカスタム400ファイルを返せないケースもありうると思いますよ
>VirtualHost外のErrorDocument(つまりVirtualHostを設定していないところ)で拾えないのでしょうか。 これは、apacheのVirtualホストの説明を見ると解りますが、 VirtualHostを使用したら、全ての設定はいずれかのVirtualHostに属さなければなりません よって、いずれのVirtualホストにも該当しないリクエストは 『最初に記述されたVirtualホストをデフォルトホストとして処理されます 』※1 つまり、デフォルトの設定を行いたいのであれば、最初に記述したVirtualHostに記述してください >また、VirtualHostが決定できないとのことですが、 >私はドメインごとにエラーログを吐く様にしてありまして >Hostを消しても、 >GET /index.html HTTP/1.1 のアクセスで >アクセスしたいドメインのアクセスログは吐かれております。 このエラーログは※1に該当していませんか? つまり、一番最初に記述されたVirtualHostの設定内にあるエラーログではないでしょうか? 以下、「名前ベースのバーチャルホスト」のmanual抜粋 「リクエストが来ると、サーバはまず最初に <NameVirtualHost> にマッチする IP アドレスかどうかをチェックします。マッチすれば マッチした IP アドレスの <VirtualHost> のそれぞれのセクションの中から ServerName か ServerAlias に要求されたホスト名があるか探します。 見つかればそのサーバ用の設定を使います。マッチするバーチャルホスト が見つからなければ、マッチした IP アドレスの リストの最初にあるバーチャルホスト が使われます。 結果として、リストの最初のバーチャルホストが デフォルト の バーチャルホストになります。IP アドレスが『 NameVirtualHost ディレクティブにマッチした場合は、<<メインのサーバ の DocumentRoot は決して使われません>>』 『どのバーチャルホストにもマッチしないリクエストに対して、 特別な設定をしたいのであれば、設定ファイル中の最初の <VirtualHost> コンテナにそれを記述してください。』」
お礼
>このエラーログは※1に該当していませんか? >つまり、一番最初に記述されたVirtualHostの設定内にあるエラーログではないでしょうか? おっしゃる通りです。 一番最初のVirtualHostのログになっております。 >(1)Live HTTP Headersで、Hostを消してリプレイする(HTTP/1.1のとき) に関してはデフォルトが表示されるのはよく分かりました。 >(2)telnetで、ヘッダとボディの間の改行を省いてリクエストする に関しては、 >(1)URLのドメインのあとのどこかに%をつけて叩く がカスタムエラーページを表示できるので、 カスタムのエラーページが表示されていいと思うのですが。 これがおかしいですよね。 Hostはしっかりと送られていますし、 不正構文で400になりますし。
>最終的に決め手が欲しいです。 >証拠というのを証明したいですね >【デフォルトのエラーページが出る場合】 >(1)Live HTTP Headersで、Hostを消してリプレイする(HTTP/1.1のとき) 理由: まず、RFC2626「5.2 リクエストによって識別されるリソース(※1)」で 「もし、 Request-URI が absoluteURI でなく、リクエストが Host ヘッダフィールドを含んでいるならば、ホストは Host ヘッダフィールド値によって決定される。」とあります。 このケースだと、 VirtualHost(リソース)を決める要素(Host:)がサーバに送られていないから、リソースが決定できずデフォルトしか出しようがない 証拠:サーバへは下記のheaderでリクエストされているはずで、リソースを決定する情報が一切ありません。よって、デフォルト400ページです ------------------------------------------------ GET /index.html HTTP/1.1 以下にはHost:を除くヘッダフィールド識別子が続く ------------------------------------------------ たぶんあなたは、 firefoxの上URLには[absoluteURI(絶対URI)]で表示されているので、 ------------------------------------------------ GET http://hogehoge.jp/index.html HTTP/1.1 (※2) 以下にはHost:を除くヘッダフィールド識別子が続く ------------------------------------------------ 上記のheaderが送信されていると思い込んでいるのではないのでしょうか? では試しに※2を送信するとカスタム400ページが表示されるのか?ですが、「表示されない」です しかし※1では、 「もし、 Request-URI が absoluteURI ならば、ホストは Request-URI の一部である。リクエストにおけるどんな Host ヘッダフィールド値も無視されなければならない。」※3 とあるので、Hostヘッダが無くてもリソースを解決できるので、カスタム400ページを出すべきだと私は考えます よって、「apacheのバグじゃないの?」と思ってます そして、※3の件から、 ------------------------------------------------ GET http://実在のvirtualHost名/index.html HTTP/1.1 host:xyz.xyz ←実在しないホスト名 以下略 ------------------------------------------------ のようなヘッダを送信すると、ちゃんとHost:を無視して [absoluteURI]からリソース(実在のvirtualHost名の部分)を決定します >(2)telnetで、ヘッダとボディの間の改行を省いてリクエストする RFC2626でのBadRequestの説明は下記のとおりである 「リクエストは、不正な構文のためサーバに理解されなかった。」※4 このケースでは「ヘッダが構文エラーなので、これに含まれるHost情報はすべて信用することができない。 よって、デフォルトの400ページが表示される」と拡大解釈しました >【カスタムのエラーページが出る場合】 >(1)URLのドメインのあとのどこかに%をつけて叩く %の後には16進数でなければならないので、 16進数のフォーマットになっていなければ必然的に※4に該当するため、BadRequestが出ることには問題ないでしょう 当然ホスト名が送られている以上、リソースは解決できるので カスタム400ページが表示されます 例: http://hogehoge.jp/%index.html→カスタム400ページが表示される http://hogehoge.jp/%12index.html→カスタム404ページが表示される
お礼
分かりやすいご回答ありがとうございます。 >(1)Live HTTP Headersで、Hostを消してリプレイする(HTTP/1.1のとき) HostがないためVirtualHostを解釈できず、デフォルトしか返せない >(2)telnetで、ヘッダとボディの間の改行を省いてリクエストする Host情報すべてを信用することができないため、デフォルトを返している >(1)URLのドメインのあとのどこかに%をつけて叩く Host名が送られていて、構文エラーのためカスタムが表示できる と言ったところでしょうか。 質問ばかりで申し訳ないのですが、 最後にもう一つだけお願いいたします。 >(1)Live HTTP Headersで、Hostを消してリプレイする(HTTP/1.1のとき) のときに、 VirtualHostが決められないならば、 VirtualHost外のErrorDocument(つまりVirtualHostを設定していないところ)で拾えないのでしょうか。 また、VirtualHostが決定できないとのことですが、 私はドメインごとにエラーログを吐く様にしてありまして Hostを消しても、 GET /index.html HTTP/1.1 のアクセスで アクセスしたいドメインのアクセスログは吐かれております。 これは、LiveHTTPHeadersが良いように解釈してる感じでしょうかw
>それはどういうことなのかまったく分かりませんね。 改行を省いたので、 POSTのbody部がヘッダの一部とみなされてBadRequestになったと思われます 詳しくはerror_logに記録が残っているかもしれません
お礼
>改行を省いたので、 >POSTのbody部がヘッダの一部とみなされてBadRequestになったと思われます そういうことですね。 かなり話が見えてきたのですが、 最終的に決め手が欲しいです。 【デフォルトのエラーページが出る場合】 (1)Live HTTP Headersで、Hostを消してリプレイする(HTTP/1.1のとき) (2)telnetで、ヘッダとボディの間の改行を省いてリクエストする 【カスタムのエラーページが出る場合】 (1)URLのドメインのあとのどこかに%をつけて叩く どれも400を起こすアクセスなのに、 デフォルトとカスタムのページが出る違いは (1)なぜで、こういう証拠というのを証明したいですね・・・。 それなら、デフォルトのエラーページが出てしまう方は、 (2)カスタムエラーページに置き換えられないということなのでしょうか。
>「HTTP1.1準拠でHostnameを含む」ヘッダを含む場合の >再現方法はどうなりますでしょうか。 telnetでポート80をたたく方法が簡単です コマンドラインや、teraterm、等で「telnet テストサーバ 80」 あるいは、テストサーバ上で「telnet localhost 80」 繋がったら GET & HTTP/1.1 [Enter1回押す] Host: hogehoge.jp [Enter2回押す] 注1:teraterm等のターミナルソフトだとサーバからのレスポンスが全て返った瞬間に画面が閉じてしまうのでロギングしたほうがいいです。 パケットをキャプチャしてロギングしても可。 注2:teratermの場合、入力したコマンドが画面上にechoしないので、 サーバからレスポンスが返るまで画面は真っ黒です HTTP/1.0準拠の場合 GET & HTTP/1.0 [Enter2回押す] 上記の方法でErrorDocumentのHTMLファイルの内容がtext表示されます ErrorDocumentがhttp://で始まる場合は302が返ります あと GET & HTTP/1.1 [Enter2回押す] だと、Hostnameが無いためデフォルトの400画面のtextが返ります この件は#7で「RFC2616の14.23に該当するため~」と回答しましたが、 「ErrorDocumentが /hogehoge/hoge.html」 と定義してある場合(http://で始まらない場合)はhoge.htmlを返すべきなのでは? 実はapacheのバグでは?と思う次第です セキュリティ上なにか都合が悪いことでもあるのでしょうかね。
お礼
Dos窓からtelnetと、該当サーバ上で「telnet localhost 80」 をしましたところ GET & HTTP/1.1 [Enter1回押す] Host: hogehoge.jp [Enter2回押す] HTTP/1.0準拠の場合 GET & HTTP/1.0 [Enter2回押す] で400カスタムエラーページが、 GET & HTTP/1.1 [Enter2回押す] でデフォルトのエラーページが返ってきました。 なんだか変な気分ですw GET & HTTP/1.1 で400返すんであれば 拾ってくれればいいのにと思いますが・・・ 文字列以外のhttp://~やパスだと302のリダイレクトになってしまうから 無視されてデフォルトが表示されてしまうということなんですね。 それならURLに%を付けて200が返ってきて 400のカスタムエラーページが表示されるのが イマイチよくわかりませんが・・・w 長々とご回答いただきまして、ありがとうございました。
補足
Hoatを消す以外にも POSTで送信したときにヘッダ部分とボディの部分に 空白行を入れないでリクエストすると 400のデフォルトのエラーページが表示されてしまいますね・・・。 それはどういうことなのかまったく分かりませんね。
>(1)Host(1行目)を消してリクエスト >確かに、GET /~ HTTP/1.1 となっていました。 このテスト方法では、 apacheは、RFC2616の14.23に該当するため、「ステータスコード:400のHTMLファイルへのURI」をリダイレクト(ステータス:302)せず、直接ステータスコード400を返さざるを得ない状況でした よって、ErrorDocumentが文字列ならば「リダイレクトしない」で「直接ステータスコード400を返す」ので、「ErrorDocumentで指定した文字列」を返すことが出来たのです また、version 2.2.11のapacheのソースコードでは、 server/protcol.c Line:988 で r->status = HTTP_BAD_REQUEST; とした後、 同ファイル Line:1005 にて ap_send_error_response(r, 0); 関数を呼び出して、「直接ステータスコード400の送信レスポンスデータを作成」していますので、 「ErrorDocumentにHTMLファイルパスを指定していても無視」されます 上記のことから、 「ErrorDocument 400」に対してHTMLファイルを表示させたいのであれば、 「「HTTP1.0準拠」もしくは「HTTP1.1準拠でHostnameを含む」ヘッダを送信してテストしてください」 となります
お礼
詳しいご説明まことにありがとうございます。 >上記のことから、 >「ErrorDocument 400」に対してHTMLファイルを表示させたいのであれば、 >「「HTTP1.0準拠」もしくは「HTTP1.1準拠でHostnameを含む」ヘッダを送信してテストしてください」 >となります 「HTTP1.1準拠でHostnameを含む」ヘッダを含む場合の 再現方法はどうなりますでしょうか。 下記にも書かせていただきましたが %をつけると400のカスタムページが表示されるので それが再現方法になるということでしょうか。 (ただし、Live HTTP Headersを見ると200となっていますが)
まず、「400以外のコード」は「あなたが指定したHTMLが正常に表示」されるのですね??? 問題なのは、ステータスコード400に対する「あなたが指定したHTML」が 「直接URLで指定すると表示できる」けど、 「実際にエラーコード400を発生させて表示させようとする」と、 「デフォルトの400が表示される」または「あなたが指定した文字列が表示される」のですね? >デフォルトが表示されてしまいます。 ここでのデフォルトとは「ステータスコード400(Bad Request)」のデフォルト画面が表示されるのですね?? 決して、404(Not Found)の画面ではありませんね??? さらに確認ですが、 400のエラーはどのように発生させてテストされているのでしょうか? HTTP1.1準拠のHTTPヘッダを送信していませんか? HTTP1.0準拠のGETメソッド等をテストで使用しているならば、HTTPヘッダにHostnameを含まなくても、「あなたがErrorDocumentで指定した400のHTMLが表示される」ますが、 HTTP1.1準拠のGETメソッド等をテストで使用しているならば、HTTPヘッダにHostnameが含まれないと「あなたがErrorDocumentで指定した400のHTMLは表示されない」です あなたのエラー400のHTMLを表示させたいのであれば、 「HTTP1.0準拠」もしくは「HTTP1.1準拠でHostnameを含む」ヘッダを送信してテストしてみてください
お礼
>まず、「400以外のコード」は「あなたが指定したHTMLが正常に表示」されるのですね??? すべてではないですが、表示されます。 >「実際にエラーコード400を発生させて表示させようとする」と、 「デフォルトの400が表示される」または「あなたが指定した文字列が表示される」のですね? その通りです。 >ここでのデフォルトとは「ステータスコード400(Bad Request)」のデフォルト画面が表示されるのですね?? 決して、404(Not Found)の画面ではありませんね??? はい、Bad Requestです。 >400のエラーはどのように発生させてテストされているのでしょうか? FireFoxのアドオンのLive HTTP Headersでリプレイしています。 (1)Host(1行目)を消してリクエスト (2)JSESSIONIDを果てしなく長い値でリクエスト しています。 >あなたのエラー400のHTMLを表示させたいのであれば、 「HTTP1.0準拠」もしくは「HTTP1.1準拠でHostnameを含む」ヘッダを送信してテストしてみてください 確かに、GET /~ HTTP/1.1 となっていました。 再現方法がおかしいのかもしれませんね・・・。 ドメインの後に%を指定をしましたら、400が効きました。
>これは、どういったことでしょうか? たとえば、エラーファイルは /var/www/htdocs/errors/403.html 等になっているのかどうかをお聞きしたかったのですが、 >DocumentRoot /usr/local/A/B >ErrorDocument エラーコード /C/error.html >error.htmlの置いてある場所は >/usr/local/A/B/C/error.html とのことですので、 気にしないでください あと、 >(3)http://ドメイン/~/~/~.html >の3つを設定しましたが、表示されませんでした。 >ちなみに(3)は直接ブラウザで叩くと表示されます。 >これは一番の謎なんですw の件ですが、 やはり動きがおかしいですね ErrorDocumentにhttp://から記述すると apacheはまず、ブラウザにHTTPコード301(リダイレクト)で(3)のURLを通知し、 ブラウザは、(3)のURLへ再接続するのですが、 これはURLを直接入力して接続することと同じことですので、 直接入力が成功する以上、リダイレクトさえ正しくブラウザに返ってきていれば必ず成功するはずです でも、成功していないとなると、 virtualHostディレクティブ自体が機能していないと思います じゃあ、どこが間違っているのかとなりますと、 現状では伏字の部分的な抜粋のみしか拝見しておりませんので、 具体的にはお答えできないです なので、まず最初にお聞きしたいことは、 virtualHost自体機能しているのか?ということになります virtualHostのdocumentRoot直下のindex.html等は正しくブラウザでご覧になれますでしょうか?
お礼
>なので、まず最初にお聞きしたいことは、 >virtualHost自体機能しているのか?ということになります >virtualHostのdocumentRoot直下のindex.html等は正しくブラウザでご覧になれますでしょうか? VirtualHost自体は機能しております。 DocumentRoot直下のindex.htmlもブラウザで確認できます。 やはりErrorDocumentが正しく動作してくれません。 遅くなりましたが、ステータスコードで言いますと400です。 その他の404などは動作いたします。 400だけ、文字列は表示できますが、 カスタムエラーページへのパスを指定すると デフォルトが表示されてしまいます。
>vartualHost:443がよくわからないのですが。 HTTPSの要求に対しての処理を記述するディレクティブのことです こちらに記述してありながら、 テストはHTTPで行っているのではと考えた次第です 大丈夫だとは思いますが。 もしかしてvirtualHostがうまく機能していないのかな? 例えば http://ドメイン/index.html 等の普通のhtmlは問題なく見れていますでしょうか? 次に、errorDocumentはvirtualHostのdocumentRootの外においてありますでしょうか? 次に、 >(3)http://ドメイン/~/~/~.html を http://ホストのIPアドレス/~/~/~.html に変更してvirtualHost経由で存在しないHTMLを呼び出した場合 errorDocumentは表示されないでしょうか? あと、ありえないと思いますが、 ご使用のブラウザが、HTTPヘッダのHost識別子を送信していないとか・・・
お礼
まだ未確認で恐縮ですが、 確認させてください。 >次に、errorDocumentはvirtualHostのdocumentRootの外においてありますでしょうか? これは、どういったことでしょうか? ちなみに、 DocumentRoot /usr/local/A/B ErrorDocument エラーコード /C/error.html error.htmlの置いてある場所は /usr/local/A/B/C/error.html となっております。
>VirtualHost内でErrorDocumentを設定 ですが、vartualHost:443のディレクティブに対して ErrorDocumentの設定をしていて、 一生懸命ポート80でアクセスしているなんてことはないですよね?
お礼
度々のご回答まことにありがとうございます。 >vartualHost:443のディレクティブに対して >ErrorDocumentの設定をしていて、 >一生懸命ポート80でアクセスしているなんてことはないですよね? 知識不足で申し訳ありません。 vartualHost:443がよくわからないのですが。 ---------------------------------------------------- NameVirtualHost *:80 <VirtualHost *:80> DocumentRoot /usr/local/~/~/~ ServerName ~.~.~ ErrorDocument エラーコード 【ファイルへのパス】 JkMount ~ ・・・ </VirtualHost> ---------------------------------------------------- となっております。 上記でmarimari01さんがおっしゃってることに なってしまっているのでしょうか?
- 1
- 2
お礼
お礼が大変遅くなりまして、申し訳ございませんでした。 今まで多くのご回答ありがとうございました。 ヘッダとbodyの間にの改行を除いてリクエストされたときに カスタムの400ページを出力できる方法を 引き続き探ってみたいと思います。 ありがとうございました。