3 คะแนน โดย GN⁺ 2024-04-06 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • HTTP/2 CONTINUATION Flood คือกลุ่มช่องโหว่ใน implementation ของ HTTP/2 ที่สามารถทำลายความพร้อมใช้งานของเซิร์ฟเวอร์ได้ด้วยการส่งเฟรมส่วนหัวต่อเนื่องโดยไม่มี END_HEADERS
  • เนื่องจากคำขอโจมตีไม่เคยเสร็จสมบูรณ์ จึงไม่ปรากฏใน HTTP access log และการหาสาเหตุอาจต้องวิเคราะห์ไบต์ทราฟฟิกดิบ
  • ขอบเขตผลกระทบแตกต่างกันไปตาม implementation ตั้งแต่ CPU exhaustion, OOM จากหลายการเชื่อมต่อ, OOM จากการเชื่อมต่อเดียว ไปจนถึงการแครชจากบั๊กเรื่องจังหวะการตัดการเชื่อมต่อ
  • กรณีของ Go, Firefox และ Node.js เผยให้เห็นตามลำดับว่า HPACK decoding ดำเนินต่อไม่หยุด, ไม่มีการจำกัดขนาด response header และมีการชนกันระหว่างการตัดการเชื่อมต่อขณะประมวลผล CONTINUATION กับการอัปเดต memory counter
  • ต่างจาก Rapid Reset ในหลาย implementation สามารถทำให้เซิร์ฟเวอร์แครชได้ด้วย TCP connection เดียว จึงอาจส่งผลกระทบต่อบริการอินเทอร์เน็ตจำนวนมากที่ใช้ HTTP/2

วิธีใช้เฟรม CONTINUATION ใน HTTP/2

  • HTTP/2 เป็นโปรโตคอลที่แลกเปลี่ยน binary frame ไม่ได้ส่งบรรทัดข้อความไปมาเหมือน HTTP/1.1
  • เฟรม HEADERS ใช้ส่ง HTTP header ของคำขอและคำตอบ โดยข้อมูล header จะถูกเก็บไว้ใน field block fragment ที่เข้ารหัสด้วย HPACK
  • เฟรม HEADERS มี flag ที่บอกจุดสิ้นสุดของ header และ stream
    • END_HEADERS: สัญญาณว่าเฟรมนี้มี header ทั้งหมดที่ต้องการส่งแล้ว
    • END_STREAM: สัญญาณว่าไม่มี body ของคำขอหรือคำตอบเพิ่มเติมแล้ว
  • เฟรมมี ขนาดสูงสุด ที่กำหนดตอนเริ่มสื่อสาร และหากเฟรมที่รับมีขนาดเกินที่อนุญาต การเชื่อมต่อจะถูกตัดด้วย protocol error
  • หากไม่สามารถใส่ header ทั้งหมดในเฟรม HEADERS เดียวได้ จะมีเฟรม CONTINUATION ต่อท้ายเฟรม HEADERS ที่ไม่มี END_HEADERS
    • เฟรม HEADERS ที่ไม่มี END_HEADERS
    • เฟรม CONTINUATION เพิ่มเติมที่ไม่มี END_HEADERS
    • ตั้งค่า END_HEADERS ในเฟรม CONTINUATION สุดท้าย
  • หลังเฟรม header สุดท้าย จะมีเฟรม DATA ที่บรรจุข้อมูลคำขอตามมา หรือ HTTP/2 stream จะสิ้นสุดลง

