nginx real_ip_header và X-Forwarded-For có vẻ sai


59

Mô tả wikipedia của tiêu đề HTTP X-Forwarded-Forlà:

X-Forwarded-For: client1, proxy1, proxy2, ...

Tài liệu nginx cho chỉ thị real_ip_headerđọc, một phần:

Lệnh này đặt tên của tiêu đề được sử dụng để chuyển địa chỉ IP thay thế.
Trong trường hợp X-Forwarded-For, mô-đun này sử dụng ip cuối cùng trong tiêu đề X-Forwarded-For để thay thế. [Nhấn mạnh của tôi]

Hai mô tả này có vẻ mâu thuẫn với nhau. Trong kịch bản của chúng tôi, X-Forwarded-Fortiêu đề chính xác như được mô tả - địa chỉ IP "thực" của khách hàng là mục nhập ngoài cùng bên trái. Tương tự như vậy, hành vi của nginx là sử dụng giá trị ngoài cùng bên phải - mà rõ ràng chỉ là một trong những máy chủ proxy của chúng tôi.

Sự hiểu biết của tôi về X-Real-IPlà nó phải được sử dụng để xác định thực tế địa chỉ IP của khách hàng - không proxy. Tôi có thiếu thứ gì không, hay đây là lỗi trong nginx?

Và, ngoài ra, có ai có bất kỳ đề xuất nào về cách làm cho X-Real-IPtiêu đề hiển thị giá trị ngoài cùng bên trái , như được định nghĩa bởi định nghĩa X-Forwarded-Forkhông?

Câu trả lời:


97

Tôi tin rằng chìa khóa để giải quyết các tai ương X-Forwarded-For khi nhiều IP bị xiềng xích là tùy chọn cấu hình được giới thiệu gần đây, real_ip_recursive(được thêm vào nginx 1.2.1 và 1.3.0). Từ các tài liệu realin nginx :

Nếu tìm kiếm đệ quy được bật, một địa chỉ khách hàng gốc khớp với một trong những địa chỉ đáng tin cậy sẽ được thay thế bằng địa chỉ không đáng tin cậy cuối cùng được gửi trong trường tiêu đề yêu cầu.

nginx đã lấy địa chỉ IP cuối cùng trong chuỗi theo mặc định vì đó là địa chỉ duy nhất được cho là đáng tin cậy. Nhưng với tính năng mới real_ip_recursiveđược kích hoạt và có nhiều set_real_ip_fromtùy chọn, bạn có thể xác định nhiều proxy đáng tin cậy và nó sẽ lấy IP không đáng tin cậy cuối cùng.

Ví dụ: với cấu hình này:

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;

Và một tiêu đề X-Forwarded-For dẫn đến:

X-Forwarded-For: 123.123.123.123, 192.168.2.1, 127.0.0.1

nginx bây giờ sẽ chọn 123.123.123.123 làm địa chỉ IP của khách hàng.

Về lý do tại sao nginx không chỉ chọn địa chỉ IP ngoài cùng bên trái và yêu cầu bạn xác định rõ ràng các proxy đáng tin cậy, đó là để ngăn chặn việc giả mạo IP dễ dàng.

Giả sử địa chỉ IP thực của khách hàng là 123.123.123.123. Chúng ta cũng nói rằng ứng dụng khách không hoạt động và họ đang cố gắng giả mạo địa chỉ IP của họ 11.11.11.11. Họ gửi yêu cầu đến máy chủ với tiêu đề này đã có sẵn:

X-Forwarded-For: 11.11.11.11

Vì các proxy ngược chỉ cần thêm IP vào chuỗi X-Forwarded-For này, giả sử nó kết thúc giống như thế này khi nginx truy cập vào nó:

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

Nếu bạn chỉ cần lấy địa chỉ ngoài cùng bên trái, điều đó sẽ cho phép khách hàng dễ dàng giả mạo địa chỉ IP của họ. Nhưng với ví dụ nginx config ở trên, nginx sẽ chỉ tin tưởng hai địa chỉ cuối cùng là proxy. Điều này có nghĩa là nginx sẽ chọn chính xác 123.123.123.123là địa chỉ IP, mặc dù IP giả mạo đó thực sự là địa chỉ bên trái nhất.


2
Cảm ơn bạn rất nhiều vì điều này, nó thực sự đã giúp tôi. Đây phải là câu trả lời được chấp nhận.
Jose F. Romaniello

1
Theo mặc định, real_ip_header dường như là X-Real-IP theo nginx.org/en/docs/http/ngx_http_realip_module.html Có nghĩa là người dùng độc hại chỉ có thể gửi yêu cầu với X-Real-IP ngẫu nhiên và sẽ được sử dụng như $ remote_addr trong nginx (và cũng có thể chuyển qua ứng dụng)?
gansbrest

@gansbrest Không, vì set_real_ip_from giới hạn các máy chủ đáng tin cậy.
El Yobo

9

Việc phân tích cú pháp của X-Forwarded-Fortiêu đề thực sự là thiếu sót trong mô đun 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;
  }
}

Nó bắt đầu ở phía bên phải của chuỗi tiêu đề và ngay khi nhìn thấy dấu cách hoặc dấu phẩy, nó dừng tìm kiếm và dán phần bên phải của khoảng trắng hoặc dấu phẩy trong biến IP. Vì vậy, nó coi địa chỉ proxy gần đây nhất là địa chỉ khách hàng ban đầu .

