nginx real_ip_header และ X-Forwarded- สำหรับดูเหมือนว่าผิด


58

คำอธิบายวิกิพีเดียของส่วนหัว HTTP X-Forwarded-Forคือ:

X-Forwarded- สำหรับ: client1, proxy1, proxy2, ...

เอกสารประกอบ nginx สำหรับคำสั่งการreal_ip_headerอ่านส่วนหนึ่ง:

คำสั่งนี้ตั้งชื่อของส่วนหัวที่ใช้สำหรับการถ่ายโอนที่อยู่ IP ทดแทน
ในกรณีของ X-Forwarded-For โมดูลนี้ใช้IP สุดท้ายในส่วนหัว X-Forwarded-For เพื่อทดแทน [เน้นเหมือง]

คำอธิบายทั้งสองนี้ดูขัดแย้งกัน ในสถานการณ์สมมติของเราX-Forwarded-Forส่วนหัวเป็นไปตามที่อธิบายไว้ - ที่อยู่ IP "ของจริง" ของลูกค้าเป็นรายการทางซ้ายสุด ในทำนองเดียวกันพฤติกรรมของ nginx คือการใช้ค่าขวาสุด - ซึ่งแน่นอนว่าเป็นเพียงหนึ่งในพร็อกซีเซิร์ฟเวอร์ของเรา

ความเข้าใจของฉันX-Real-IPคือมันควรจะใช้เพื่อกำหนดที่อยู่ IP ของลูกค้าที่แท้จริง - ไม่ใช่พร็อกซี ฉันขาดอะไรไปหรือว่าเป็นบั๊กใน nginx

และนอกเหนือจากนั้นไม่มีใครมีคำแนะนำสำหรับวิธีการทำให้X-Real-IPส่วนหัวแสดงค่าซ้ายสุดตามที่ระบุโดยคำจำกัดความของX-Forwarded-For?

คำตอบ:


95

ฉันเชื่อว่ากุญแจสำคัญในการแก้ปัญหา X-Forwarded-For woes เมื่อหลาย IP ถูกล่ามโซ่เป็นตัวเลือกการกำหนดค่าที่เพิ่งเปิดตัวreal_ip_recursive(เพิ่มใน nginx 1.2.1 และ 1.3.0) จากเอกสาร nginx realip :

หากเปิดใช้การค้นหาแบบเรียกซ้ำที่อยู่ไคลเอ็นต์ดั้งเดิมที่ตรงกับหนึ่งในที่อยู่ที่เชื่อถือได้จะถูกแทนที่ด้วยที่อยู่ที่ไม่น่าเชื่อถือสุดท้ายที่ส่งในฟิลด์ส่วนหัวคำขอ

โดยค่าเริ่มต้น nginx กำลังดึงที่อยู่ IP สุดท้ายในห่วงโซ่เนื่องจากเป็นที่อยู่เดียวที่สันนิษฐานว่าเชื่อถือได้ แต่ด้วยการreal_ip_recursiveเปิดใช้งานใหม่และด้วยหลายset_real_ip_fromตัวเลือกคุณสามารถกำหนดพร็อกซีที่เชื่อถือได้หลายรายการและจะดึง IP ที่ไม่น่าเชื่อถือล่าสุด

ตัวอย่างเช่นด้วยการกำหนดค่านี้:

set_real_ip_from 127.0.0.1;
set_real_ip_from 192.168.2.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

และส่วนหัว X-Forwarded-For ทำให้เกิด:

X-Forwarded-For: 123.123.123.123, 192.168.2.1, 127.0.0.1

nginx จะเลือก 123.123.123.123 เป็นที่อยู่ IP ของลูกค้า

สำหรับเหตุผลที่ nginx ไม่เพียงแค่เลือกที่อยู่ IP ซ้ายสุดและต้องการให้คุณกำหนดพร็อกซีที่เชื่อถือได้อย่างชัดเจนเพื่อป้องกันการแอบอ้าง IP ได้ง่าย

สมมติว่าที่อยู่ IP 123.123.123.123จริงของลูกค้าคือ Let 's ยังบอกลูกค้าถึงไม่ดีและพวกเขากำลังพยายามที่จะหลอกที่อยู่ IP 11.11.11.11ของพวกเขาจะ พวกเขาส่งคำขอไปยังเซิร์ฟเวอร์โดยมีส่วนหัวนี้อยู่แล้ว:

X-Forwarded-For: 11.11.11.11

เนื่องจาก reverse proxies เพียงแค่เพิ่ม IP ลงในเชน X-Forwarded-For นี้สมมติว่ามันจะเป็นแบบนี้เมื่อ nginx เข้ามา:

X-Forwarded-For: 11.11.11.11, 123.123.123.123, 192.168.2.1, 127.0.0.1

