Dva dotazy k CD-collection

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
warp
Člen | 26
+
0
-

snazim se predelat prihlasovaci script z CD-collection do sveho projektu a zatim v podstate uspesne, jen by me zajimaly dva detaily:

1/ jaka komponenta se stara o vypisovani chyby (spatne zadane heslo, spatne zadane jmeno) primo na stranku. AuthPresenter a template Auth/default.phtml jsem skopiroval beze zmeny a chyby mi to stale vypisuje do Ladicky :/

2/ jake kodovani pouziva Nette password, nebo spis dibi. Zkousel jsem klasicke kodovani z html formularu i plain text a ani jedno mi to nevzalo. A pripadne jestli je tu nekde skript pro registraci a tim padem i kodovani hesla rovnou do databaze :)

warp
Člen | 26
+
0
-

tak ten prvni problem se mi uz podarilo vyresit, ale s tim kodovanim furt tapu, heslo pri registraci zapisuju do databaze pomoci tohodle kodu:

$heslo = hash('sha256', $form['password']->getValue());

a kdyz ho pak chci vytahnout zpatky pres klasickej password formular

$form->addPassword('password', 'Heslo:')

tak mi nahlasi spatne heslo :-/

redhead
Člen | 1313
+
0
-

No a porovnáváš zadaný heslo (a zahashovaný!!) s tím co je v databázi?

To co uživatel zadá, to taky dostaneš. Abys ho mohl porovnat s heslem (hashem) v db, tak ho musíš nejdřív zahashovat a pak porovnat.

Editoval redhead (17. 11. 2010 21:50)

warp
Člen | 26
+
0
-

puvodne jsem tam mel toto:

$user->login($form['username']->getValue(), $form['password']->getValue());

nahradil jsem to timto:

$pass = (hash('sha256',$form['password']->getValue()));
$user->login($form['username']->getValue(), $pass);

a hlasi to invalid password v obou pripadech

redhead
Člen | 1313
+
0
-

Tady by to hashování nemělo co dělat. Podívej se do implementace třídy UserModel ve složce models, jsem si jist, že tam je problém.

Editoval redhead (17. 11. 2010 22:51)

warp
Člen | 26
+
0
-

Tridu UserModel nemam, ale kdyz zkousel jsem ten formular prochazet s prilozenym souborem demo.db a s tim to fungovalo, takze bude podle me opravdu problem nekde v tom kodovani.

westrem
Člen | 398
+
0
-

Co chcel redhead povedat je, aby si sa podival do triedy, ktora sa ti stara o autentifikaciu, tam bude nejspis problem, pretoze sa tam nieco blbo porovnava, nehashuje alebo hashuje dvojnasobne ..

S kodovanim by nemal byt problem.

warp
Člen | 26
+
0
-

Mam model Users, ale nejak sem tam vubec nenasel propojeni s tim AuthPresenterem, tak sem dam vsechen kod, kterej se tyka prihlasovani a registrace a budu doufat, ze nekdo bude ochotnej se na to mrknout :)

BasePresenter (jedine co se tyka prihlasovani)

$this->getSession()->start();
$user = $this->getUser();
$this->template->user = $user->isLoggedIn() ? $user->getIdentity() : NULL;

AuthPresenter

class AuthPresenter extends BasePresenter
{

	public $backlink = '';

	protected function createComponentLoginForm()
	{
		$form = new NAppForm;
		$form->addGroup('Přihlašovací formulář');
		$form->addText('username', 'Jméno:')
			->addRule(NForm::FILLED, 'Nezadal jste jméno.');

		$form->addPassword('password', 'Heslo:')
			->addRule(NForm::FILLED, 'Nezadal jste heslo.');

		$form->addSubmit('login', 'Přihlásit');

		$form->addProtection('Please submit this form again (security token has expired).');

		$form->onSubmit[] = callback($this, 'loginFormSubmitted');
		return $form;
	}

	public function loginFormSubmitted($form)
	{
		try {
			$user = $this->getUser();
			$user->login($form['username']->getValue(), $form['password']->getValue());
			$this->getApplication()->restoreRequest($this->backlink);
			$this->redirect('Login:');

		} catch (NAuthenticationException $e) {
      $form->addError($e->getMessage());
		}
	}

}

model Users

