ไม่อนุญาตให้ใช้วิธีการ HTTP บน Tomcat แบบตรงตามตัวพิมพ์ใหญ่ - เล็ก?


11

ฉันใส่สิ่งต่อไปนี้ใน web.xml ของแอปพลิเคชันของฉันเพื่อพยายามไม่อนุญาต PUT, DELETE และอื่น ๆ :

 <security-constraint>
 <web-resource-collection>
  <web-resource-name>restricted methods</web-resource-name>
  <url-pattern>/*</url-pattern>
  <http-method>DELETE</http-method>
  <http-method>PUT</http-method>
  <http-method>SEARCH</http-method>
  <http-method>COPY</http-method>
  <http-method>MOVE</http-method>
  <http-method>PROPFIND</http-method>
  <http-method>PROPPATCH</http-method>
  <http-method>MKCOL</http-method>
  <http-method>LOCK</http-method>
  <http-method>UNLOCK</http-method>
  <http-method>delete</http-method>
  <http-method>put</http-method>
  <http-method>search</http-method>
  <http-method>copy</http-method>
  <http-method>move</http-method>
  <http-method>propfind</http-method>
  <http-method>proppatch</http-method>
  <http-method>mkcol</http-method>
  <http-method>lock</http-method>
  <http-method>unlock</http-method>
 </web-resource-collection>
 <auth-constraint />
 </security-constraint>

ตกลงดังนั้นตอนนี้:

หากฉันทำคำขอด้วยวิธีการของDELETEฉันได้รับ 403 กลับ

หากฉันทำคำขอด้วยวิธีการของdeleteฉันได้รับ 403 กลับ

แต่

ถ้าฉันทำตามคำขอด้วยวิธีการของDeLeTeฉันได้ตกลง!

ฉันจะทำให้มันไม่อนุญาตให้ใช้ตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ได้อย่างไร

แก้ไข: ฉันทดสอบด้วยโปรแกรม C #:

    private void button1_Click(object sender, EventArgs e)
    {
        textBox1.Text = "making request";
        System.Threading.Thread.Sleep(400);
        WebRequest req = WebRequest.Create("http://serverurl/Application/cache_test.jsp");
        req.Method = txtMethod.Text;
        try
        {
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();

            textBox1.Text = "Status: " + resp.StatusCode;

            if (resp.StatusCode == System.Net.HttpStatusCode.OK)
            {
                WebHeaderCollection header = resp.Headers;
                using (System.IO.StreamReader reader = new System.IO.StreamReader(resp.GetResponseStream(), ASCIIEncoding.ASCII))
                {
                    //string responseText = reader.ReadToEnd();
                    textBox1.Text += "\r\n" + reader.ReadToEnd();
                }
            }
        }
        catch (Exception ex)
        {
            textBox1.Text = ex.Message;
        }
    }

txtMethod.Textเป็นกล่องข้อความที่ฉันพิมพ์ชื่อวิธี เมื่อมี 403 ข้อยกเว้นจะถูกโยนทิ้งซึ่งติดอยู่ในบล็อก catch

cache_test.jsp ประกอบด้วย:

<%
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma","no-cache");

out.print("Method used was: "+request.getMethod());
%>

คุณทดสอบมันยังไง?
ซาเวียร์ลูคัส

@XavierLucas เพิ่มไปยังคำถาม
developerwjk

1
โปรแกรมทดสอบของคุณมีข้อบกพร่อง HttpWebRequestจะคำนึงถึงขนาดตัวพิมพ์ และการแปลงเมธอด HTTP มาตรฐานเป็นตัวพิมพ์ใหญ่ นอกจากนี้ยังมีการบันทึกไว้ว่าอนุญาตให้ใช้เมธอด HTTP มาตรฐานเท่านั้น ตัวเลือกที่ดีที่สุดคือการใช้สตรีม TCP ดิบ (เช่นใน netcat หรือ PuTTY raw หรือ telnet เป็นต้น)
Bob

1
@ บ๊อบฉันทำใน. NET 2.0 ใน Visual C # 2005 Express และไม่พบปัญหาใด ๆ มันกำลังส่งสิ่งที่ฉันพิมพ์ ดังนั้นพวกเขาจะต้องมีการเปลี่ยนแปลงในรุ่นที่ใหม่กว่า
developerwjk

1
@Bob, ฮ่า ๆ เอกสารของ Microsoft ผิด / ทำให้เข้าใจผิด สำหรับเวอร์ชั่น. NET 2.0 พวกเขายังพูดว่า "คุณสมบัติเมธอดสามารถตั้งค่าเป็นกริยาโปรโตคอล HTTP 1.1: GET, HEAD, POST, PUT, DELETE, TRACE หรือ OPTIONS" แต่มันก็ไม่ได้ จำกัด อยู่แค่นั้นในทางปฏิบัติ
developerwjk

คำตอบ:


13

โดยไม่คำนึงถึงพฤติกรรมที่ไม่ถูกต้องของ Tomcat เกี่ยวกับมาตรฐาน HTTP คุณควรใช้บัญชีขาวเพื่ออนุญาตวิธีการเฉพาะแทนที่จะเป็นบัญชีดำ

ตัวอย่างเช่นรายการที่อนุญาตต่อไปนี้จะบล็อกวิธีการทั้งหมดยกเว้นตัวพิมพ์เล็ก GETและตัวพิมพ์HEADใหญ่

<security-constraint>
    <web-resource-collection>
        <web-resource-name>restricted methods</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method-omission>GET</http-method-omission>
        <http-method-omission>HEAD</http-method-omission>
    </web-resource-collection>
    <auth-constraint />
</security-constraint>

(หมายเหตุ: ต้องใช้ Tomcat 7+ ผู้ที่ใช้รุ่นที่เก่ากว่าจะต้องตรวจสอบโซลูชันอื่น ๆ เช่นตัวกรองเซิร์ฟเล็ต)

อ้าง


เมื่อฉันทำเช่นนั้นด้วย POST รวมอยู่ด้วยฉันไปที่หน้าบนเว็บไซต์ (เพียงคลิกที่ลิงค์หรือคั่นหน้าไว้) และทำให้ฉันมี 405
developerwjk

ที่จริงแล้วมันทำให้ฉันสถานะ HTTP 403 - การเข้าถึงทรัพยากรที่ร้องขอได้รับการปฏิเสธ
developerwjk

ฉันลองใน web.xml ของเซิร์ฟเวอร์แล้วมันก็ไม่สนใจการละเว้นและเพิ่งปิดกั้นทุกอย่าง เอาออกไป พยายามใน web.xml ของแอปพลิเคชันและอีกครั้งมันเพิ่งปิดกั้นทุกวิธีและละเว้นการละเว้น
developerwjk

ยังพยายามตรงตามด้านบน แต่ถอดออก<auth-constraint />แล้วก็อนุญาตทุกอย่างได้
developerwjk

2
@developerwjk http-method-omissionถูกกำหนดเป็นครั้งแรกในใน Servlet 3.0 API ซึ่งดำเนินการโดย Tomcat 7+: tomcat.apache.org/whichversion.html น่าเสียดายนี่หมายความว่าสิ่งนี้จะไม่ทำงานใน Tomcat 6 และรุ่นเก่ากว่า (หมายเหตุ: 5 คือ EOL แล้ว) คุณสามารถลองวิธีแก้ปัญหาที่เสนออื่น ๆ ในคำถาม SO ที่เชื่อมโยงซึ่งแนะนำให้ตั้งค่าแยกสองตัวsecurity-constraint- ฉันไม่สามารถยืนยันได้ว่าผลงานหนึ่งใน 7 นั้นไม่ได้รวมไว้ในคำตอบนี้
Bob

13

หลังจากการทดสอบอย่างรวดเร็วเกี่ยวกับเซิร์ฟเวอร์สุ่มบางตัวที่มีServer: Apache-Coyotteลายเซ็นส่วนหัวในการตอบกลับ HTTP ของพวกเขาดูเหมือนว่าคุณจะถูกต้องในขณะที่ส่งget / HTTP/1.1\r\nHost: <target_IP>\r\n\r\nด้วยการเชื่อมต่อ netcat แบบธรรมดาที่ทำงานได้ทุกครั้งในขณะที่ควรได้รับ 400 โค้ด HTTP

ตัวอย่างเช่น

$ { echo -en "get / HTTP/1.1\r\nHost: <target_IP>:8080\r\n\r\n" ; } | nc <target_IP> 8080

01:14:58.095547 IP 192.168.1.3.57245 > <target_IP>.8080: Flags [P.], seq 1:42, ack 1, win 115, options [nop,nop,TS val 4294788321 ecr 0], length 41
E..]C.@.@..Y......p.....A..v.......s.......
..D.....get / HTTP/1.1
Host: <target_IP>:8080

[...]

01:14:58.447946 IP <target_IP>.8080 > 192.168.1.3.57245: Flags [.], seq 1:1409, ack 43, win 65494, options [nop,nop,TS val 7981294 ecr 4294787971], length 1408
E...f...i.....p.............A..............
.y....C.HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Transfer-Encoding: chunked
Date: Tue, 27 Jan 2015 00:15:14 GMT

ฉันต้องบอกว่าฉันตกใจเล็กน้อยที่นี่และฉันจะไม่แปลกใจที่เห็นพฤติกรรมนั้นขยายไปถึงวิธี HTTP / 1.1 ทั้งหมดในกรณีเช่นนี้

คุณควรกรอกรายงานบั๊กเกี่ยวกับเครื่องมือติดตามบั๊กของพวกเขาและส่งอีเมลไปยังรายชื่อผู้รับจดหมายที่เหมาะสมเพราะเป็นการละเมิดที่น่าเกลียดอย่างหนึ่งของ RFC 2616 (ดูด้านล่าง) ด้วยผลกระทบที่ไม่ดี

5.1.1 วิธีการ

  The Method  token indicates the method to be performed on the
  resource identified by the Request-URI. The method is case-sensitive.

      Method         = "OPTIONS"                ; Section 9.2
                     | "GET"                    ; Section 9.3
                     | "HEAD"                   ; Section 9.4
                     | "POST"                   ; Section 9.5
                     | "PUT"                    ; Section 9.6
                     | "DELETE"                 ; Section 9.7
                     | "TRACE"                  ; Section 9.8
                     | "CONNECT"                ; Section 9.9
                     | extension-method
      extension-method = token

3
หมายเหตุ: ตอนนี้ RFC 2616 ถูกแทนที่ด้วย RFC 7230-7235 RFC 7230 § 3.1.1 : "วิธีการร้องขอเป็นกรณี ๆ ไป" RFC 7231 § 4 : "โดยการประชุมวิธีมาตรฐานจะถูกกำหนดในตัวอักษร US-ASCII ตัวพิมพ์ใหญ่ทั้งหมด" ตามด้วยรายการเดียวกันในคำตอบของคุณ
Bob

1
รหัสสถานะการตอบกลับควรเป็น 405 วิธีที่ไม่ได้รับอนุญาต
Lie Ryan

3
@LieRyan ไม่เพราะนั่นจะหมายถึงวิธีที่โทเค็นเหมาะกับ RFC ในขณะที่เซิร์ฟเวอร์ไม่อนุญาตให้ใช้กับทรัพยากรนี้ RFC 2616 § 10.4.1: [400 คำขอไม่ถูกต้อง] เซิร์ฟเวอร์ไม่สามารถเข้าใจคำขอได้เนื่องจากไวยากรณ์ผิดรูปแบบ RFC 2616 § 10.4.6 [405 วิธีที่ไม่อนุญาต] วิธีการที่ระบุไว้ในคำขอ-Line ไม่ได้รับอนุญาตสำหรับทรัพยากรที่ระบุโดยขอ URI โทเค็นไม่ใช่วิธี HTTP ในทางใดทางหนึ่ง (ดูข้อความที่ตัดตอนมาของ RFC 2616 § 5.1.1 ข้างต้น)get
Xavier Lucas

@XavierLucas: ใช้วิธีกรณีที่ต่ำกว่าไม่ได้เป็นข้อผิดพลาดทางไวยากรณ์ตรวจสอบRFC2616 มาตรา 5 ใน ABNF extension-methodมีไวยากรณ์tokenซึ่งรวมถึงตัวอักษรและตัวเลขทั้งหมดและสัญลักษณ์บางอย่างไม่ใช่เฉพาะวิธีการที่ระบุไว้ใน RFC HTTP เกือบทุกส่วนสามารถขยายได้ตราบใดที่ทั้งไคลเอนต์และเซิร์ฟเวอร์ยอมรับว่ามีการขยายมากเกินไปรวมถึงการกำหนดวิธีการตัวพิมพ์เล็กของคุณเอง บรรทัดคำขอ "get / HTTP / 1.1" นั้นถูกต้องตามหลัก syntactically มันแค่ละเมิด RFC ในชื่อเมธอดนั้นควรคำนึงถึงขนาดตัวพิมพ์
โกหกไรอัน

@LieRyan extension-methodอยู่ที่นี่เพื่อเปิดประตูให้ RFC ถัดไปนั่นไม่ได้อยู่ที่นี่เพื่อเพิ่มวิธีการของคุณเองออกจากขอบเขตของ RFC และแสร้งทำเป็นว่าคุณกำลังใช้บริการที่สอดคล้องกับ HTTP / 1.1 ดังนั้นควรคืน 400 เพราะไม่มีวิธีดังกล่าวปรากฏใน RFC ล่าสุดดังนั้นในวันนี้โทเค็นที่ไม่ถูกต้อง หากโทเค็นนั้นถูกต้องเกี่ยวกับรายการวิธีการปัจจุบันและนำไปใช้กับฝั่งเซิร์ฟเวอร์ แต่ไม่ได้รับอนุญาต 405 จะถูกส่งกลับ ควรส่งคืน 501 ในกรณีที่เมธอดใช้ได้ แต่ไม่ได้ใช้งานฝั่งเซิร์ฟเวอร์
ซาเวียร์ลูคัส
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.