AJPv13拡張提案

はじめに

このドキュメントは、ajp13としても知られる、現在のApache JServ Protocolバージョン1.3の進化に関する提案です。ここではプロトコル全体を網羅するのではなく、ajp13からの追加機能のみを説明します。このn回目の改訂版には、tomcat-devリストからのコメントと開発中に発見された欠点が含まれています。

AJP13で欠けている機能

ajp13は、TomcatのようなサーブレットエンジンをApacheのようなWebサーバーに接続するための優れたプロトコルです。

  • 永続的な接続を使用して、リクエストごとに再接続する時間を回避します。
  • 多くのHTTPコマンドをエンコードして、ストリームサイズを削減します。
  • Webサーバーからサーブレットエンジンに多くの情報(SSL証明書など)を送信します。

しかし、ajp13には以下のサポートが欠けています。

  • Webサーバーとサーブレットエンジン間のセキュリティ。誰でもajp13ポートに接続できます(ログインメカニズムは使用されません)。たとえば、telnetで接続し、データを送信せずにリモートスレッドを稼働状態に保つことができます(接続にタイムアウトがありません)。
  • サーブレットエンジンからWebサーバーに渡されるコンテキスト情報。JK(Webサーバーコネクタ)の設定の一部は、Webサーバーに処理するURIを指示することです。mod_jk JkMountディレクティブは、WebサーバーにどのURIをサーブレットエンジンに転送する必要があるかを指示しました。サーブレットエンジンは既に処理するURIを認識しており、TC 3.3は既に利用可能なコンテキストのリストからJKの構成ファイルを生成できます。
  • サーブレットエンジンからWebサーバーへのコンテキストの状態更新。ISPや仮想ホスティング事業者のような、Tomcatのファームを持つ大規模なサイトでは、管理目的でコンテキストを停止する必要がある場合があります。その場合、フロントWebサーバーは、コンテキストが現在ダウンしていることを認識し、最終的にリクエストを別のTomcatにリレーする必要があります。
  • リクエストを送信する前に接続の状態を確認します。実際、JKはリクエストをサーブレットエンジンに送信し、次に応答を待ちます。しかし、ソケットAPIの優れた点の1つは、エラーを報告せずにクローズされた接続にwrite()できることです。ただし、クローズされた接続へのread()はエラーコードを返します。

AJP13への提案された追加機能

ここでは、AJP13に追加できる機能とアドオンについて説明します。このドキュメントは提案であるため、最初はかなりの混乱が予想されます。tomcatリストでの議論は、ポイントの明確化、機能の追加に役立ちますが、現在のリストは「必要最小限」のようです。

  • 接続時の高度なログイン機能
  • Webサーバーとサーブレットエンジンに共有秘密鍵が存在する基本的な認証システム。
  • 将来AJP13に機能が追加された場合でも、現在の実装が引き続き機能するようにするための基本的なプロトコルネゴシエーション。
  • 「不明なパケット」のクリーンな処理
  • Webサーバーからサーブレットエンジンに渡される拡張環境変数。
  • Servlet 2.3 APIで必要な追加のSSL情報(SSL_KEY_SIZEなど)を追加します。

高度なログイン

  1. WEBサーバーはLOGIN INIT CMD + ネゴシエーションデータ + WEBサーバー情報を送信します。
  2. TOMCATはLOGIN SEED CMD + ランダムデータで応答します。
  3. WEBサーバーはランダムデータ+秘密データのMD5を計算します。
  4. WEBサーバーはLOGIN COMP CMD + MD5(秘密データ + ランダムデータ)を送信します。
  5. TOMCATはLOGIN STATUS CMD + ネゴシエートされたデータ + サーブレットエンジン情報で応答します。
