2012-07-12 42 views
20

Được rồi, tôi gặp sự cố xác thực nhỏ. Dịch vụ web của tôi cho phép kết nối với API của tôi qua HTTP với tên người dùng và mật khẩu, nhưng kết nối này cũng có thể bị giới hạn ở một địa chỉ IP cụ thể.Cách sử dụng HTTP_X_FORWARDED_FOR đúng cách?

Điều này có nghĩa là $_SERVER['REMOTE_ADDR'] có thể không chính xác. Tôi đã biết rằng mọi thông tin IP có thể không bao giờ thực sự được dựa vào - tôi chỉ có giới hạn trong một nỗ lực để thêm một lớp bảo mật khác.

Nếu đây là tổng quan chung của một yêu cầu đến máy chủ web của tôi:

clientSERVER => clientPROXY => myPROXY => mySERVER

Sau đó, điều này có nghĩa rằng myserver lãm REMOTE_ADDR của MyProxy thay vì đó của khách hàng và gửi IP thực tế của khách hàng là HTTP_X_FORWARDED_FOR.

Để khắc phục điều này, dịch vụ web của tôi có danh sách địa chỉ IP 'tin cậy proxy' và nếu REMOTE_ADDR là một trong những địa chỉ IP đáng tin cậy đó, thì nó sẽ cho dịch vụ web của tôi biết địa chỉ IP thực tế là giá trị HTTP_X_FORWARDED_FOR.

Bây giờ vấn đề là với clientPROXY. Điều này có nghĩa là (thường xuyên) mySERVER nhận được giá trị HTTP_X_FORWARDED_FOR có nhiều địa chỉ IP. Theo tài liệu HTTP_X_FORWARDED_FOR, giá trị là danh sách địa chỉ IP được phân tách bằng dấu phẩy, trong đó IP đầu tiên là địa chỉ IP của ứng dụng khách thực sự và mọi địa chỉ IP khác là của proxy.

Vì vậy, nếu HTTP_X_FORWARDED_FOR có nhiều giá trị và dịch vụ của tôi bị hạn chế IP, tôi có phải kiểm tra giá trị 'cuối cùng' của HTTP_X_FORWARDED_FOR đối với danh sách IP được cho phép của tôi không? Tôi giả định rằng trong một hệ thống, nơi tôi phải thiết lập danh sách các địa chỉ IP được cho phép, địa chỉ IP được đưa vào danh sách trắng phải là địa chỉ của proxy và không phải là IP phía sau proxy (vì đó có thể là một số IP localhost). và thay đổi thường xuyên).

Và nội dung của HTTP_CLIENT_IP là gì?

+0

http : //stackoverflow.com/q/7445592/759866 – Benjamin

Trả lời

-4

HTTP_CLIENT_IP là cách đáng tin cậy nhất để nhận địa chỉ IP của người dùng. Tiếp theo là HTTP_X_FORWARDED_FOR, tiếp theo là REMOTE_ADDR. Kiểm tra tất cả ba, theo thứ tự đó, giả định rằng giá trị đầu tiên được đặt (isset($_SERVER['HTTP_CLIENT_IP']) trả về true nếu biến đó được đặt) là chính xác. Bạn có thể kiểm tra độc lập nếu người dùng đang sử dụng proxy sử dụng các phương pháp khác nhau. Kiểm tra this.

+7

Không có tiêu đề nào trong số này là "đáng tin cậy hơn" so với các tiêu đề khác. Tất cả chúng có thể được khách hàng giả mạo và các ứng dụng của bạn cần biết những gì đáng tin cậy và những gì không: bạn thường biết cơ sở hạ tầng và địa chỉ IP của bất kỳ trình cân bằng tải/proxy nào trước máy chủ HTTP của bạn. – Benjamin

+1

Đúng, nhưng nói chung, nếu một thứ tự ưu tiên được thiết lập dựa trên độ tin cậy giả định, thì đây là nó. Tôi nhận ra rằng tất cả chúng đều có thể được điều khiển, nhưng nếu chúng phải được sử dụng, thì đây là cách để thực hiện nó. – TheEnvironmentalist

+5

Tại sao có quá nhiều thông tin sai lệch về chủ đề này? '$ _SERVER ['REMOTE_ADDR']' là trường * đáng tin cậy * duy nhất không bị ảnh hưởng bởi người dùng từ xa, tất cả các trường khác được phân tích cú pháp từ các tiêu đề. – transistor09

13

Bạn có thể sử dụng chức năng này để có được đúng IP của khách hàng:

public function getClientIP(){  
    if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)){ 
      return $_SERVER["HTTP_X_FORWARDED_FOR"]; 
    }else if (array_key_exists('REMOTE_ADDR', $_SERVER)) { 
      return $_SERVER["REMOTE_ADDR"]; 
    }else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { 
      return $_SERVER["HTTP_CLIENT_IP"]; 
    } 

    return ''; 
} 
+3

Câu trả lời này không giải quyết được tình huống cụ thể được mô tả trong câu hỏi, trong đó ** không phải tất cả yêu cầu đều được chuyển qua proxy **. Do đó, các yêu cầu nhận được trực tiếp từ khách hàng có thể chứa địa chỉ IP không chính xác trong tiêu đề. – duskwuff

+0

