Saya tahu ada sejumlah besar variabel $ _SERVER header tersedia untuk pencarian alamat IP. Saya bertanya-tanya apakah ada konsensus umum tentang bagaimana cara paling akurat mengambil alamat IP asli pengguna (juga mengetahui tidak ada metode yang sempurna) menggunakan variabel tersebut?
Saya menghabiskan waktu mencoba mencari solusi yang mendalam dan menghasilkan kode berikut berdasarkan sejumlah sumber. Saya akan senang jika seseorang bisa menyodok jawaban atau memberi penjelasan tentang sesuatu yang mungkin lebih akurat.
sunting mencakup optimisasi dari @Alix
/**
* Retrieves the best guess of the client's actual IP address.
* Takes into account numerous HTTP proxy headers due to variations
* in how different ISPs handle IP addresses in headers between hops.
*/
public function get_ip_address() {
// Check for shared internet/ISP IP
if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))
return $_SERVER['HTTP_CLIENT_IP'];
// Check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// Check if multiple IP addresses exist in var
$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($iplist as $ip) {
if ($this->validate_ip($ip))
return $ip;
}
}
}
if (!empty($_SERVER['HTTP_X_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_X_FORWARDED']))
return $_SERVER['HTTP_X_FORWARDED'];
if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
return $_SERVER['HTTP_FORWARDED_FOR'];
if (!empty($_SERVER['HTTP_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_FORWARDED']))
return $_SERVER['HTTP_FORWARDED'];
// Return unreliable IP address since all else failed
return $_SERVER['REMOTE_ADDR'];
}
/**
* Ensures an IP address is both a valid IP address and does not fall within
* a private network range.
*
* @access public
* @param string $ip
*/
public function validate_ip($ip) {
if (filter_var($ip, FILTER_VALIDATE_IP,
FILTER_FLAG_IPV4 |
FILTER_FLAG_IPV6 |
FILTER_FLAG_NO_PRIV_RANGE |
FILTER_FLAG_NO_RES_RANGE) === false)
return false;
self::$ip = $ip;
return true;
}
Words of Warning (pembaruan)
REMOTE_ADDR
masih merupakan sumber alamat IP yang paling dapat diandalkan . $_SERVER
Variabel lain yang disebutkan di sini dapat dipalsukan oleh klien jarak jauh dengan sangat mudah. Tujuan solusi ini adalah untuk mencoba menentukan alamat IP klien yang duduk di belakang proxy. Untuk tujuan umum Anda, Anda dapat mempertimbangkan menggunakan ini dalam kombinasi dengan alamat IP yang dikembalikan langsung dari $_SERVER['REMOTE_ADDR']
dan menyimpan keduanya.
Untuk 99,9% pengguna solusi ini akan sesuai dengan kebutuhan Anda dengan sempurna. Itu tidak akan melindungi Anda dari 0,1% pengguna jahat yang ingin menyalahgunakan sistem Anda dengan menyuntikkan header permintaan mereka sendiri. Jika mengandalkan alamat IP untuk sesuatu misi penting, gunakan REMOTE_ADDR
dan jangan repot-repot melayani mereka yang berada di belakang proxy.
sumber
Jawaban:
Berikut ini cara yang lebih singkat dan lebih bersih untuk mendapatkan alamat IP:
Saya harap ini membantu!
Kode Anda tampaknya sudah cukup lengkap, saya tidak dapat melihat kemungkinan bug di dalamnya (selain dari peringatan IP yang biasa), saya akan mengubah
validate_ip()
fungsi untuk mengandalkan ekstensi filter:HTTP_X_FORWARDED_FOR
Cuplikan Anda juga dapat disederhanakan dari ini:Untuk ini:
Anda mungkin juga ingin memvalidasi alamat IPv6.
sumber
filter_var
perbaikan karena menghapus sekelompok cek int unsigned hackish pada alamat IP. Saya juga menyukai kenyataan itu memberi saya opsi untuk memvalidasi alamat IPv6 juga. TheHTTP_X_FORWARDED_FOR
optimasi juga dihargai. Dalam beberapa menit saya akan memperbarui kode.Namun demikian, mendapatkan alamat IP asli pengguna akan menjadi tidak dapat diandalkan. Yang perlu mereka lakukan adalah menggunakan server proxy anonim (server yang tidak menghormati header untuk http_x_forwarded_for, http_forwarded, dll) dan yang Anda dapatkan hanyalah alamat IP server proxy mereka.
Anda kemudian dapat melihat apakah ada daftar alamat IP server proxy yang anonim, tetapi tidak ada cara untuk memastikan bahwa 100% akurat juga dan yang paling banyak dilakukan adalah memberi tahu Anda bahwa itu adalah server proxy. Dan jika seseorang pandai, mereka bisa menipu header untuk HTTP ke depan.
Katakanlah saya tidak suka perguruan tinggi setempat. Saya mencari tahu alamat IP apa yang mereka daftarkan, dan mendapatkan alamat IP mereka dilarang di situs Anda dengan melakukan hal-hal buruk, karena saya tahu Anda menghormati HTTP ke depan. Daftar ini tidak ada habisnya.
Lalu ada, seperti yang Anda duga, alamat IP internal seperti jaringan perguruan tinggi yang saya kenal sebelumnya. Banyak yang menggunakan format 10.xxx. Jadi yang Anda tahu adalah bahwa itu diteruskan untuk jaringan bersama.
Maka saya tidak akan mulai banyak ke dalamnya, tetapi alamat IP dinamis adalah cara broadband lagi. Begitu. Bahkan jika Anda mendapatkan alamat IP pengguna, harapkan itu berubah dalam 2 - 3 bulan, paling lama.
sumber
Kita gunakan:
Ledakan pada HTTP_X_FORWARDED_FOR adalah karena masalah aneh kami telah mendeteksi alamat IP ketika Squid digunakan.
sumber
Jawaban saya pada dasarnya hanya versi @ AlixAxel yang dipoles, sepenuhnya divalidasi, dan dikemas penuh:
Perubahan:
Ini menyederhanakan nama fungsi (dengan gaya format 'camelCase').
Ini termasuk pemeriksaan untuk memastikan fungsi tersebut belum dideklarasikan di bagian lain dari kode Anda.
Ini memperhitungkan kompatibilitas akun 'CloudFlare'.
Ini menginisialisasi beberapa nama variabel "terkait IP" ke nilai yang dikembalikan, dari fungsi 'getClientIP'.
Ini memastikan bahwa jika fungsi tidak mengembalikan alamat IP yang valid, semua variabel diatur ke string kosong, bukan
null
.Hanya (45) baris kode.
sumber
Pertanyaan terbesar adalah untuk tujuan apa?
Kode Anda hampir selengkap mungkin - tetapi saya melihat bahwa jika Anda melihat apa yang tampak seperti header yang ditambahkan proxy, Anda menggunakan BUKAN dari CLIENT_IP, namun jika Anda ingin informasi ini untuk keperluan audit maka diperingatkan - sangat mudah untuk palsu.
Tentu saja Anda tidak boleh menggunakan alamat IP untuk segala jenis otentikasi - bahkan ini dapat dipalsukan.
Anda bisa mendapatkan pengukuran yang lebih baik dari alamat ip klien dengan mendorong keluar flash atau applet java yang menghubungkan kembali ke server melalui port non-http (yang karenanya akan mengungkapkan proxy transparan atau kasus di mana header yang disuntikkan proxy salah - tetapi ingatlah bahwa, di mana klien HANYA dapat terhubung melalui proxy web atau port keluar diblokir, tidak akan ada koneksi dari applet.
C.
sumber
$_SERVER['CLIENT_IP']
sebagai pernyataan if if yang kedua?Saya menyadari ada jawaban yang jauh lebih baik dan lebih ringkas di atas, dan ini bukan fungsi atau skrip yang paling anggun di sekitar. Dalam kasus kami, kami perlu menampilkan x_forwarded_for yang dapat spoofable dan remote_addr yang lebih andal dalam peralihan simplistic per-say. Itu diperlukan untuk memungkinkan kosong untuk menyuntikkan ke fungsi lain jika-tidak ada atau jika-tunggal (daripada hanya mengembalikan fungsi yang sudah diformat sebelumnya). Itu membutuhkan var "on atau off" dengan label khusus per-switch untuk pengaturan platform. Itu juga membutuhkan cara agar $ ip menjadi dinamis tergantung pada permintaan sehingga akan mengambil bentuk forwarded_for.
Saya juga tidak melihat siapa pun alamat isset () vs! Empty () - kemungkinan untuk memasukkan apa pun untuk x_forwarded_for namun masih memicu isset () kebenaran yang menghasilkan blank var, cara untuk berkeliling adalah menggunakan && dan menggabungkan keduanya sebagai syarat. Ingatlah bahwa Anda dapat memalsukan kata-kata seperti "PWNED" sebagai x_forwarded_for jadi pastikan Anda mensterilkan ke sintaks ip nyata jika keluaran Anda di suatu tempat dilindungi atau menjadi DB.
Juga, Anda dapat menguji menggunakan google translate jika Anda memerlukan multi-proxy untuk melihat array di x_forwarder_for. Jika Anda ingin spoof header untuk diuji, lihat ini Spoof Header Klien Chrome ekstensi . Ini akan default ke standar hanya remote_addr sementara di belakang proxy anon.
Saya tidak tahu apa pun di mana remote_addr bisa kosong, tetapi ada sebagai cadangan untuk berjaga-jaga.
Untuk membuat ini dinamis untuk digunakan dalam fungsi (s) atau permintaan / gema / tampilan di bawah ini, katakan untuk log gen atau pelaporan kesalahan, gunakan global atau hanya gema di mana pun Anda inginkan tanpa membuat satu ton kondisi lain atau static-schema-output fungsi.
Terima kasih atas semua pemikiran hebat Anda. Tolong beri tahu saya jika ini bisa lebih baik, masih agak baru untuk header ini :)
sumber
Saya datang dengan fungsi ini yang tidak hanya mengembalikan alamat IP tetapi sebuah array dengan informasi IP.
Inilah fungsinya:
sumber
Seperti yang dikatakan seseorang sebelumnya, kuncinya di sini adalah untuk alasan apa Anda ingin menyimpan ips pengguna.
Saya akan memberikan contoh dari sistem registrasi tempat saya bekerja dan tentu saja solusinya hanya untuk berkontribusi pada diskusi lama ini yang sering muncul dalam pencarian saya.
Banyak perpustakaan pendaftaran php menggunakan ip untuk menutup / mengunci upaya yang gagal berdasarkan ip pengguna. Pertimbangkan tabel ini:
Kemudian, ketika pengguna mencoba melakukan login atau apapun yang berhubungan dengan servis seperti pengaturan ulang kata sandi, sebuah fungsi dipanggil di awal:
Katakanlah, misalnya,
$this->token->get('attempts_before_ban') === 10
dan 2 pengguna datang untuk ips yang sama seperti halnya dalam kode sebelumnya di mana tajuk dapat dipalsukan , lalu setelah 5 upaya masing-masing keduanya dilarang ! Bahkan yang terburuk, jika semua berasal dari proxy yang sama maka hanya 10 pengguna pertama yang akan dicatat dan sisanya akan diblokir!Yang penting di sini adalah bahwa kita memerlukan indeks unik di atas meja
attempts
dan kita bisa mendapatkannya dari kombinasi seperti:di mana
jwt_load
berasal dari cookie http yang mengikuti teknologi token web json di mana kami menyimpan hanya muatan terenkripsi yang harus berisi nilai arbitrer / unik untuk setiap pengguna. Tentu saja permintaan harus diubah ke:"SELECT count(*) FROM {$this->token->get('table_attempts')} WHERE ip = ? AND jwt_load = ?"
dan kelas juga harus memulai aprivate $jwt
.sumber
Saya bertanya-tanya apakah mungkin Anda harus mengulangi HTTP_X_FORWARDED_FOR yang meledak dalam urutan terbalik, karena pengalaman saya adalah bahwa alamat IP pengguna berakhir di akhir daftar yang dipisahkan koma, jadi mulai dari awal header, Anda lebih mungkin untuk mendapatkan alamat ip dari salah satu proxy yang dikembalikan, yang berpotensi masih memungkinkan pembajakan sesi karena banyak pengguna dapat datang melalui proxy itu.
sumber
Terima kasih untuk ini, sangat berguna.
Akan sangat membantu jika kode itu benar secara sintaksis. Karena ada {terlalu banyak di sekitar baris 20. Yang saya khawatir berarti tidak ada yang benar-benar mencoba ini.
Saya mungkin gila, tetapi setelah mencobanya pada beberapa alamat yang valid dan tidak valid, satu-satunya versi validate_ip () yang berfungsi adalah ini:
sumber
Ini adalah versi yang dimodifikasi jika Anda menggunakan Layanan lapisan caching CloudFlare
sumber
Hanya versi VB.NET dari jawabannya:
sumber
Hanya cara bersih lainnya:
sumber
Dari kelas Permintaan Symfony https://github.com/symfony/symfony/blob/1bd125ec4a01220878b3dbc3ec3156b073996af9/src/Symfony/Component/HttpFoundation/Request.php
sumber
Saya terkejut tidak ada yang menyebutkan filter_input, jadi inilah jawaban Alix Axel yang diringkas menjadi satu baris:
sumber
Anda cukup banyak menjawab pertanyaan Anda sendiri! :)
Sumber
sumber
sumber