Ukládání IP adresy

Školení, která pořádám

U některých záznamů se hodí ukládat IP adresu počítače, který je vytvořil – jsou to např. diskusní příspěvky, objednávky, záznamy o přihlášení do aplikace a další. Adresa se nikde nemusí zobrazovat, ale může se v budoucnu hodit např. pro ověření pravosti. IPv4 adresu lze uložit do čtyř bajtů, takže od lidí bez znalosti funkce ip2long jsem viděl rozličné pokusy tohoto převodu, např.:

<?php
$ip = 0;
foreach (explode(".", $_SERVER["REMOTE_ADDR"]) as $val) {
    $ip = 256*$ip + $val;
}
?>

Problém s tímto a podobnými převody nastává u IPv6 – ta už potřebuje 16 bajtů. Přechod na IPv6 navíc bývá postupný – hosting může podporovat obě rozhraní, většina lidí může přicházet přes IPv4, ale tu a tam někdo přes IPv6. Pokud tedy databáze nepodporuje speciální typ pro uložení IP adresy, doporučoval bych ji ukládat jako varchar(39), do které se vejdou oba typy a je čitelná i při běžném výpisu dat.

Někdy se vyplatí ukládat i doménové jméno adresy zjištěné funkcí gethostbyaddr. Jeho zjišťování při výpisu totiž může být poměrně časově náročné a navíc se v čase může měnit.

Pokud byl přístup k našim stránkám uskutečněn přes proxy, bude skutečná adresa počítače uložena v proměnné $_SERVER["HTTP_X_FORWARDED_FOR"] (což je seznam oddělený čárkami). Může se hodit ukládat i tuto adresu, ale rozhodně se nevyplatí na ni spoléhat (protože se dá snadno zfalšovat) ani ukládat jenom ji (protože může obsahovat adresu ve vnitřní síti, která je bez znalosti adresy proxy serveru bezcenná).

Jakub Vrána, Dobře míněné rady, 1.2.2006, diskuse: 15 (nové: 0)

Diskuse

Rick:

Nechápu v článku funkci explode. Já ukládám adresy normálně jako varchar a pak jen zjišťuji, zda se ve výpisu vyskytuje tečka. Pokud ano, je to IPV6

Spud:

explode rozsekne IPko podle tecek do pole o velikosti 4 a pak prepise do decimalniho tvaru:

<?php
$ip
= 256*0 + val[0];
$ip = 256*(256*0 + val[0]) + val[1];
$ip = 256*(256*(256*0 + val[0]) + val[1]) + val[2];
$ip = 256*(256*(256*(256*0 + val[0]) + val[1]) + val[2]) + val[3];
?>

ikona spaze:

"Někdy se vyplatí ukládat i doménové jméno adresy zjištěné funkcí gethostbyaddr. Jeho zjišťování při výpisu totiž může být poměrně časově náročné a navíc se v čase může měnit."

No jo, ale kdy jindy hostname zjišťovat, než při výpisu, když všechno je v podstatě fáze výpisu? :) Rada je jednoduchá, hostname neukládat rovnou, ale později projet všechny záznamy nezávisle na nějakém přístupu a doplnit hostnames.

BTW, doporučuje se nezapínat převod IP na hostname třeba na webových serverech, FTP serverech apod.

Darion:

Chtěl sem se zeptat má vůbec smysl ukládat si IP? Je tak výraznej počet uživatelů co ho maj neměný?

jahu:

co tak riesit to priamo na mysql serveri
INET_ATON/INET_NTOA

Ondrej Podolinsky:

Kde jste přišel na velikost IPv6 39 znaků? Ať hledám kde hledám, nemůžu se dohledat:-/

ikona Jakub Vrána OpenID:

IPv6 adresa má 128 bitů, které se obvykle zapisují hexadecimálně oddělené po čtveřicích dvojtečkou. To je 32 hexadecimálních číslic v osmi čtveřicích oddělených sedmi dvojtečkami, celkem 39 znaků.

Ondrej Podolinsky:

Tohle naštěstí ještě chápu, ale nepočítá se do toho ještě lomítko a číslo na konci?

ikona Jakub Vrána OpenID:

Lomítko a číslo na konci označuje síť, nikoliv jednotlivou adresu.

Ondrej Podolinsky:

Skvěle, děkuju za vysvětlení. O IPv6 jsem pár článků četl, ale tuto důležitou radu jsem našel až tady.

Lukas Kola:

Pokud se mi na web hodí trvalé přihlášení, je lepší kontrolovat i ip a prohlizec, aby si nekdo proste nemohl jen prekopirovat cookie k sobe(utocnik).
Problem je, jak ukladat adresu.Takhle(ip2long($_SERVER['REMOTE_ADDR'])) totiz nebude trvale prihlaseni fungovat pokud uzivatel nema pevnou adresu.Nebude taky fungovat, pokud jeho ISP je velky a ma tak vice proxyn pres ktere je posila, takze bude problem.
Existuje nejake reseni pro ipv4 i ipv6?
Chtel jsem ukladat takhle:  $celaIp=addslashes($_SERVER['REMOTE_ADDR']);
  self::$ip=substr($celaIp,0,strrpos($celaIp,'.',4));
ale fungovalo by to jen na ipv4.

Dragonn:

Já osobně při trvalém příhlášení ukládám k uživateli celkem 3 cookies. První je login, druhá hashované heslo tak, aby bylo možno ho nějak porovnat s databází (v databázi mám uložená hesla ve formátu sha1(sha1('heslo')) ), poslední cookies je pak hash ID uživatele + IP adresy + jednoho ze skupiny speciálních znaků (prostě jsem si vybral několik znaků z ascii tabulky a vždy vyberu jeden z těchto znaků), které označují aktivní trvalé přihlášení. Při odhlášení uživatele jenom změním hash hesla uloženou v cookies uživatele na nějakou náhodnou hodnotu a v tý kontrolní hash použiji na konci jiný znak.

Osobně si myslím, že je zabezepčení dostačující a útočník alespoň nemůže podle přítomnosti proměnných v cookies poznat, jestli jde o přihlášené, nebo nepřihlášené hodnoty. Navíc kontrola IP adresy zužuje počet možných útočníků.

Co si o tom myslíte?

ikona Jakub Vrána OpenID:

Je to odstrašující řešení. Cookie by neměla obsahovat login a už vůbec ne hash hesla, ale měl by to být náhodný řetězec, který na základě dat uložených na serveru identifikuje uživatele.

pirat:

Souhlasim s Jakubem. Tyto informace by se nikdy neměly uchovávat v Cookies uživatele, kde k nim má útočník snadnější přístup. Neměly by opustit bezpečí serveru

Sengir:

sha1(sha1($heslo))? Názorná ukázka toho, že do programování se dneska cpe každá lama bez znalosti jakýchkoli zásad programování, teorie algoritmů nebo alespoň základní vysokošklské matematiky. Takhle bezpečnost hashe snížíš ty lamo.

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.