แก่นของช่องโหว่: header stream ที่ไม่สิ้นสุด

  • หากไคลเอนต์เริ่ม HTTP/2 stream ใหม่ แล้วส่งเฟรม HEADERS และ CONTINUATION โดยไม่ตั้งค่า END_HEADERS เลย เซิร์ฟเวอร์จะพยายาม parse และจัดเก็บ header stream ที่ไม่สิ้นสุด ต่อไป
  • โดยทั่วไปเซิร์ฟเวอร์ HTTP/1.1 มีกลไกสองอย่างเพื่อป้องกัน header ที่ไม่สิ้นสุด
    • การจำกัดขนาด header ที่ตัดการเชื่อมต่อเมื่อรายการ header เกินขนาดที่อนุญาต
    • timeout ของคำขอ/header ที่ตัดการเชื่อมต่อเมื่อคำขอหรือ header ไม่ถูกส่งภายในเวลาที่กำหนด
  • HTTP/2 implementation หลายตัวไม่มีการป้องกันเหล่านี้ หรือ implement ไว้ไม่ถูกต้อง รวมถึง Apache httpd, Envoy และแพ็กเกจกับ codec ของ HTTP/2 หลายตัว
  • ผลลัพธ์แยกได้เป็นสี่แบบตาม implementation
    • CPU exhaustion: ระหว่างอ่านและ decode header เพิ่มเติม การใช้ CPU เพิ่มขึ้น ทำให้การตอบคำขออื่นช้าลงหรือหยุดชะงัก
    • OOM แบบอาศัยหลายการเชื่อมต่อ: header ของ CONTINUATION ถูกเก็บในหน่วยความจำ และแม้จะมีการจำกัดขนาดรายการ header แต่ไม่มี header timeout ทำให้แต่ละ connection ยึดหน่วยความจำต่อไป
    • OOM แบบอาศัยการเชื่อมต่อเดียว: implementation บางตัวอ่าน header ต่อไปจนหน่วยความจำเต็ม ทำให้ OS ยุติ process
    • แครชได้ด้วยเฟรมเพียงไม่กี่เฟรม: เซิร์ฟเวอร์แครชจากบั๊กของ implementation เมื่อตัดการเชื่อมต่อกลาง CONTINUATION stream
  • หากไม่มี END_HEADERS คำขอจะไม่ถูกปิดอย่างถูกต้อง ดังนั้นคำขอของไคลเอนต์ประสงค์ร้ายจะไม่ถูกบันทึกใน access log

กรณีของ Go: CPU exhaustion จาก HPACK decoding ที่ไม่หยุด

  • Go เป็นกรณีที่ CPU exhaustion โดดเด่นใน CONTINUATION Flood
  • implementation ของ Go ใช้ abstraction ชื่อ http2MetaHeadersFrame เพื่อรวมเฟรม HEADERS หนึ่งเฟรม, เฟรม CONTINUATION จำนวน 0 เฟรมขึ้นไป และ HPACK decoder เข้าด้วยกัน
  • readMetaFrame เมื่อถึงขีดจำกัดขนาด header หรือเกิดข้อผิดพลาด จะเรียก SetEmitEnabled(false) เพื่อหยุดปล่อย header ที่ decode แล้วออกมา
  • แต่แม้หยุดปล่อย header แล้ว HPACK decoder ก็ยังคง decode ไบต์ input ต่อไป
  • ลูปที่ป้อนเฟรมจะหยุดก็ต่อเมื่อ HeadersEnded() เป็น true ซึ่งเกิดขึ้นเมื่อมีการตั้ง flag END_HEADERS
  • หากผู้โจมตีไม่ส่ง END_HEADERS ฟังก์ชัน readMetaFrame จะไม่ return และระหว่างที่ผู้โจมตีส่งข้อมูล HPACK decoder ก็จะประมวลผลไบต์ใหม่ต่อไปเรื่อย ๆ

