AJP協議總結與分析


Tomcat服務器通過Connector連接器組件與客戶程序建立連接,Connector組件負責接收客戶的請求,以及把Tomcat服務器的響應結果發送給客戶。默認情況下,Tomcat在server.xml中配置了兩種連接器:
  
  <!-- Define a non-SSL Coyote HTTP/1.1
  Connector on port 8080 -->
  <Connector port="8080"
  maxThreads="150"
  minSpareThreads="25"
  maxSpareThreads="75"
  enableLookups="false"
  redirectPort="8443"
  acceptCount="100"
  debug="0"
  connectionTimeout="20000"
  disableUploadTimeout="true" />
  
  <!-- Define a Coyote/JK2 AJP 1.3
  Connector on port 8009 -->
  <Connector port="8009"
  enableLookups="false"
  redirectPort="8443" debug="0"
  protocol="AJP/1.3" />
  
  第一個連接器監聽8080端口,負責建立HTTP連接。在通過瀏覽器訪問Tomcat服務器的Web應用時,使用的就是這個

http://blog.sina.com.cn/s/blog_6870d1e00100mv64.html

 

 

 

 

一般Tomcat默認的SSL端口號是8443,但是對於SSL標准端口號是443,這樣在訪問網頁的時候,直接使用https而不需要輸入端口號就可以訪問,如https://ip/ 
想要修改端口號,需要修改Tomcat的server.xml文件: 
1.non-SSL HTTP/1.1 Connector定義的地方,一般如下: 
     <Connector port="80" maxHttpHeaderSize="8192" 
                maxThreads="500" minSpareThreads="25" maxSpareThreads="75" 
                enableLookups="false" redirectPort="443" acceptCount="100" 
                connectionTimeout="20000" disableUploadTimeout="true" /> 
將其中的redirectPort端口號改為:443 
2.SSL HTTP/1.1 Connector定義的地方,修改端口號為:443,如下: 
<Connector     
   port="443" maxHttpHeaderSize="8192" 
   maxThreads="150" minSpareThreads="25" 
   maxSpareThreads="75" 
   enableLookups="false" 
   disableUploadTimeout="true" 
   acceptCount="100" scheme="https" 
   secure="true" 
   clientAuth="false" sslProtocol="TLS" 
   keystoreFile="conf/tomcat.keystore" 
   keystorePass="123456" /> 
3.AJP 1.3 Connector定義的地方,修改redirectPort為443,如下: 
     <Connector port="8009" 
                enableLookups="false" redirectPort="443" protocol="AJP/1.3" /> 

重新啟動Tomcat就可以了。到這一步可以形成訪問方式 https://ip/

4、強制https訪問

  在tomcat\conf\web.xml中的</welcome-file-list>后面加上這樣一段:

<login-config>  
    <!-- Authorization setting for SSL -->  
    <auth-method>CLIENT-CERT</auth-method>  
    <realm-name>Client Cert Users-only Area</realm-name>  