DOS攻撃を防ぐために、サーブレットエンジンはLOGIN CMDを15/30秒間だけ待機し、管理者の調査のためにタイムアウト例外を報告します。ログインコマンドには、圧縮機能、暗号化、コンテキスト情報(起動時)、実行時のコンテキスト更新(アップ/ダウン)、SSL環境変数のレベル、サポートされるAJPプロトコルレベル(レベル1/レベル2/レベル3...)などの基本的なプロトコルネゴシエーション情報が含まれます。Webサーバー情報は、Webサーバー情報とコネクタ名(例:Apache 1.3.26 + mod_ssl 2.8.8 + mod_jk 1.2.41 + mod_perl 1.25)を含みます。サーブレットエンジンは、ネゴシエーションマスクを独自のマスク(実行可能なもの)でマスクし、ログインが受け入れられたときにそれを返します。これにより、Webサーバー上の基本的なAJP13実装(レベル1)が、サーブレットエンジン側、またはその逆の、より高度なプロトコルハンドラで動作するようになります。AJP13は小型で高速になるように設計されているため、Webサーバーに存在する多くのSSL情報はサーブレットエンジンに転送されません。ここでは、クライアントSSLデータ(証明書)、サーバーSSLデータ、使用される暗号、およびその他のデータ(タイムアウトなど)に関する詳細情報を提供するために、4つのネゴシエーションフラグを追加します。

メッセージストリーム

+----------------+------------------+-----------------+
| LOGIN INIT CMD | NEGOCIATION DATA | WEB SERVER INFO |
+----------------+------------------+-----------------+

+----------------+----------------+
| LOGIN SEED CMD | MD5 of entropy |
+----------------+----------------+

+----------------+----------------------------+
| LOGIN COMP CMD | MD5 of RANDOM + SECRET KEY |
+----------------+----------------------------+

+-----------+---------------+---------------------+
| LOGOK CMD | NEGOCIED DATA | SERVLET ENGINE INFO |
+-----------+---------------+---------------------+

+------------+--------------+
| LOGNOK CMD | FAILURE CODE |
+------------+--------------+
  • LOGIN INIT CMD、LOGIN SEED CMD、LOGIN COMP CMD、LOGOK CMD、LOGNOK CMDは1バイト長です。
  • MD5、ランダム+秘密鍵のMD5は32文字長です。
  • ネゴシエーションデータ、ネゴシエートされたデータ、障害コードは32ビット長です。
  • WEBサーバー情報、サーブレットエンジン情報はCStringです。
秘密鍵はworkers.propertiesの新しいプロパティsecretkeyによって設定されます。
worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13
worker.ajp13.secretkey=myverysecretkey

シャットダウン機能

AJP13には、シャットダウンコマンドであるAJP12の機能がありません。ログアウトは、サーブレットエンジンに自身をシャットダウンするように指示します。

+--------------+----------------------------+
| SHUTDOWN CMD | MD5 of RANDOM + SECRET KEY |
+--------------+----------------------------+

+------------+
| SHUTOK CMD |
+------------+

+-------------+--------------+
| SHUTNOK CMD | FAILURE CODE |
+-------------+--------------+
  • SHUTDOWN CMD、SHUTOK CMD、SHUTNOK CMDは1バイト長です。
  • ランダム+秘密鍵のMD5は32文字長です。
  • 障害コードは32ビット長です。

拡張環境変数機能

注:JKでAJP13に取り組んでいる間、「JkEnvVar」を発見しました。次の「拡張環境変数機能」の説明は、元の実装ですでに利用可能であるため、拡張AJP13では実装されない場合があります。説明:多くのユーザーは、Webサーバーの環境変数の一部がサーブレットエンジンに渡されることを望んでいます。ネットワークトラフィックを削減するために、Webサーブレットは、外部変数をより短い形式で記述するテーブルを送信します。ここでは、AJP13に既に存在する機能である属性リストを使用します。AJP13には以下があります。

AJP13_FORWARD_REQUEST :=
    prefix_code      2
    method           (byte)
    protocol         (string)
    req_uri          (string)
    remote_addr      (string)
    remote_host      (string)
    server_name      (string)
    server_port      (integer)
    is_ssl           (boolean)
    num_headers      (integer)
    request_headers *(req_header_name req_header_value)

    ?context       (byte string)
    ?servlet_path  (byte string)
    ?remote_user   (byte string)
    ?auth_type     (byte string)
    ?query_string  (byte string)
    ?route         (byte string)
    ?ssl_cert      (byte string)
    ?ssl_cipher    (byte string)
    ?ssl_session   (byte string)

    ?attributes   *(attribute_name attribute_value)
    request_terminator (byte)