กรณี OOM และผลกระทบต่อไคลเอนต์ Firefox

  • OOM เกิดขึ้นใน implementation ที่ไม่ได้จำกัดขนาดรายการ header ที่สร้างจากเฟรม CONTINUATION
  • ใน implementation ที่ไม่มี header timeout สามารถทำให้เซิร์ฟเวอร์แครชได้ด้วย HTTP/2 connection เดียว
  • แม้ใน implementation ที่มี idle timeout ก็ยังสามารถเปิด HTTP/2 connections หลายรายการให้แต่ละรายการใช้ RAM ใกล้ขีดจำกัดต่อ connection แล้วคอยส่งเฟรม CONTINUATION สุดท้ายทีละไบต์ทุกไม่กี่วินาทีเพื่อคงการเชื่อมต่อไว้
  • CONTINUATION Flood สามารถเกิดขึ้นได้ไม่เพียงกับเซิร์ฟเวอร์ แต่ยังเกิดที่ ฝั่งไคลเอนต์ เช่น browser ได้ด้วย
  • commit แก้ไขของ Mozilla Firefox เพิ่มการตรวจสอบว่า หากผลรวมของขนาด header ที่สะสมแล้วกับขนาดเฟรมใหม่เกิน network_http_max_response_header_size() ให้ส่งคืน session error เป็น PROTOCOL_ERROR

กรณีของ Node.js: assertion crash ระหว่างตัดการเชื่อมต่อ

  • Node.js จัดการ stream ของเฟรม CONTINUATION ที่ไม่สิ้นสุดได้อย่างเหมาะสม แต่เกิด data race เมื่อตัดการเชื่อมต่อระหว่าง header stream
  • ระหว่างรันโค้ดโจมตี Node.js แครชจาก assertion CHECK_EQ(current_nghttp2_memory_, 0) ล้มเหลวใน Http2Session::~Http2Session()
  • การแครชเชื่อมโยงกับจังหวะที่แม่นยำซึ่ง HTTP/2 client ตัดการเชื่อมต่อจากเซิร์ฟเวอร์ Node.js และ assertion อยู่ภายใน destructor ของ Http2Session
  • Node.js ฝังไลบรารี nghttp2 ไว้เพื่อประมวลผล HTTP/2 connection
  • current_nghttp2_memory_ ใช้ติดตามหน่วยความจำที่จัดสรรภายใน nghttp2 และหลัง session_.reset() ใน destructor จะตรวจสอบว่า artifact ทั้งหมดของ nghttp2 ถูกลบออกจากหน่วยความจำแล้วหรือไม่
  • ผลการตรวจสอบพบว่ามีบางกรณีที่ callback ของ nghttp2 กับ reset() ทำงานพร้อมกันระหว่าง parse เฟรม CONTINUATION
    • เฟรม CONTINUATION มาถึงในสถานะ NGHTTP2_IB_EXPECT_CONTINUATION
    • สถานะเปลี่ยนเป็น NGHTTP2_IB_READ_HEADER_BLOCK
    • เกิด flow ต่อเนื่องของ session_after_header_block_received, session_call_on_frame_received, on_frame_recv_callback
    • OnFrameReceive และ HandleHeadersFrame ของ Node.js อัปเดต memory counter
  • หาก HandleHeadersFrame และ Http2Session::~Http2Session() ทำงานพร้อมกัน current_session_memory_ จะถูกอัปเดตพร้อมกัน และค่า current_nghttp2_memory_ กลายเป็นค่าติดลบ ทำให้ CHECK_EQ ล้มเหลว

ความแตกต่างจากช่องโหว่ HTTP/2 ในปี 2019

  • ชุดช่องโหว่ HTTP/2 ที่ Netflix และ Google รายงานในปี 2019 ถูกสรุปไว้ใน CERT/CC Vulnerability Note VU#605641
  • CVE-2019-9516, “0-Length Headers Leak” เป็นปัญหาที่ทำให้ implementation บางตัวจัดสรรหน่วยความจำสำหรับชื่อและค่าของ header ที่มีความยาว 0 และคงไว้จนกว่า session จะจบ
  • CONTINUATION Flood ไม่ได้ใช้ header ว่าง แต่ใช้วิธีส่ง header แบบสุ่มจำนวนมาก จนถึงขีดจำกัดขนาดเฟรมที่เซิร์ฟเวอร์ตั้งไว้
  • CVE-2019-9518, “Empty Frame Flooding” เป็นปัญหาที่ส่งเฟรม payload ว่าง เช่น DATA, HEADERS, CONTINUATION, PUSH_PROMISE โดยไม่มี end-of-stream ทำให้อีกฝ่ายใช้เวลาประมวลผลมากเกินไปเมื่อเทียบกับแบนด์วิดท์โจมตี
  • CONTINUATION Flood ไม่ใช่เฟรมว่าง แต่ใช้เฟรมที่ใหญ่ที่สุดเท่าที่เป็นไปได้เพื่อยึดหน่วยความจำและใช้ CPU cycle ในกระบวนการ decode

