ทำไม Port-Share ทำให้ผู้เข้าชมเว็บไซต์ทุกคนดูเหมือน localhost
แบ็กเอนด์เห็นฮอปของการส่งต่อ ไม่ใช่เบราว์เซอร์ ตรวจสอบว่าที่อยู่ต้นทางหายไปที่ใด แล้วตัดสินใจว่าส่วนประกอบใดได้รับอนุญาตให้รับรอง
ทุกบรรทัดในบันทึกการเข้าถึงแสดงที่อยู่ loopback เดียวกัน ขณะที่หน้าเว็บโหลดได้และใบรับรองตรวจสอบผ่าน สิ่งที่เสียคือการระบุตัวตน เพราะแบ็กเอนด์ของเว็บบันทึกที่อยู่ของฮอปที่ส่งต่อการเชื่อมต่อ และทุกการตัดสินใจหลังจากนั้นที่เชื่อบันทึกก็สืบทอดคำตอบผิดเดียวกันนี้
การตรวจสอบด้านล่างไล่จากสายเคเบิลเข้าไปข้างใน หยุดที่รายการแรกที่อธิบายค่าที่คุณเห็น เพราะแต่ละขั้นถัดไปถือว่าขั้นก่อนหน้าเป็นจริงแล้ว ไม่มีขั้นใดต้องเดาการตั้งค่าของส่วนหน้า
ตามสองการเชื่อมต่อ ไม่ใช่บรรทัดในบันทึก
Port-Share รวมสองโพรโทคอลไว้บนตัวรับฟัง TCP ตัวเดียว OpenVPN ตรวจไบต์แรกของการเชื่อมต่อที่เข้ามา เก็บไว้เมื่อดูเหมือนโพรโทคอลของตัวเอง และส่งอย่างอื่นทั้งหมดไปยังปลายทางที่สอง ปลายทางนั้นมักเป็นเว็บเซิร์ฟเวอร์บนโฮสต์เดียวกัน ซ็อกเก็ตที่เว็บเซิร์ฟเวอร์รับจึงมีโพรเซส OpenVPN เป็นคู่
ss -ltnp 'sport = :443'
ss -tnp 'dport = :8080'
คำสั่งแรกแสดงว่าใครเป็นเจ้าของตัวรับฟังสาธารณะ คำสั่งที่สองแสดงการเชื่อมต่อที่มาถึงพอร์ตแบ็กเอนด์ และที่อยู่คู่ของมันคือค่าที่บันทึกการเข้าถึงจะพิมพ์ออกมา ถ้าคู่นั้นเป็น loopback บันทึกก็ถูกต้องและข้อมูลหายไปหนึ่งชั้นก่อนหน้านี้ การเปลี่ยนชื่อฟิลด์ในบันทึกหรือเปิดโมดูล IP ของไคลเอนต์ไม่ทำให้ที่อยู่ที่การเชื่อมต่อไม่เคยพากลับมา
นี่คือการตรวจสอบที่ตัดสินทุกอย่างที่เหลือ ถ้าคู่ของแบ็กเอนด์เป็นที่อยู่ของเบราว์เซอร์ การแบ่งพอร์ตไม่ใช่ปัญหาของคุณ แต่รูปแบบบันทึกคือปัญหา
การส่งต่อระดับทรานสปอร์ตไม่ใช่การแทรกเฮดเดอร์
ตัวส่งต่อย้ายไบต์ มันไม่แยกวิเคราะห์ HTTP จึงแทรกเฮดเดอร์ในคำขอที่มันไม่เคยอ่านเป็นคำขอไม่ได้ และเพิ่มสิ่งใดลงในสตรีม TLS ที่มันปล่อยผ่านไปเฉย ๆ ไม่ได้ โมดูลที่รอเฮดเดอร์พร็อกซีจะรอสิ่งที่ไม่มีส่วนประกอบใดผลิตออกมา
มีสองกลไกที่พาที่อยู่เดิมไปได้ และทั้งสองต้องมีความตกลงทั้งสองฝั่ง โพรโทคอล PROXY เติมเฮดเดอร์เล็ก ๆ ไว้ข้างหน้าการเชื่อมต่อ และแบ็กเอนด์ต้องตั้งค่าให้คาดหวังมัน แบ็กเอนด์ที่ไม่คาดหวังจะถือไบต์เหล่านั้นเป็นจุดเริ่มต้นของคำขอและล้มเหลวอย่างสับสน เฮดเดอร์พร็อกซีที่เชื่อถือได้อย่าง X-Forwarded-For ทำงานเมื่อพร็อกซีที่เข้าใจ HTTP เป็นผู้กำหนดและบอกแบ็กเอนด์ว่าคู่ใดมีสิทธิ์ยืนยัน
ทั้งสองไม่ใช่เรื่องอัตโนมัติ และทั้งสองไม่ปลอดภัยโดยค่าเริ่มต้น แบ็กเอนด์ที่เชื่อทุกเฮดเดอร์ที่ถูกส่งเข้ามาจะเปิดให้ไคลเอนต์เลือกที่อยู่ของตัวเอง ซึ่งเปลี่ยนความไม่ถูกต้องในบันทึกให้กลายเป็นการหลบเลี่ยงการควบคุมการเข้าถึง ทดลองสาธิตหนึ่งครั้งบนโฮสต์ทดสอบก่อนเชื่อเฮดเดอร์ใดบนเส้นทางโปรดักชัน
curl -sS -H 'X-Forwarded-For: 127.0.0.1' https://site.example.com/health
grep -F '127.0.0.1' /var/log/nginx/access.log | tail -n 3
ไดเรกทอรีแมปต้นทางที่เป็นทางเลือก
การแบ่งพอร์ตมีอาร์กิวเมนต์ไดเรกทอรีแบบเลือกได้ซึ่งบันทึกการแมประหว่างที่อยู่ต้นทางเดิมกับการเชื่อมต่อที่ส่งต่อ บนแพลตฟอร์มที่คุณลักษณะนี้ถูกนำไปใช้ ฝั่งเว็บควรสอบถามการแมปนั้น มันไม่ใช่เฮดเดอร์และไม่ถูกแทรกเข้าในคำขอ
การออกแบบนั้นควรค่าแก่การรู้จักเพราะอธิบายว่าทำไมบางการติดตั้งรายงานที่อยู่จริงและบางแห่งไม่ ทั้งที่มีการตั้งค่าส่วนหน้าที่ดูเหมือนเหมือนกัน ความแตกต่างอยู่ที่ฝั่งรับ และมักอยู่ในโมดูลหรือแพตช์ที่เว็บเซิร์ฟเวอร์แบบแพ็กเกจส่วนใหญ่ไม่เปิดใช้โดยค่าเริ่มต้น อ่านเอกสารของเว็บเซิร์ฟเวอร์คุณถึงฮุกที่แน่นอนที่มันมีให้ และยืนยันว่าโมดูลถูกโหลดแล้วแทนที่จะสันนิษฐาน
ถ้าเลือกทางนี้ ให้ถือว่าเป็นการผสานสองครึ่ง คือการแมปที่ตัวส่งต่อเขียนและการค้นหาที่แบ็กเอนด์ทำ ตรวจสอบทั้งสอง และยืนยันว่าไดเรกทอรียังอยู่หลังรีสตาร์ตและไม่โตเกินขอบเขตบนตัวรับฟังที่ยุ่ง
ตัดสินใจว่าส่วนประกอบใดรับรองที่อยู่
ก่อนเปลี่ยนการตั้งค่า ให้ระบุชื่อส่วนประกอบที่ได้รับอนุญาตให้ยืนยันที่อยู่ไคลเอนต์และส่วนประกอบที่ได้รับอนุญาตให้เชื่อ คำตอบเดียวที่เขียนไว้จะป้องกันการเลื่อนไถลปกติที่สามชั้นต่างก็เชื่อแหล่งต่างกัน
การออกแบบสามแบบครอบคลุมความต้องการส่วนใหญ่ แยกตัวรับฟังสาธารณะกับตัวรับฟังเว็บออกจากกัน เพื่อให้เว็บเซิร์ฟเวอร์เห็นคู่จริงและไม่มีปัญหาการระบุตัวตน หรือวางพร็อกซีย้อนกลับที่เข้าใจ HTTP ไว้ข้างหน้า ยุติหรือแยกวิเคราะห์คำขอที่นั่น และปล่อยให้มันตั้งเฮดเดอร์ที่ส่งต่อให้แบ็กเอนด์ที่เชื่อเฉพาะพร็อกซีนั้น หรือคงการแบ่งพอร์ตไว้และยอมรับว่าบันทึกแสดงฮอป โดยกฎการเข้าถึงเขียนกับตัวตนของแอปพลิเคชันแทนที่จะเป็นที่อยู่
สิ่งที่ใช้ไม่ได้คือการถือที่อยู่ loopback ที่ถูกส่งต่อเป็นหลักฐานว่าคำขอเกิดบนเครื่องนี้ ข้อสรุปนั้นกลับกันเต็มที่ ที่อยู่มีอยู่ก็เพราะส่วนประกอบภายในสร้างการเชื่อมต่อขึ้น กฎที่เขียนเช่นนั้นจะรับทุกคนที่เข้าถึงตัวรับฟังได้
ทดสอบกฎ ไม่ใช่หน้าเว็บ
หน้าที่โหลดได้พิสูจน์ว่าเส้นทางการส่งต่อทำงาน และไม่ได้บอกอะไรเกี่ยวกับการระบุตัวตน ทดสอบผู้ใช้ที่อยู่ ทั้งกฎการเข้าถึง ขีดจำกัดอัตรา รายการตรวจสอบ และการค้นหาตามพื้นที่
curl -sS -o /dev/null -w '%{http_code}\n' https://site.example.com/
tail -n 5 /var/log/nginx/access.log
grep -c '' /var/log/nginx/access.log
เปรียบเทียบคำขอภายนอกที่ได้รับอนุญาตกับบันทึกทั้งฝั่งหน้าและฝั่งแบ็กเอนด์ และยืนยันว่ากฎที่ควรปฏิเสธยังปฏิเสธและกฎที่ควรอนุญาตยังอนุญาต ถ้าบรรทัดในบันทึกถูกต้องแต่กฎยังทำเหมือนทุกคนเป็นคนในเครื่อง แสดงว่ากฎอ่านฟิลด์อื่นไม่ใช่ฟิลด์ที่คุณแก้
ปิดท้ายด้วยการเขียนห่วงโซ่การระบุตัวตนลงในบันทึกการติดตั้ง ทั้งตัวรับฟังใด ตัวส่งต่อใด เฮดเดอร์หรือการแมปใด และแบ็กเอนด์ใดที่ตั้งค่าให้เชื่อสิ่งนั้น คนถัดไปที่อ่านบรรทัดในบันทึกจะต้องใช้ทั้งสี่อย่าง และการไม่มีบันทึกนั้นคือเหตุที่ตั๋วเดียวกันเปิดใหม่ในอีกหนึ่งปี ให้เก็บไว้ข้างการตั้งค่าไม่ใช่ในเธรดแชต