短い「Webサーバー属性名」を使用すると、ネットワークトラフィックが削減されます。
+-------------------+---------------------------+-------------------------------+----+
| EXTENDED VARS CMD | WEB SERVER ATTRIBUTE NAME | SERVLET ENGINE ATTRIBUTE NAME | ES |
+-------------------+---------------------------+-------------------------------+----+
例:
JkExtVars S1 SSL_CLIENT_V_START javax.servlet.request.ssl_start_cert_date
JkExtVars S2 SSL_CLIENT_V_END   javax.servlet.request.ssl_end_cert_date
JkExtVars S3 SSL_SESSION_ID     javax.servlet.request.ssl_session_id


+-------------------+----+-------------------------------------------+
| EXTENDED VARS CMD | S1 | javax.servlet.request.ssl_start_cert_date |
+-------------------+----+-------------------------------------------+
+----+-----------------------------------------+
| S2 | javax.servlet.request.ssl_end_cert_date |
+----+-----------------------------------------+
+----+-----------------------------------------+
| S3 | javax.servlet.request.ssl_end_cert_date |
+----+-----------------------------------------+
拡張AJP13での送信中に、S1、S2、S3を含む属性名と、2001/01/03、2002/01/03、0123AFE56の属性値が表示されます。この例では、拡張SSL変数の使用法を示していますが、カスタム認証変数などの「個人用」Webサーバー変数をサーブレットエンジンで再利用できます。コストは、AJPトラフィックで数バイト増えるだけです。
  • EXTENDED VARS CMDは1バイト長です。
  • WEBサーバー属性名、サーブレットエンジン属性名はCStringです。
  • ESは空のCStringです。

サーブレットエンジンからWebサーバーへのコンテキスト情報の転送

ログオンフェーズの直後に、Webサーバーはサーブレットエンジンによって処理されるコンテキストとURL / URIのリストを要求します。多くのサイトでのインストールが容易になり、tomcat-userリストでの構成に関する質問が減り、サーブレットAPI 2.3に対応できるようになります。このモードは、新しいディレクティブJkAutoMountによってアクティブ化されます。例:JkAutoMount examples myworker1 / examples / サーブレットエンジンによって処理されるすべてのコンテキストを取得する場合、ワイルドカードを使用できます。例:JkAutoMount * myworker1 * サーブレットエンジンには、/ examples、/ admin、/ testなど、多くのコンテキストを含めることができます。特定のワーカーに一部のコンテキストのみを使用する場合があります。これは以前、たとえばApache HTTP Serverでは、Apacheの各[仮想]領域でJkMountを手動で設定することによって行われました。Webサーバーが仮想ホスティングをサポートしている場合は、その情報をサーブレットエンジンにも転送します。サーブレットエンジンは、その仮想ホストのコンテキストのみを返します。この場合、サーブレットエンジンは、これらの特定の仮想サーバー(server.xmlで定義)に一致するURL / URIのみを返します。この機能は、負荷分散構成でTomcatの大規模ファームを相互運用するISPおよび大規模サイトに役立ちます。

+-----------------+-------------------+----------+----------+----+
| CONTEXT QRY CMD | VIRTUAL HOST NAME | CONTEXTA | CONTEXTB | ES |
+-----------------+-------------------+----------+----------+----+

+------------------+-------------------+----------+-------------------+----------+---------------+----+
| CONTEXT INFO CMD | VIRTUAL HOST NAME | CONTEXTA | URL1 URL2 URL3 ES | CONTEXTB | URL1 URL2 ... | ES |
+------------------+-------------------+----------+-------------------+----------+---------------+----+
コンテキストクエリを使用して、コンテキストのリストに対してリモートサーブレットエンジンによって処理されるURL / MIMEのリストを検出します。ワイルドカードモードでは、CONTEXTAには「*」のみが含まれます。
  • CONTEXT QRY CMDとCONTEXT INFO CMDは1バイト長です。
  • 仮想ホスト名はCStringです。つまり、ヌルバイト(/ 0)で終わる文字の配列です。
  • 空の文字列はヌルバイト(/ 0)だけです。
  • ESは空のCStringです。URI / URLの終わりまたはCONTEXTの終わりを示します。
注意
VirtualModeを使用しない場合、仮想ホスト名は「*」です。この場合、サーブレットエンジンは処理されるすべてのコンテキストを送信します。

サーブレットエンジンからWebサーバーへのコンテキスト情報の更新