Câu trả lời hay, bạn có thể tìm thấy thậm chí chính xác từ lớp Tools của Prestashop :). Tìm hàm getRemoteAddr() –

13

Tôi thích câu trả lời của Hrishikesh, mà tôi chỉ có này để thêm ... bởi vì chúng ta đã thấy một chuỗi dấu phẩy phân cách đi ngang qua khi nhiều proxy trên đường đi đã được sử dụng, chúng tôi tìm thấy nó cần thiết để thêm một phát nổ và lấy giá trị cuối cùng, như thế này:

$IParray=array_values(array_filter(explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']))); 
return end($IParray); 

các array_filter là ở đó để loại bỏ các mục rỗng.

+2

Lưu ý rằng có vẻ như việc sử dụng giá trị cuối cùng trong danh sách vẫn có thể sử dụng IP của proxy. Theo liên kết bên dưới, khách hàng gốc là IP ĐẦU TIÊN. http://en.wikipedia.org/wiki/X-Forwarded-For –

+2

Cũng lưu ý rằng cùng một nguồn nói rằng điều này rất dễ dàng để giả mạo, vì vậy cuối cùng là đáng tin cậy hơn. Vì vậy, mỗi trường hợp sử dụng có thể đưa ra các lựa chọn khác nhau. Nếu trường hợp sử dụng để nhận IP là chống gian lận hoặc spam, IP đầu tiên có thể là vô nghĩa và địa chỉ đáng tin cậy nhất - địa chỉ cuối cùng - hữu ích nhất. Nếu trường hợp sử dụng để nhận IP ít hoạt động bất chính, trường hợp đầu tiên sẽ hữu ích nhất. –

0

Nếu bạn sử dụng nó trong một cơ sở dữ liệu, đây là một cách tốt:

Đặt lĩnh vực ip trong cơ sở dữ liệu varchar (250), và sau đó sử dụng này:

$theip = $_SERVER["REMOTE_ADDR"]; 

if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) { 
    $theip .= '('.$_SERVER["HTTP_X_FORWARDED_FOR"].')'; 
} 

if (!empty($_SERVER["HTTP_CLIENT_IP"])) { 
    $theip .= '('.$_SERVER["HTTP_CLIENT_IP"].')'; 
} 

$realip = substr($theip, 0, 250); 

Sau đó, bạn chỉ cần kiểm tra $ realip đối với trường ip cơ sở dữ liệu

6

Trong ánh sáng mới nhất của httpoxy lỗ hổng, thực sự cần có một ví dụ đầy đủ, cách sử dụng HTTP_X_FORWARDED_FOR đúng cách.

Vì vậy, đây là một ví dụ viết bằng PHP, làm thế nào để phát hiện một địa chỉ IP của khách hàng, nếu bạn biết rằng khách hàng có thể sau một proxy và bạn biết proxy này có thể được tin cậy. Nếu bạn không biết bất kỳ proxy đáng tin cậy, chỉ cần sử dụng REMOTE_ADDR

<?php 

function get_client_ip() 
{ 
    // Nothing to do without any reliable information 
    if (!isset ($_SERVER['REMOTE_ADDR'])) { 
     return NULL; 
    } 

    // Header that is used by the trusted proxy to refer to 
    // the original IP 
    $proxy_header = "HTTP_X_FORWARDED_FOR"; 

    // List of all the proxies that are known to handle 'proxy_header' 
    // in known, safe manner 
    $trusted_proxies = array ("2001:db8::1", "192.168.50.1"); 

    if (in_array ($_SERVER['REMOTE_ADDR'], $trusted_proxies)) { 

     // Get the IP address of the client behind trusted proxy 
     if (array_key_exists ($proxy_header, $_SERVER)) { 

      // Header can contain multiple IP-s of proxies that are passed through. 
      // Only the IP added by the last proxy (last IP in the list) can be trusted. 
      $proxy_list = explode (",", $_SERVER[$proxy_header]); 
      $client_ip = trim (end ($proxy_list)); 

      // Validate just in case 
      if (filter_var ($client_ip, FILTER_VALIDATE_IP)) { 
       return $client_ip; 
      } else { 
       // Validation failed - beat the guy who configured the proxy or 
       // the guy who created the trusted proxy list? 
       // TODO: some error handling to notify about the need of punishment 
      } 
     } 
    } 

    // In all other cases, REMOTE_ADDR is the ONLY IP we can trust. 
    return $_SERVER['REMOTE_ADDR']; 
} 

print get_client_ip(); 

?> 
+0

Đây là một câu trả lời tuyệt vời, nhưng có một vấn đề nhỏ. Nếu báo cáo lỗi nghiêm ngặt được bật, cố gắng 'cắt (kết thúc (phát nổ()))' trên một dòng sẽ trả về "Chỉ các biến sẽ được chuyển qua tham chiếu". Để giải quyết vấn đề đó, hãy đặt tiêu đề proxy đã phát hiện thành biến trước, sau đó thay vào đó 'cắt (kết thúc())'. –

+0

@BenDyer Cảm ơn bạn đã sửa nó. –

1

Bạn cũng có thể giải quyết vấn đề này thông qua cấu hình Apache sử dụng mod_remoteip, bằng cách thêm dòng sau vào một tập tin conf.d:

RemoteIPHeader X-Forwarded-For 
RemoteIPInternalProxy 172.16.0.0/12 
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined 
Các vấn đề liên quan