เหตุผลที่อาจร้ายแรงกว่า Rapid Reset

  • ในเดือนตุลาคม 2023 มีการเปิดเผยรายละเอียด “Rapid Reset” ซึ่งเป็น zero-day ของโปรโตคอล HTTP/2 และถูกเรียกว่า “การโจมตี DDoS ที่ใหญ่ที่สุดจนถึงปัจจุบัน”
  • Rapid Reset ใช้การผสมระหว่างเฟรม HEADERS ที่ตั้งค่า END_STREAM และ END_HEADERS กับเฟรม RST_STREAM
  • ด้วยวิธีนี้ มาตรการบรรเทามาตรฐานอย่าง rate limiting สามารถลดความเสียหายได้ และผู้ดูแลเซิร์ฟเวอร์สามารถเห็นคำขอ inbound จำนวนมากใน log และได้รับการแจ้งเตือน
  • ใน CONTINUATION Flood ไม่มี END_HEADERS ดังนั้น ไม่มีคำขอแม้แต่รายการเดียวที่เสร็จสมบูรณ์ และผู้ดูแลจะมองไม่เห็นคำขอใน log
  • ในหลาย implementation CONTINUATION Flood สามารถทำให้เซิร์ฟเวอร์แครชได้ด้วย TCP connection เดียว และบางกรณีใช้ข้อมูลเพียงเล็กน้อยมากก็ทำได้
  • Rapid Reset ถูกใช้ในการโจมตี DDoS และโดยมากต้องใช้ botnet เพื่อให้โจมตีสำเร็จ

ผลกระทบที่อาจเกิดกับบริการอินเทอร์เน็ต

  • ตามข้อมูลของ Cloudflare Radar ทราฟฟิก HTTP/2 คิดเป็นประมาณ 60% ของทราฟฟิก HTTP จากมนุษย์โดยไม่นับ bot
  • Cloudflare Radar ประเมินว่า HTTP traffic คิดเป็นมากกว่า 70% ของการส่งข้อมูลทั้งหมดบนอินเทอร์เน็ต
  • เมื่อพิจารณาความสำคัญของโปรเจกต์ที่ได้รับผลกระทบและความง่ายในการ exploit ส่วนใหญ่ของอินเทอร์เน็ตจึงเคยเปิดรับช่องโหว่นี้
  • HTTP ไม่ได้ใช้เฉพาะกับเว็บไซต์เท่านั้น แต่ยังใช้กับ RESTful API จำนวนมากด้วย
  • ปัญหาความพร้อมใช้งานของ API และเว็บไซต์สำคัญขององค์กรหรือภาครัฐอาจก่อให้เกิดความสูญเสียหรือความวุ่นวายมูลค่าหลายล้านดอลลาร์
  • หากถูก exploit ผู้ดูแลเซิร์ฟเวอร์อาจ debug ได้ยากมากหากไม่มีความรู้ HTTP/2
    • คำขอ HTTP ประสงค์ร้ายไม่ได้ถูกปิดอย่างถูกต้อง
    • ไม่เห็นคำขอใน server access log
    • เซิร์ฟเวอร์ HTTP/2 ส่วนใหญ่ขาดความสามารถวิเคราะห์เฟรมขั้นสูง
    • ต้องวิเคราะห์ข้อมูลการเชื่อมต่อดิบด้วยตนเอง