class Users extends NObject implements IAuthenticator
{
	public function authenticate(array $credentials)
	{
		$username = strtolower($credentials[self::USERNAME]);
		$password = strtolower($credentials[self::PASSWORD]);

		$row = dibi::select('*')->from('uzivatel')->where('Login=%s', $username)->fetch();

		if (!$row) {
			throw new NAuthenticationException("User '$username' not found.", self::IDENTITY_NOT_FOUND);
		}

		if ($row->password !== $password) {
			throw new NAuthenticationException("Invalid password.", self::INVALID_CREDENTIAL);
		}

		unset($row->password);
		return new NIdentity($row->username, NULL, $row);
	}

}

a ted ta cast, ktera se tyka registrovani: RegisterPresenter

class RegisterPresenter extends BasePresenter
{

protected function createComponentFormPassword() {
  $form = new NAppForm;
  $form->addGroup('Založení nového uživatele');
  $form->addText('username', 'Jméno:')
       ->addRule(NForm::FILLED, 'Zadejte jméno.');

  $form->addPassword('password', 'Heslo:')
       ->addRule(NForm::FILLED, 'Zadejte heslo');

  $form->addPassword('password2', 'Heslo (ověření):')
        ->addRule(NForm::FILLED, 'Zadejte nové heslo ještě jednou, pro kontrolu.')
        ->addRule(NForm::EQUAL, 'Zadané hesla se neshodují', $form['password']);

  $form->addSubmit('submitted', 'Odeslat');
  $form->onSubmit[] = array($this, 'formPasswordSubmitted');

  return $form;
}

public function formPasswordSubmitted($form) {

    $jmeno = $form['username']->getValue();
    $heslo = hash('sha256', $form['password']->getValue());
    return dibi::query("INSERT INTO [uzivatel] (Login, Heslo, Prava) VALUES ('$jmeno', '$heslo', 0)");
}

}

ale jak rikam, kdyz jsem tam zkusil jako vychozi databazi nastavit ten prilozenej soubor demo.db tak vsechny tyhle procedury probehly uspesne, takze musi byt chyba v hashovani toho hesla v RegisterPresenteru.

Editoval warp (18. 11. 2010 10:39)

westrem
Člen | 398
+
0
-

V modeli Users mas mat namiesto tohto:

if ($row->password !== $password) {

toto:

if ($row->password !== hash('sha256', $password)) {
Lopata
Člen | 139
+
0
-

Při registraci ukládáš do db hash hesla a při loginu s tím hashem porovnáváš normální heslo, co ti user napsal. Takhle to tedy bude fungovat jen pokud ti uživatel napíše hash vlastního hesla.

Databázové operace nedělej v presenteru. Ty volání strtolower jsou podle mě kontraproduktivní. Při registraci neověřuješ, jestli uživatel se zadaným username již neexistuje.

EDIT: too late

Editoval Lopata (18. 11. 2010 11:33)

warp
Člen | 26
+
0
-

Bohuzel to stale nefunguje. Zkousel jsem do toho formulare hodit i zahashovane heslo (ctrl c z db) a neproslo to. Podle me ten password label ma nejaky svuj hash kod, ktery neodpovida tomu sha256.

Navic, kdyz sem nahradil kod podle rady, tak se mi ani ze souboru demo.db prihlasit neslo.

Podle vasi teorie by v pripade ze bych ten hash vypustil ve vsech krocich (register i autheticate), tak by to fungovalo a tak to neni.

A o bezpecnost (dat SQL mimo presenter) se muzu starat az mi bude fungovat tenhle zaklad. To same s kontrolou jmen jiz existujicich uzivatelu.

//jeste by mohla byt nejaka zrada v config.ini protoze ten menim pro pristup k souboru / do databaze, ale mam defaultni nastaveni, takze o tom pochybuju

Editoval warp (18. 11. 2010 13:28)

Ani
Člen | 226
+
0
-

Si ty hodnoty před tim porovnáním vypiš, ať vidíš proč ta kontrola neprojde.

pekelnik
Člen | 462
+
0
-

Kristepane!!!

blábol za blábolem – nechápu jak na to někdo může mít nervy… jenom slovo „kódování“ je tazatelem užíváno asi v deseti významech…

  • …ake kodovani pouziva Nette password… co to je?
  • …klasicke kodovani z html formularu… ano, ano ;)
  • …ale s tim kodovanim furt tapu… já taky ;)
  • …problem nekde v tom kodovani… zajisté ;)
  • …s kodovanim by nemal byt problem… to ne no ;)