หากคุณเพียงแค่คว้าที่อยู่ทางซ้ายสุดนั่นจะทำให้ลูกค้าสามารถปลอมแปลงที่อยู่ IP ของพวกเขาได้อย่างง่ายดาย แต่ด้วยตัวอย่างข้างต้นการกำหนดค่า nginx nginx จะไว้วางใจที่อยู่สองรายการสุดท้ายเป็นพร็อกซีเท่านั้น ซึ่งหมายความว่า nginx จะเลือกอย่างถูกต้อง123.123.123.123เป็นที่อยู่ IP แม้ว่า IP ปลอมแปลงนั้นจะอยู่ทางซ้ายสุด


1
ขอบคุณมากสำหรับสิ่งนี้มันช่วยฉันได้จริงๆ นี่ควรเป็นคำตอบที่ยอมรับได้
José F. Romaniello

1
โดยค่าเริ่มต้น real_ip_header ดูเหมือนจะเป็น X-Real-IP ตามnginx.org/en/docs/http/ngx_http_realip_module.htmlหมายความว่าผู้ใช้ที่ประสงค์ร้ายสามารถส่งคำขอด้วยการสุ่ม X-Real-IP และจะใช้เป็น $ remote_addr ใน nginx (และอาจส่งผ่านไปยังแอปพลิเคชันด้วย)
gansbrest

@gansbrest ไม่เพราะ set_real_ip_from จำกัด โฮสต์ที่เชื่อถือได้
El Yobo

9

การวิเคราะห์X-Forwarded-Forส่วนหัวนั้นมีข้อบกพร่องในโมดูล nginx real_ip

len = r->headers_in.x_forwarded_for->value.len;
ip = r->headers_in.x_forwarded_for->value.data;

for (p = ip + len - 1; p > ip; p--) {
  if (*p == ' ' || *p == ',') {
    p++;
    len -= p - ip;
    ip = p;
    break;
  }
}

มันเริ่มต้นที่ด้านขวาสุดของสตริงส่วนหัวและทันทีที่เห็นช่องว่างหรือเครื่องหมายจุลภาคหยุดค้นหาและติดชิ้นส่วนทางด้านขวาของช่องว่างหรือเครื่องหมายจุลภาคในตัวแปร IP ดังนั้นจึงเป็นการรักษาที่อยู่พร็อกซี่ล่าสุดเป็นที่อยู่ลูกค้าเดิม

มันไม่ได้เล่นได้ดีตามสเป็ค; นี่คืออันตรายที่ไม่มีการสะกดคำในเงื่อนไขที่ชัดเจนอย่างเจ็บปวดใน RFC

ด้านข้าง:มันยากที่จะหาแหล่งที่มาหลักที่ดีในรูปแบบซึ่งเดิมกำหนดโดย Squid - ขุดผ่านเอกสารของพวกเขายืนยันการสั่งซื้อ; leftmost เป็นไคลเอนต์ดั้งเดิม rightmost คือผนวกล่าสุด ฉันถูกล่อลวงอย่างมากที่จะเพิ่ม[อ้างอิงที่จำเป็น]ไปยังหน้าวิกิพีเดีย ดูเหมือนว่าการแก้ไขที่ไม่ระบุชื่อหนึ่งรายการจะเป็นสิทธิ์ของอินเทอร์เน็ตในหัวเรื่อง

ถ้าเป็นไปได้คุณสามารถให้ผู้รับมอบฉันทะกลางของคุณหยุดเพิ่มตัวเองลงที่ส่วนท้ายของส่วนหัวได้หรือไม่เพียงปล่อยให้มันอยู่กับที่อยู่ลูกค้าจริงเท่านั้น


ขอบคุณสำหรับการตอบกลับ @Shane ในความเป็นจริงเมื่อไปถึง nginx มีX-Forwarded-Forอยู่แล้ว (เป็นที่อยู่ IP ไคลเอนต์ที่ถูกต้อง) nginxนั้นจะดำเนินการผนวกที่อยู่ IP ของ load balancer ของเรา (hop ก่อนหน้า) เข้ากับX-Forwarded-Forส่วนหัว (สันนิษฐานว่าต่อท้ายสิ่งที่เห็นว่าเป็น "ที่อยู่ระยะไกล") หากไม่ได้ทำอย่างนั้นฉันก็จะสามารถใช้X-Forwarded-Forส่วนหัวเหมือนเดิม (เราเพิ่งย้ายไปที่ nginx)
Kirk Woll