コンテキストの更新は、コンテキストが非アクティブ化/再アクティブ化されるたびにサーブレットエンジンから送信されるメッセージです。更新は、ディレクティブJkUpdateMountが使用されている場合に使用されます。このディレクティブは、AJP13_CONTEXT_UPDATE_NEGフラグを設定します。例:JkUpdateMount myworker1

+--------------------+-------------------+----------+--------+----------+--------+----+
| CONTEXT UPDATE CMD | VIRTUAL HOST NAME | CONTEXTA | STATUS | CONTEXTB | STATUS | ES |
+--------------------+-------------------+----------+--------+----------+--------+----+
  • CONTEXT UPDATE CMD、STATUSは1バイト長です。
  • 仮想ホスト名、CONTEXTはCStringです。
  • ESは空のCStringです。CONTEXTの終わりを示します。
注意
VirtualModeが使用されていない場合、仮想ホスト名は「*」です。STATUSは、コンテキストがUP / DOWN / INVALIDであるかを示す1バイトです。

サーブレットエンジンへのコンテキストステータスクエリ

このクエリは、Webサーバーが特定のコンテキストがUP、DOWN、またはINVALID(削除する必要がある)であるかどうかを判断するために使用されます。

+-------------------+--------------------+----------+----------+----+
| CONTEXT STATE CMD |  VIRTUAL HOST NAME | CONTEXTA | CONTEXTB | ES |
+-------------------+--------------------+----------+----------+----+

+-------------------------+-------------------+----------+--------+----------+--------+----+
| CONTEXT STATE REPLY CMD | VIRTUAL HOST NAME | CONTEXTA | STATUS | CONTEXTB | STATUS | ES |
+-------------------------+-------------------+----------+-------------------+--------+----+
  • CONTEXT STATE CMD、CONTEXT STATE REPLY CMD、STATUSは1バイト長です。
  • 仮想ホスト名、CONTEXTはCStringです。
  • ESは空のCStringです。
注意
VirtualModeが使用されていない場合、仮想ホスト名は空の文字列です。

不明なパケットの処理

適切にネゴシエートされたプロトコルを使用している場合でも、一方の側(Webサーバーまたはサーブレットエンジン)が理解できないメッセージを受信する場合があります。この場合、受信者は、処理されていないメッセージを添付した「UNKNOW PACKET CMD」を送信します。

+--------------------+------------------------+-------------------+
| UNKNOWN PACKET CMD | UNHANDLED MESSAGE SIZE | UNHANDLED MESSAGE |
+--------------------+------------------------+-------------------+
メッセージによっては、送信者はエラーを報告し、可能であればメッセージを別のエンドポイントに転送しようとします。
  • UNKNOWN PACKET CMDは1バイト長です。
  • 処理されていないメッセージサイズは16ビット長です。
  • 処理されていないメッセージはバイトの配列です(長さは処理されていないメッセージサイズに含まれています)。
注意
処理されていないメッセージサイズを追加しました(開発中)。

リクエストを送信する前の接続の検証

注意: この機能は、Webサーバー側でリクエストを転送する前に追加のIO(読み取り)が必要になるため、通常のプロセスを遅くする可能性があるため、使用されない場合があります。ソケットAPIの利点の1つは、ハーフクローズドソケットに書き込むことができることです。サーブレットエンジンがソケットを閉じると、Webサーバーはソケットへの次のread()で初めてそれを検出します。基本的に、AJP13プロトコルでは、WebサーバーはHTTPヘッダーとHTTPボディ(8KのチャンクごとのPOST)をサーブレットエンジンに送信し、応答の受信を試みます。接続が切断された場合、Webサーバーは受信時にのみそれを認識します。バッファリングスキームを使用することもできますが、8koを超えるデータでサーブレットエンジンをアップロード操作に使用するとどうなるでしょうか? AJP13プロトコルのハックは、サービスの終了後に読み取るバイトを追加することです。

EXAMPLE OF DISCUSSION BETWEEN WEB SERVER AND SERVLET ENGINE

AJP HTTP-HEADER (+ HTTP-POST)   (WEB->SERVLET)

AJP HTTP-REPLY					(SERVLET->WEB)

AJP END OF DISCUSSION			(SERVLET->WEB)
						