Nó không chơi đẹp theo thông số kỹ thuật; Đây là mối nguy hiểm của việc không đánh vần bằng các thuật ngữ rõ ràng đau đớn trong RFC.

Ngoài ra: Thật khó để tìm thấy một nguồn chính tốt trên định dạng, được xác định ban đầu bởi Squid - một tài liệu khai thác thông qua tài liệu của họ xác nhận việc đặt hàng; ngoài cùng bên trái là khách hàng ban đầu, ngoài cùng bên phải là phụ lục gần đây nhất. Tôi rất muốn thêm [cần dẫn nguồn] vào trang wikipedia đó. Một chỉnh sửa ẩn danh dường như là thẩm quyền của internet về chủ đề này.

Nếu có thể, bạn có thể yêu cầu proxy trung gian của mình dừng thêm vào cuối tiêu đề không, chỉ để lại nó với địa chỉ khách hàng thực sự?


Cảm ơn đã trả lời, @Shane. Trong thực tế, khi đạt nginx, một X-Forwarded-Forđã tồn tại. (đó là địa chỉ IP của máy khách chính xác) nginx sau đó tiến hành nối thêm địa chỉ IP của bộ cân bằng tải của chúng tôi (bước nhảy trước) vào X-Forwarded-Fortiêu đề. (có lẽ là nối thêm cái mà nó xem là "địa chỉ từ xa") Nếu đơn giản là nó không làm điều đó, tôi sẽ có thể chỉ sử dụng X-Forwarded-Fortiêu đề như trước đây. (gần đây chúng tôi đã chuyển sang nginx)
Kirk Woll

@Kirk Vậy, khi nginx có tiêu đề, đó chỉ là địa chỉ của khách hàng ban đầu? Nhưng khi xử lý nó, nó có được thêm vào tiêu đề của máy chủ proxy kết nối không? Điều đó không thêm - lần duy nhất nó chạm vào tiêu đề đó là khi nó gửi kết nối đến một proxy khác thông qua một proxy_pass- và thậm chí sau đó, chỉ khi có proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;tại chỗ.
Shane Madden

Ngay cả W3C cũng hiểu sai điều này : tài liệu của họ nói rằng "proxy nên thêm địa chỉ IP của người khởi tạo yêu cầu vào cuối danh sách được phân tách bằng dấu phẩy trong trường tiêu đề X-Forwarded-For HTTP", nên nêu rõ bắt đầu .
Ian Kemp

3
@IanKemp, không, kết thúc là chính xác. Về phía máy chủ của một proxy, người khởi tạo yêu cầu (tức là yêu cầu TCP ) là proxy trước đó (nếu có). Proxy trước đó có thể đã gửi một X-Forwarded-Fortiêu đề có thể có địa chỉ máy khách gốc ở bên trái và có thể bất kỳ proxy trước nào được thêm vào đó. Vì vậy, proxy hiện đang phục vụ sẽ thêm proxy trước (= initator) vào cuối danh sách đó và phục vụ X-Forwarded-Fortiêu đề được tăng cường như vậy cho hop ngược dòng tiếp theo. Cấp, họ có thể đã chọn một từ ngữ rõ ràng hơn.
blubberdiblub

5

X-Real-IP là địa chỉ IP của máy khách thực tế mà máy chủ đang nói chuyện (máy khách "thực" của máy chủ), trong trường hợp kết nối được ủy quyền, là máy chủ proxy. Đó là lý do tại sao X-Real-IP sẽ chứa IP cuối cùng trong tiêu đề X-Forwarded-For.


1
OK, nhưng, đối với tôi, đó đơn giản là thông tin không bao giờ hữu ích. Tôi muốn lấy địa chỉ IP gốc của khách hàng - điều đó rất quan trọng và theo mọi thứ tôi đã đọc, mục đích của những tiêu đề này. Tại sao tôi muốn biết địa chỉ IP của máy chủ proxy của chúng tôi?
Kirk Woll

Nếu nó không hữu ích cho bạn thì nó không dành cho bạn. Không ai ép buộc bạn sử dụng X-Real-IP. Nếu bạn cần IP của người dùng trong ứng dụng của mình, thì hãy phân tích ứng dụng của bạn X-Forwarded-For (không phải lúc nào cũng đáng tin cậy vì có một số proxy (thiết bị / tường lửa bảo mật internet) không đặt X-Forwarded- Cho). Trong ngữ cảnh của nginx, X-Forwarded-For không quan trọng vì dù sao nó cũng không nói chuyện với những khách hàng đó, ngoài mục cuối cùng (X-Real-IP) là khách hàng của nginx. Nếu bạn không cần nó thì đừng đặt nó, bỏ đặt nó hoặc bỏ qua nó: /
user558061

2
Không, những gì tôi có nghĩa là, tại sao sẽ X-Real-IPtrở về địa chỉ IP máy chủ proxy của riêng tôi bao giờ có ích?
Kirk Woll

Tuyệt vời .. trả lời người đàn ông. Tôi đã tìm kiếm thông tin chính xác này. Tôi cần nói chuyện với một máy chủ ncat trên máy chủ proxy của mình, vì vậy tôi cần điều này một cách nhanh chóng.
Joly Julum
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.