@ Kirk ดังนั้นเมื่อ nginx ได้รับส่วนหัวก็เป็นเพียงที่อยู่เดิมของลูกค้า? แต่เมื่อมันประมวลผลมันจะถูกเพิ่มในส่วนหัวของเซิร์ฟเวอร์พร็อกซีเชื่อมต่อ? ที่ไม่ได้เพิ่มขึ้น - เพียงครั้งเดียวที่มันควรจะแตะที่ส่วนหัวนั่นคือเมื่อมันกำลังส่งการเชื่อมต่อไปยังพร็อกซีอื่นผ่านทางproxy_pass- และแม้กระทั่งproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;ในสถานที่เท่านั้น
เชนหัวเสีย

แม้ได้รับ W3C ผิดนี้ : เอกสารของพวกเขาระบุว่า "ผู้รับมอบฉันทะควรเพิ่มที่อยู่ IP ของริเริ่มของการร้องขอไปยังจุดสิ้นสุดของจุลภาครายการแยก X-Forwarded-For ฟิลด์หัว HTTP" ก็ควรระบุจุดเริ่มต้น
Ian Kemp

3
@IanKemp ไม่สิ้นสุดถูกต้อง ไปยังฝั่งเซิร์ฟเวอร์ของพร็อกซีผู้ริเริ่มการร้องขอ (เช่นการร้องขอTCP ) เป็นพร็อกซีก่อนหน้า (ถ้ามี) พร็อกซีก่อนหน้านี้อาจจะมีอยู่แล้วส่งX-Forwarded-Forส่วนหัวที่มีอาจจะเป็นที่อยู่ของลูกค้าเดิมที่ด้านซ้ายและอาจมอบฉันทะก่อนหน้าใด ๆ ต่อท้ายว่า ดังนั้นพร็อกซีที่ให้บริการในปัจจุบันจะเพิ่มพร็อกซีก่อนหน้า (= ผู้เริ่มต้น) ไปยังจุดสิ้นสุดของรายการX-Forwarded-Forนั้น จริงอยู่พวกเขาสามารถเลือกถ้อยคำที่ชัดเจนกว่านี้ได้
blubberdiblub

5

X-Real-IP เป็นที่อยู่ IP ของไคลเอนต์จริงที่เซิร์ฟเวอร์กำลังพูดถึง (ไคลเอนต์ "ของจริง" ของเซิร์ฟเวอร์) ซึ่งในกรณีของการเชื่อมต่อพร็อกซีเป็นพร็อกซีเซิร์ฟเวอร์ นั่นเป็นเหตุผลที่ X-Real-IP จะมี IP สุดท้ายในส่วนหัว X-Forwarded-For


1
ตกลง แต่สำหรับฉันนั่นเป็นเพียงข้อมูลที่ไม่มีประโยชน์ ฉันต้องการได้รับที่อยู่ IP ดั้งเดิมของลูกค้า - นั่นเป็นสิ่งสำคัญและจากทุกสิ่งที่ฉันอ่านวัตถุประสงค์ของส่วนหัวเหล่านี้ เหตุใดฉันจึงต้องการทราบที่อยู่ IP ของพร็อกซีเซิร์ฟเวอร์ของเรา
Kirk Woll

หากไม่มีประโยชน์สำหรับคุณก็ไม่เหมาะสำหรับคุณ ไม่มีใครบังคับให้คุณใช้ X-Real-IP หากคุณต้องการ IP ของผู้ใช้ในแอปพลิเคชันของคุณให้แอปพลิเคชันของคุณแยกวิเคราะห์ X-Forwarded-For (ซึ่งไม่น่าเชื่อถือเสมอไปเนื่องจากมีพร็อกซี่บางอย่าง (อุปกรณ์ความปลอดภัยอินเทอร์เน็ต / ไฟร์วอลล์) ที่ไม่ได้ตั้งค่า X-Forwarded- สำหรับ). ในบริบทของ nginx, X-Forwarded-For นั้นไม่สำคัญเพราะมันไม่ได้พูดคุยกับลูกค้าเหล่านั้นนอกเหนือจากรายการสุดท้าย (X-Real-IP) ซึ่งเป็นไคลเอนต์ของ nginx ถ้าคุณไม่ต้องการมันก็ไม่ต้องตั้งมันให้ยกเลิกมันหรือไม่สนใจมัน: /
user558061

2
ไม่มีสิ่งที่ผมหมายถึงคือทำไมจะX-Real-IPกลับที่อยู่ IP พร็อกซีเซิร์ฟเวอร์ของฉันเองเคยเป็นประโยชน์หรือไม่
Kirk Woll

ยอดเยี่ยม .. ตอบคน ฉันกำลังมองหาข้อมูลที่แม่นยำนี้ ฉันต้องคุยกับเซิร์ฟเวอร์ ncat บนพร็อกซีเซิร์ฟเวอร์ของฉันดังนั้นฉันต้องการสิ่งนี้ในทันที
Jugal Jindle
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.