การเปิดเผยแบบประสานงานและการตอบสนองของ CERT/CC

  • กลุ่มช่องโหว่นี้มีความเสี่ยงอย่างมากต่อ ความปลอดภัยของอินเทอร์เน็ต
  • หลังจากมีรายงานในเดือนมกราคม 2024 CERT/CC ได้เปิด Vulnerability Coordination case เพื่อติดตามปัญหานี้
  • บริษัทเทคโนโลยีขนาดใหญ่หลายแห่งและโปรเจกต์โอเพนซอร์สหลายโครงการเข้าร่วมกระบวนการเปิดเผยอย่างรับผิดชอบที่เกี่ยวข้อง
  • เนื่องจากนักวิจัยคนเดียวตรวจสอบ implementation จำนวนมากทั้งหมดได้ยาก ปัญหาที่ส่งผลต่อ vendor หลายรายจึงจำเป็นต้องมี Vulnerability Coordination
  • CERT/CC ได้เผยแพร่ Vulnerability Note สำหรับปัญหานี้ และ note ลักษณะนี้มีการเผยแพร่เพียงไม่กี่รายการต่อปี

1 ความคิดเห็น

 
GN⁺ 2024-04-06
ความคิดเห็นจาก Hacker News
  • เดือนที่แล้ว Bandit ก็ได้บรรเทาปัญหานี้ไว้ตรงจุดนี้พอดี
    https://github.com/mtrudel/bandit/blob/main/lib/bandit/http2...
    จากมุมมองของคนทำ implementation พูดตรง ๆ ว่านี่เป็นจุดที่ควรต้องป้องกันอยู่แล้วแบบชัดเจนมาก เราคิดเรื่องนี้มานานแล้ว และก็เคยเชื่อว่า implementation อื่น ๆ ก็น่าจะป้องกันไว้เป็นเรื่องปกติเหมือนกัน

    • ก็รู้กันอยู่ว่าถ้าคิดเอาเองจะเกิดอะไรขึ้น มันจะพาเธอกับฉันไปเป็น พาดหัวหน้าแรก
  • ในช่วงหลายเดือนที่ผ่านมา มีการตรวจดู implementation หลายสิบตัว แต่ที่แปลกคือแม้แต่ เซิร์ฟเวอร์ HTTP/2 รายหลัก ๆ ก็ยังไม่มีการป้องกันแบบนี้ หรือไม่ก็ทำไว้ผิด
    โดยแก่นแล้ว นี่น่าจะเป็นผลจากวัฒนธรรมการพัฒนาที่คุ้นชินกับการขยายทุกอย่างแบบไดนามิกอัตโนมัติ โดยไม่ค่อยกังวลว่ามันจะโตได้มากแค่ไหน
    ปัญหาประเภทนี้ไม่ได้จำกัดอยู่แค่ HTTP/2 แต่ความซับซ้อนอย่างหนักของ HTTP/2 น่าจะมีส่วนมาก ในยุค HTTP/1.x มีนักพัฒนาที่คุ้นกับภาษาอย่าง C มากกว่า จึงคอยระวังเรื่องการจัดการความยาวบัฟเฟอร์อยู่ตลอด และคงไม่ทำให้การจัดสรรหน่วยความจำสำหรับเฮดเดอร์ตลอดทั้งคำขอขยายได้ไม่สิ้นสุด ทั้งที่จริงอย่างมากก็ใช้แค่ไม่กี่ KB

    • ผู้คนยังคงโฟกัสและ optimize แค่ เส้นทางปกติ อยู่เรื่อย ๆ แต่ไม่ค่อยหยุดคิดว่าถ้าผู้โจมตีจงใจทำให้เกิดกรณีเลวร้ายที่สุดซ้ำ ๆ จะเป็นอย่างไร
      การโจมตีแบบปฏิเสธการให้บริการหลายอย่าง เช่น slowloris หรือการชนกันของแฮชใน query parameter เกิดขึ้นได้จริงก็เพราะเพิ่งมานึกถึงเรื่อง การใช้ทรัพยากรที่มีขีดจำกัด กันในภายหลัง
  • > ไม่ได้รับผลกระทบ: Nginx, Jetty, HAProxy, NetScaler, Varnish. [0]
    0: https://nowotarski.info/http2-continuation-flood/

    • พูดอีกแบบคือ เป็น implementation ที่คัดค้านการใช้ CONTINUATION มาตั้งแต่ 10 ปีก่อนเพราะความเสี่ยงด้านการปฏิเสธการให้บริการ ถ้าไปอ่านเธรดยาว ๆ จะเห็นว่าใจความหลักคือจะหลีกเลี่ยง CONTINUATION เจ้าปัญหานี้อย่างไร: https://lists.w3.org/Archives/Public/ietf-http-wg/2014JulSep...
      อย่างน้อยถ้ายอมรับข้อเสนอที่ห้ามใช้หลัง HEADERS frame ที่ยังไม่เต็ม ก็น่าจะทำให้แข็งแรงขึ้นได้มากกว่านี้ แต่ตอนนั้นมองกันว่านั่นอาจทำให้งานด้าน encoding ยากขึ้นเอง เพราะมีปัญหาเรื่องอย่างขอบเขตไบต์ของตัวบีบอัด
      ตลกดีที่ทุก 10 ปีเราจะ “ค้นพบใหม่” เรื่องเดิม ๆ อีกครั้ง ช่วงก่อนก็ RESET_STREAM flood ที่เป็นที่รู้จักกันดี ครั้งนี้เป็น CONTINUATION และต่อไปก็คงเป็น DATA frame ความยาว 0, WINDOW_UPDATE ขนาด 1 ไบต์, หรือ INITIAL_WINDOW SETTINGS ที่ทำให้ใช้ CPU สูง ถ้าแค่เอาปัญหาที่รู้อยู่แล้วมาตั้งชื่อใหม่และถ้าเป็นไปได้ก็ทำโลโก้เพิ่ม โลกก็จะหมุนคณะละครสัตว์ความปลอดภัยนี้ต่อไปได้เรื่อย ๆ
    • แล้ว Caddy ล่ะ? เป็นโครงการที่ยอดเยี่ยมพอจะได้บรรทัดแยกต่างหากเลย ;)
  • บทความก่อนหน้าของผู้เขียนคนเดียวกันที่สรุป เว็บเซิร์ฟเวอร์/รีเวิร์สพร็อกซี ที่ได้รับผลกระทบ
    https://nowotarski.info/http2-continuation-flood/

  • บทความนี้อยู่บนสุดทั้งวัน
    สงสัยว่าถ้าเป็นเว็บไซต์ทราฟฟิกไม่มาก การรันด้วยแค่ HTTP/1.1 จะปลอดภัยกว่าหรือเปล่า?

    • การมองว่า HTTP/1.1 มีบั๊กน้อยกว่าเพราะ implement ได้ง่ายกว่านั้นถือว่าสมเหตุสมผล
      HTTP/2 และ HTTP/3 ต่างจากเดิมมากในแง่ฟีเจอร์ มีทั้ง multiplexing, windowing, HPACK ฯลฯ เพิ่มเข้ามา ทำให้การเชื่อมต่อที่แทบไม่มีสถานะของ HTTP/1.1 กลายเป็น การเชื่อมต่อแบบมีสถานะ การคงไว้ซึ่งการเชื่อมต่อแบบมีสถานะต้องเก็บข้อมูลอย่างสถานะและการตั้งค่าไว้ และนั่นเองที่ทำให้เกิดปัญหาเหล่านี้
      ใน HTTP/2 มีการเพิ่ม multiplexing เข้ามา จึงทำให้คุณสมบัติด้านการป้องกันต่างไปด้วย เช่น ถ้าการเชื่อมต่อมาจากคำขอไปยังต้นทางของ CDN คุณอาจอนุญาตให้มีจำนวนการเชื่อมต่อน้อย แต่ให้แต่ละการเชื่อมต่อมีพูลช่อง multiplexing ขนาดใหญ่ได้ ขณะที่ถ้าเป็นการเข้าถึงจากผู้ใช้โดยตรง คุณอาจอยากอนุญาตจำนวนการเชื่อมต่อมาก แต่ลดจำนวนช่อง multiplexing ต่อการเชื่อมต่อ ใน HTTP/1 แทบทุกอย่างดูคล้ายกันไปหมด จึงทำให้การป้องกันง่ายกว่ามาก
    • การอัปเกรดเพียงเพื่อจะอัปเกรดไม่ใช่แนวปฏิบัติทางวิศวกรรมที่ดี ถ้าการอัปเกรดไม่ได้ให้ประโยชน์เพิ่ม ก็ยากจะหาเหตุผลมารองรับ
    • ไม่จำเป็นต้องเป็นแบบนั้นเสมอไป คนที่บอกว่า HTTP/1.1 เรียบง่าย มักไม่เคยลอง implement parser ที่สมบูรณ์ ซึ่งเข้ากันได้กับสภาพแวดล้อมจริง
      HTTP/1 มี edge case ที่มองไม่เห็นชัดและพฤติกรรมยกเว้นแบบเก่าอยู่มาก รูปแบบข้อความมีความยืดหยุ่นกว่าที่เห็นจากการดูแค่เฮดเดอร์ที่ถูกต้องมาก ทั้ง multi-line header, ความสามารถ MIME แบบเก่า, race condition ของ 100-continue, hop-by-hop header แบบกำหนดเอง และฟีเจอร์กำกวมอย่าง GET body
      โชคดีที่ RFC HTTP ฉบับใหม่ ๆ ได้บันทึกกับดักจำนวนมากไว้แล้ว หาก implement โดยดูแค่ RFC 2616 ก็จะไม่ได้ implementation ที่ปลอดภัย
      ขนาดจริงของ request หรือ response สามารถถูกระบุพร้อมกันได้หลายวิธี และค่าก็อาจขัดแย้งกันเองได้ นอกจากนี้ยังขึ้นอยู่กับการผสมกันของหลายฟีเจอร์ และค่าเฮดเดอร์ที่ต้องใช้กฎ parsing แปลก ๆ เพื่อความเข้ากันได้ย้อนหลัง จึงทำให้ implementation HTTP ที่ “เรียบง่าย” อาจโดน request smuggling หลอกได้
      ไม่ว่าจะเลือกทางไหน ก็ต้องการ implementation ที่แข็งแรง ผ่านการทดสอบมาอย่างดี และมีความเป็นผู้ใหญ่มากพอ
    • ฉันก็สงสัยแบบนั้นเหมือนกัน เพราะมัน mature กว่าและซับซ้อนน้อยกว่า จึงดูมีโอกาสปลอดภัยกว่า
    • น่าจะใช่ HTTP/2 เหมาะกับ สตรีมมิง และแม้แต่ตรงนั้นตอนนี้ก็ยังถูกแทนที่ด้วยโปรโตคอลที่ใหม่กว่า
      สำหรับการให้บริการ static asset ทั่วไป ข้อดีของ HTTP/1 มีเพียงเรื่องที่มันติดข้อจำกัดจำนวนการเชื่อมต่อต่อโดเมน จึงสามารถโหลด asset แบบขนานได้มากกว่า และปกติก็แก้ปัญหานี้ได้ด้วยการใช้ CDN หลายโดเมน
      ในทางทฤษฎี HTTP/2 อาจใช้เสิร์ฟ JavaScript asset ที่ไม่ได้ bundle ได้ แต่ในสภาพแวดล้อมการใช้งานจริงยังไม่ค่อยเห็น ส่วนใหญ่คงเป็นเพราะในหลายกรณีก็ยังต้องมีขั้นตอน compile อยู่ดี
  • ถ้าทำแบบช้า ๆ ก็คงเรียกมันว่า slowloris v2 ได้สินะ :(

  • HTTP/2 หรือวิธีเอา “การอัปเกรด” ชั้นขนส่งมายัดใส่โปรโตคอลชั้นแอปพลิเคชันแบบฝืน ๆ