„Bohuzel to stale nefunguje.“

Není se čemu divit!

Když tazatel místo aby se zamyslel a třeba si nakreslil na papír co se vlastně v tom programu děje, neustále klade přiblbé dotazy typu: „Zkopírovaný kód nefunguje. Nevíte co je tam za kódování?“

Víme: UTF-8 :D

No a na závěr bych snad jen doporučil používat více funkci Debug::barDump(), která přehledně v jakémkoli místě programu vypíše proměné do debug baru… Dvě proměnné se tak porovnají neporovnatelně lépe než dotazem do fóra ;)

Editoval pekelnik (18. 11. 2010 14:28)

warp
Člen | 26
+
0
-

uz sem nasel kde je zakopanej pes, ale je to tak trapny, ze to snad ani radsi vedet nechcete :D

Pekelnik: tobe se zrejme nikdy nestalo, ze si hledal chybu v programu a pak si ji po nekolikahodinovem hledani nasel v preklepu. dej si nohy do tepla a bude dobre ;)

vsem ostatnim dik za rady, diky takovemu feedbacku je pro me mnohem lehci pochopit Nette jako takovy ;)

Editoval warp (18. 11. 2010 14:37)

pekelnik
Člen | 462
+
0
-

@warp: kde teda byl problém?

Ped
Člen | 64
+
0
-

tipuji ze bud nemel v DB dostatecne dlouhy string a se mu to osekalo, nebo mel preklep v nazvu hash funkce a pouzival 2 ruzne.

warp: jeste by bylo dobre pridat ke heslu pred hashovanim „salt“, jinak kdokoli kdo ma predpripravene rainbow tables pro sha256 ti vytaha hesla z te DB po jejim ukradeni lusknutim prstu. Kdyz delas salt, tak by musel ukradnout DB + zdrojak aby vubec salt znal, a i se znalosti saltu jsou mu rainbow tables myslim naprd pokud se nemylim. Bez znalosti saltu jsou mu na prd urcite.

T.j.
$hash = sha256( 'Ped dava salt i pred'.$user_password.'a i po.. a delsi' );

warp
Člen | 26
+
0
-

pekelnik napsal(a):

@warp: kde teda byl problém?

preklep v nazvu radku databaze v modelu Users :-/

jansfabik
Člen | 193
+
0
-

btw. databáze nemá řádky – ten překlep byl v názvu sloupce tabulky

warp
Člen | 26
+
0
-

jansfabik napsal(a):

btw. databáze nemá řádky – ten překlep byl v názvu sloupce tabulky

databaze je tabulka, takze ma radky i sloupce, ale melo tam bejt sloupce no ;)

Lopata
Člen | 139
+
0
-

Jak jako „databáze je tabulka“?!?

Je dům snad cihla…?

warp
Člen | 26
+
0
-

achjo :( v databazi sou tabulky :(

Lopata
Člen | 139
+
0
-

Ja vím. ;-) Ikdyž nemusí být nutně. Do toho ale zabíhat nebudeme.

Ped
Člen | 64
+
0
-

uz sme si zabehali tak jako tak docela dost… :)
Ale tak trochu joggingu neuskodi… :D

Ale kdyz uz sme u te validace hesel .. kdo to ma udelane poradne vcetne JS hashovani na client strane + challenge-response ochrany, tak aby to bylo odolne i proti odposlouchavani pres http:// ?
Ja delam jenom server-side salt+hash, aby ukradena DB byla k nicemu, na klient-side jsem jeste nemel cas se podivat. Treba jednou…

jansfabik
Člen | 193
+
0
-

Doporučuju nastudovat si HMAC, je tam i vzorové řešení pro Javascript a odkaz na PHP funkci hash_hmac. Při odeslání formuláře vezmeš heslo z políčka formuláře, pomocí klíče ho zahashuješ a uložíš do hidden pole. Potom smažeš původní heslo v textovém poli. Je to asi nejbezpečnější varianta, když nemáš k dispozici SSL, protože při každé relaci je klíč jiný, takže pokud útočník odposlechne hash hesla, nemá šanci se s ním ani přihlásit.