Autor Zpráva
Iver
Profil
Zdravím. Mám takový problém. Pomocí funkce generuji hash kód. Mě na localhostu se vždy vytvoří pomocí funkce vždy správně, ale zákazníkovi se vytvoří při instalaci jeden hash a při přihlašování jiný. Má s tím někdo zkušenosti? Vypadá to, jako by jeho PHP server vždy k vygenerovanému hashi přidal nějaký svůj salt.
Jan Tvrdík
Profil
Iver:
Jak ten hash generuješ?
Iver
Profil
<?php

class Hash {
    
    function Hash($text,$salt) {
        $this->returned=hash('md5',$text.$salt);
        }
        
    }

?>



Při instalaci generuji náhodný salt a při přihlašování ho tahám z databáze.
Sir Tom
Profil
Iver:
Pečlivě zkontroluj parametry v metodě Hash při instalaci a při přihlašování. Nech si je vypsat např. pomocí echo, nebo alert(). Jsou stejné?
Iver
Profil
Jsou. Jak říkám. Na localhostu jsou hashe stejné, ale na hostingu bohužel ne. Kontroloval jsem i systém ukládání do tabulky. Dokonce i jestli to nedělá přímo zákazníkův prohlížeč.
Nox
Profil
Napiš prosimtě jak to testuješ a celý kód té funkce ... uvedený kód vybízí k otázce (::returned), jestli to není jen část, takže vlastně nevíme, jak to používáš.
Jestli jsou tam nějaké jiné procesy (jestli je to prostě složitější než dvě echa za sebou), tak tam může být nějaký vliv, co to mění
Iver
Profil
Takže při instalaci je kód pro vložení do databáze:
$connection=new MySQL($_POST['database_server_address'],$_POST['database_port_number'],$_POST['database_username'],$_POST['database_password']);
$mysql_query_array=array();
$salt=rand(0, 9999999999);
            $hashed_main_administrator_password=new Hash($_POST['administrator_password'],$salt);
            $mysql_query_array[]='INSERT INTO users VALUES ("","'.$_POST['administrator_name'].'","'.$hashed_main_administrator_password->returned.'","'.$salt.'","100","'.$_POST['administrator_e_mail'].'")';
$connection->mySQLQuery($mysql_query_array);

Při přihlašování pak:

$connection=new MySQL($GLOBALS['config']['database_server_address'],$GLOBALS['config']['database_port_number'],$GLOBALS['config']['database_username'],$GLOBALS['config']['database_password']);
        $permissions=$connection->mySQLReturn($GLOBALS['config']['database_name'],'SELECT permissions FROM users WHERE username="'.$_POST['administrator_username'].'"');
        $administration=$connection->mySQLReturn($GLOBALS['config']['database_name'],'SELECT administration FROM permissions WHERE level="'.$permissions[0][0].'"');
        
        if($administration[0][0]=='true') {
            $salt=$connection->mySQLReturn($GLOBALS['config']['database_name'],'SELECT salt FROM users WHERE username="'.$_POST['administrator_username'].'"');
            $hashed_password=$connection->mySQLReturn($GLOBALS['config']['database_name'],'SELECT password FROM users WHERE username="'.$_POST['administrator_username'].'"');
            $hash=new Hash($_POST['administrator_password'],$salt[0][0]);
if($hashed_password[0][0]==$hash->returned) {
                
                session_start();
                header("Cache-control: private");
                $_SESSION['is_signed']=true;
                header("Location: index.php?page=main");
                
                }

Instalace je na jedné stránce a přihlašování na druhé.
Nox
Profil
velmi pravděpodobně tam bude 123 != '123', takže jedno z toho přetypuj ... doporučuju to první na string, abys tam případně mohl v budoucnu dát i ne-čísla
Majkl578
Profil
Nox:
velmi pravděpodobně tam bude 123 != '123', takže jedno z toho přetypuj
PHP není silně typový jazyk, 123 a '123' je při kontrole rovnosti totéž ((123 == '123') === TRUE);
Iver
Profil
Ano. Potvrdil jsem si to výpisem pomocí is_numeric(). Nicméně problém trvá. Zkoušel jsem i na druhé stránce přejmenovat $salt na $salt_login, jestli se nemíchají, ale stále nic. Všiml jsem si že má klient vypnuto zobrazování chyb, tak na něj počkám a změníme to. Možná to právě tu chybu vypíše.
Tori
Profil
Iver:
Je jisté, že sloupce v obou databázích jsou ve stejném pořadí? (Jestli nedošlo k záměně salt a toho násl.sloupce, kam se vkládá "100".)
Je sloupec salt typu BIGINT (nebo textový typ pro alespoň 10 znaků) ?
Nepoužívá zákazník v hesle nějaké znaky, které by mohlo ovlivnit nastavení serveru (např. magic_quotes)?

dodatek nesouvisející s dotazem: Ta třída MySQL sama provádí escapování vstupů?


Iver:
Zásadní věc - zkontrolujte hodnotu konstanty PHP_INT_MAX. Na 32-bit systému se bude generovat jiné číslo než na 64-bit, protože 9999999999 je mimo rozsah 32-bit celých čísel a PHP s ním pracuje jako s desetinným. Funkce rand ale vyžaduje celé číslo, takže si ho nějak oseká (nezjišťovala jsem podrobně jak) bez upozornění přetypuje na celé číslo. Např. když dám generovat náh. číslo mezi 9.999.999.000 a 9.999.999.999, tak na 32-bit systému mi to vytvoří např. 1.410.064.965, což je očividně mimo požadovaný rozsah.
Iver
Profil
Díky Tori. Ještě než jsem si přečetl váš příspěvek, jsem zjistil, že je to opravdu tím. Změnil jsem to náhodné generování na $salt=(string)rand(0, 1000000000).
Joker
Profil
Iver:
Nechybí třeba na jedné ze stránek kódování?

Jinak podle mého názoru se na chybě, nebo minimálně na potížích s jejím odhalením, podílí i ten děsně komplikovaný návrh skriptu. Možná se to jen zdá z té malé ukázky, ale je to hodně nepravděpodobné.
Například:
- Třída Hash je podle všeho prakticky zbytečná. Kdyby to byla funkce/metoda, kde hash bude návratová hodnota, bude funkčnost stejná a bude o jednu úroveň zanoření a jeden zdroj potenciálních chyb méně.
- Třída MySQL je podle všeho taky jen obálka nad vestavěnými MySQL funkcemi, přičemž PHP objektové rozhraní k MySQL už má.
- Proč se na zjištění hodnot tří sloupců stejného záznamu dělají tři SQL dotazy?
- SQL injection. Teoreticky by to sice mohla zachránit třída MySQL, ale jelikož celý dotaz přebírá jako parametr, vsadím se, že prostě provede to co dostane. Takže když do přihlášení zadám jméno: ' OR password = MD5(CONCAT('heslo',salt)) a heslo heslo, přihlásí mě to pod účtem prvního uživatele, který má heslo heslo.
Kdybych ten dotaz ještě trochu poladil, šlo by dosáhnout toho, abych byl přihlášen pod uživatelem s nejvyššími právy, který má dané heslo.
Iver
Profil
Díky za rady. Třídu Hash upravím aby vracela přímo pomocí return. Jinak později ta třída může mít více funkcí. Takže jsem si ji jen takto připravil do budoucna. Do té třídy MySQL později přidám taktéž různé funkce a další parametry. Proto takto. Ty dotazy spojím do jednoho bude to opravdu lepší. A tu ochranu proti SQL injection přidám co nejdříve. Opravdu všem děkuji.
Tori
Profil
Doplňuji předchozí: „Funkce rand ale vyžaduje celé číslo, takže ho bez upozornění přetypuje na celé číslo.

Jediné upozornění rand vyhazuje, pokud některý ze vstupů je řetězec a zároveň neprojde testem is_numeric.
* Pokud je první argument vyšší než druhý, nic se neděje - rand(0, 10) funguje totožně jako rand(10, 0)
* Desetinná čísla, hexadecimální / exponencionální zápis jako řetězec, null i logické hodnoty se převedou na celé číslo stejně, jako bychom použili přetypování: (int) "1e3", (int) "0x10". Oktalový zápis jako řetězec se převádí na desítkové číslo vyhozením začáteční nuly: (int) 020 === 16, ale (int) "020" === 20

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0