---> AJP STATUS 				(SERVLET->WEB AJP13)
AJP STATUSは、リクエスト/レスポンス#Nの最後ではなく、次のセッションの開始時にサーブレットエンジンによって読み取られます。さらに、WebサーバーはOS依存関数(またはより優れたAPR関数)を使用して、読み取るデータがさらに存在するかどうかを判断することもできます。そして、そのデータはCONTEXT Updatesになる可能性があります。これにより、Webサーバーが無効化されたコンテキストにリクエストを送信することを回避できます。この場合、ロードバランシングが使用されている場合、リクエストを処理する別のサーブレットエンジンが検索されます。そして、この機能は、ISPやTomcatのファームを持つ大規模サイトが、サービスを中断することなくサーブレットエンジンを更新するのに役立ちます。
+------------+-------------+
| STATUS CMD | STATUS DATA |
+------------+-------------+
  • STATUS CMDとSTATUS DATAは1バイト長です。

結論

拡張AJP13プロトコルの目標は、元のAJP13の制限のいくつかを克服することです。より簡単な構成、大規模サイトとTomcatファームのより良いサポート、シンプルな認証システム、およびプロトコル更新のプロビジョニング。JK(ネイティブ)およびサーブレットエンジン(Java)で安定したajp13実装を使用することは、よく知られているajp13の合理的な進化です。

拡張AJP13のインデックスにおけるコマンドとID

AJP13プロトコルに追加されるコマンドとIDのインデックス

コマンドID

コマンド名コマンド番号
AJP13_LOGINIT_CMD0x10
AJP13_LOGSEED_CMD0x11
AJP13_LOGCOMP_CMD0x12
AJP13_LOGOK_CMD0x13
AJP13_LOGNOK_CMD0x14
AJP13_CONTEXT_QRY_CMD0x15
AJP13_CONTEXT_INFO_CMD0x16
AJP13_CONTEXT_UPDATE_CMD0x17
AJP13_STATUS_CMD0x18
AJP13_SHUTDOWN_CMD0x19
AJP13_SHUTOK_CMD0x1A
AJP13_SHUTNOK_CMD0x1B
AJP13_CONTEXT_STATE_CMD0x1C
AJP13_CONTEXT_STATE_REP_CMD0x1D
AJP13_UNKNOW_PACKET_CMD0x1E

ネゴシエーションフラグ

コマンド名番号説明
AJP13_CONTEXT_INFO_NEG0x80000000Webサーバーはログイン後にコンテキスト情報を必要とする
AJP13_CONTEXT_UPDATE_NEG0x40000000Webサーバーはコンテキストの更新を必要とする
AJP13_GZIP_STREAM_NEG0x20000000Webサーバーは圧縮ストリームを必要とする
AJP13_DES56_STREAM_NEG0x10000000Webサーバーは秘密鍵を使用した暗号化されたDES56ストリームを必要とする
AJP13_SSL_VSERVER_NEG0x08000000サーバーSSL変数の拡張情報
AJP13_SSL_VCLIENT_NEG0x04000000クライアントSSL変数の拡張情報
AJP13_SSL_VCRYPTO_NEG0x02000000暗号SSL変数の拡張情報
AJP13_SSL_VMISC_NEG0x01000000その他のSSL変数の拡張情報

ネゴシエーションID番号説明
AJP13_PROTO_SUPPORT_AJPXX_NEG0x00FF0000サポートされているプロトコルのマスク
AJP13_PROTO_SUPPORT_AJP13L1_NEG0x00010000通信はAJP13レベル1を使用できる
AJP13_PROTO_SUPPORT_AJP13L2_NEG0x00020000通信はAJP13レベル2を使用できる
AJP13_PROTO_SUPPORT_AJP13L3_NEG0x00040000通信はAJP13レベル3を使用できる

その他のすべてのフラグは、将来の使用のために予約されているため、0に設定する必要があります。

失敗ID

失敗ID番号
AJP13_BAD_KEY_ERR0xFFFFFFFF
AJP13_ENGINE_DOWN_ERR0xFFFFFFFE
AJP13_RETRY_LATER_ERR0xFFFFFFFD
AJP13_SHUT_AUTHOR_FAILED_ERR0xFFFFFFFC

ステータス

失敗ID番号
AJP13_CONTEXT_DOWN0x01
AJP13_CONTEXT_UP0x02
AJP13_CONTEXT_OK0x03