</login-config>  
<security-constraint>  
    <!-- Authorization setting for SSL -->  
    <web-resource-collection >  
        <web-resource-name >SSL</web-resource-name>  
        <url-pattern>/*</url-pattern>  
    </web-resource-collection>  
    <user-data-constraint>  
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>  
    </user-data-constraint>  
</security-constraint> 

注意:(如果對方使用的機器端口被占用)

需要切換端口來轉換數據:iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

 

 

 

AJP(Apache JServ Protocol)是定向包協議。因為性能原因,使用二進制格式來傳輸可讀性文本。WEB服務器通過TCP連接和SERVLET容器連接。

 

(格式顯示不好,本文已放附件中)

AJP協議是定向包(面向包)協議,采用二進制形式代替文本形式,以提高性能。Web Server一般維持和Web Container的多個TCP Connecions,即TCP連接池,多個request/respons循環重用同一個Connection。但是當Connection被分配(Assigned)到某個請求時,該請求完成之前,其他請求不得使用該連接。

Tcp Connection 具有兩種狀態:

(1). Idle
沒有請求正使用該連接。
(2). Assigned
當前連接正在處理某個請求.
 
數據類型:
 AJP協議中包括四種數據類型:Byte,  Boolean,  Integer and  String.
 Byte: 一個字節

  Boolean: 一個字節,1 = true, 0 = false。

 Integer:兩個字節,無符號整數,高位字節在前。
 String:可變字符串,最大長度為2^16. 字符串的前而會有二個字節(Integer型)表示字符串的長度,-1表示null。字符串后面會跟上 終結符”\0”,而且字符串長度不包括這個終結符。
 
AJP的包結構,圖表1:
包方向
0
1
2
3
4…(n+3)
Server->Container
0x12
0x34
數據長度(n)
數據(payload)
Container->Server
A
B
數據長度(n)
數據(payload)
                       圖表1
可以看出,從apache發向tomcat包都帶有0x1234頭,而從tomcat發向apache的包都帶有AB(ascii碼)頭,隨后二字節代表數據的長度(不包括前四個字節).所認AJP包的最大長度可以接近2^16,但目前的版本支持的最大包長度為2^13,即8K。
 
再看數據部分(payload),除Server->Container的請求體包外,其他包的數據部分的首字節為其消息類型(code),如下表(描述部分是原文,譯成中文本人認為更難理解,英文表義比中文是好一些):
方向
code
包類型
描述
Server->Container
2

Forward Request

Begin the request-processing cycle with the following data。

7
Shutdown

The web server asks the container to shut itself down

8
Ping

The web server asks the container to take control (secure login phase).

10
Cping

The web server asks the container to respond quickly with a CPong

none
Data

Size (2 bytes) and corresponding body data.

Container->Server
3
Send Body Chunk

Send a chunk of the body from the servlet container to the web server

4
Send Headers

Send the response headers from the servlet container to the web server

5
End Response
Marks the end of the response
6
Get Body Chunk

Get further data from the request if it hasn't all been transferred yet

9
CPong Reply
The reply to a CPing request
Forward Request包數據部分(payload)結構:
AJP13_FORWARD_REQUEST :=
    prefix_code      (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
    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)

    attributes      *(attribut_name attribute_value)

request_terminator (byte) OxFF

---------------------------------------------------------------------------------------------------------------------------------
req_header_name :=

sc_req_header_name | (string) [see below for how this is parsed]

---------------------------------------------------------------------------------------------------------------------------------

sc_req_header_name := 0xA0xx (integer)

req_header_value := (string)
---------------------------------------------------------------------------------------------------------------------------------

attribute_name := sc_a_name | (sc_a_req_attribute string)

attribute_value := (string)
 

(1)     prefix_code 所有的Forward Request包都是0x02.

(2)     Method: 一個字節,對方法的編碼,其對應如下(只列了部分):

Command Name

code
POST      
4
OPTIONS 
1
PUT       
5
GET     
2
DELETE   
6
HEAD    
3
TRACE    
7
(參考:http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html)
 

(3)     protocol, req_uri, remote_addr, remote_host, server_name, server_port, is_ssl: 每個請求包都有這幾個字段,格式都是 長度+字符串值+\0結束符。

(4)     num_headers: 請求頭的個數,兩個字節。
(5)     request_headers:
請求頭名稱分化為兩類, 一類請求頭被轉換為0xA0xx格式(如下表所示),其他請求頭仍然用原字符串編碼。
 
請求頭

Code 值

Code 名稱

accept

0xA001
SC_REQ_ACCEPT
accept-charset
0xA002
SC_REQ_ACCEPT_CHARSET
accept-encoding
0xA003
SC_REQ_ACCEPT_ENCODING
accept-language
0xA004
SC_REQ_ACCEPT_LANGUAGE
authorization
0xA005
SC_REQ_AUTHORIZATION
connection
0xA006
SC_REQ_CONNECTION
content-type
0xA007
SC_REQ_CONTENT_TYPE
content-length
0xA008
SC_REQ_CONTENT_LENGTH
cookie
0xA009
SC_REQ_COOKIE
cookie2
0xA00A
SC_REQ_COOKIE2
host
0xA00B

SC_REQ_HOST 0xA00C

pragma
0xA00C
SC_REQ_PRAGMA
referer
0xA00D
SC_REQ_REFERER
user-agent
0xA00E
SC_REQ_USER_AGENT
(6)     Java代碼讀取頭兩個字節的整數型,如果高位字節為”0xA0” ,則第二字節為上在列表的索引。如果高位字節不是”0xA0”,則這兩個字節為隨后請求頭名稱的長度。
(7)     Attributes:很少用,直接看tomcat文檔吧。     
(8)     request_terminator: 一個字節0xFF,請求結束符。
 
響應包數據部分(payload)結構:
AJP13_SEND_HEADERS :=
 prefix_code       4
 http_status_code (integer)
 http_status_msg   (string)
 num_headers       (integer)

 response_headers *(res_header_name header_value)

 
res_header_name :=
    sc_res_header_name | (string)   [see below for how this is parsed]
 

sc_res_header_name := 0xA0 (byte)

header_value := (string)
 
AJP13_SEND_BODY_CHUNK :=
 prefix_code   3
 chunk_length (integer)

 chunk        *(byte)

 
AJP13_END_RESPONSE :=
 prefix_code       5
 reuse             (boolean)
 
AJP13_GET_BODY_CHUNK :=
 prefix_code       6
 requested_length (integer)
 
1.       response_headers: 和請求頭一樣,一類響應頭被轉換為0xA0xx格式(如下表所示),其他響應頭名稱采用原字符串編碼。
請求頭

Code 值

Code 名稱

Content-Type
0xA001
SC_RESP_CONTENT_TYPE
Content-Language
0xA002
SC_RESP_CONTENT_LANGUAGE
Content-Length
0xA003
SC_RESP_CONTENT_LENGTH
Date
0xA004
SC_RESP_DATE
Last-Modified
0xA005
SC_RESP_LAST_MODIFIED
Location
0xA006
SC_RESP_LOCATION
Set-Cookie
0xA007
SC_RESP_SET_COOKIE
Set-Cookie2
0xA008
SC_RESP_SET_COOKIE2
Servlet-Engine
0xA009
SC_RESP_SERVLET_ENGINE
Status
0xA00A
SC_RESP_STATUS
WWW-Authenticate
0xA00B
SC_RESP_WWW_AUTHENTICATE
2.       reuse: 如果為1,表示該連接可以被子重用,否則這個連接應該關閉。
 
下面我們來看一個簡單AJP請求過程中抓到的請求包:
 

1,2字節是上文所說的Server->Container包頭,3,4字節表示包長度(0x01b0=432),即從第5個字節到最后的一個字節(ff)的長度。第5個字節(02)代表是”Forward Request”包。
第6個字節(02)代表是Get請求。第7,8字節(0x0008)代表 protocol字符串的長度,后8個字節為protocol字符串(HTTP/1.1),第9個字節為protocol字符串的終結符“\0”。
18-41字節 代表req_uri字符串(0x15+2+1=24個)。
42-53 字節代表remote_addr字符串(0x09+2+1=12個)
54-55 兩字節(0xffff=-1)代表null字符串,即remote_host不存在。
56-67 兩字節代表server_name字符串(0x09+2+1=12個)
68-69兩字節(0x0050=80)代表server_port
70字節(0x00)代表is_ssl為false
71-72兩字節(0x0009)代表該請求有9個請求頭,如圖中的前9個紅色 橢圓.
第10個紅色橢圓(0x06)代表Attributes的route.
第11個紅橢圓之后,代表AJP_REMOTE_PORT與JK_LB_ACTIVATION兩個請求屬性.
最后一個字節0xFF表示請求結束。
響應頭數據包:
 

和請示頭比較類似,不再細描述。其中第5個字節0x04代表”Send Headers”響應。
並且沒有終結符字節0xFF.
 
響應正文數據包:

 響應結束End Response:
 
其中最后一個字節(01),代表當前連接仍然可用。
(完)

http://guojuanjun.blog.51cto.com/277646/688559/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM