Jump to content
php.lv forumi

Lietotāju autentificēšana


Aleksejs

Recommended Posts

Pirms dažām dienām solīju parādīt kā izskatās lietotāju autentifikācija, kas nebalstās uz sesijas mainīgo izmantošanas un kas izmanto "Hardened stateless cookies".

 

Tad nu te ir tas, kas sanācis. Uzreiz brīdinu, ka pārāk briesmīgi ar komentēšanu neesmu aizrāvies, tādēļ ja ir jautājumi pēc būtības par tiem vai citiem izvēlētajiem risinājumiem, centīšos uz tiem pēc iespējas atbildēt. Vēl jāpiebilst, ka kaut arī sapņoju kādreiz nopietni pieķerties OOP, tomēr arī šoreiz kods ir rakstīts procedurāli, tādēļ OOP aizstāvji nesitiet mani. ;)

 

Vispirms sākam ar datubāzes uzbūvi. Esmu pieņēmis, ka lietotāju dati glabājas datu bāzē users: sqls, kas izveido datubāzi un pievieno lietotāju "labietis", kuram uzstāda paroli "parole". (iekš paste.php.lv neielikās):

CREATE DATABASE IF NOT EXISTS `WebApp`;

CREATE TABLE IF NOT EXISTS `users` (

`id` int(11) NOT NULL auto_increment,

`username` varchar(20) NOT NULL,

`password` char(128) NOT NULL,

`salt` char(128) NOT NULL,

PRIMARY KEY (`id`),

KEY `username` (`username`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `users` (`username`,`password`,`salt`) VALUES

( 'labietis',

'2fe0be79380e195da158a7919bca7c74a262d71a51d96f89b3ce073bedb03048de33c6417c9b

0372532724402d09880fad4e60436ba53be035e1479a9718d2d0',

'008f5d0a8d12f7bfec2596d2b248a37745077df60ac29d930c0c3595c6c706519ca7813c2d74

46e0084e6fdd7d028d9927fab1733b75ee722974ebff58f0b6bf');

 

Tālāk pārejam pie funkcijām:

fails auth_common.php satur funkcijas un mainīgos, kas nepieciešami autentifikācijas pārbaudei;

fails auth_logon.php satur funkcijas kas apstrādā nehashotas paroles, un kas dabū no lietotājvārda lietotāja ID;

fails auth_user_management.php satur funkcijas, kas ļauj izveidot jaunus lietotājus, nomainīt paroli norādot/nenorādot veco paroli kādam no lietotāja ID, kā arī palīgfunkcijas.

 

Tālāk seko piemēri šo funkciju izmantošanā:

login lapa: logon.php;

autentifikācijas pārbaudes lapa autentifikators.php, kuru paredzēts ar require_once() izsaukt katras aizsargājamās lapas sākumā - kā piemēram te: index.php;

logoff lapa: logoff.php būtībā izdzēš autentificēšanas cookie;

Administratora lapa user_mod.php lietotāju paroļu (arī savas!!! un tad būs jāielogojas ar jauno paroli, lai turpinātu darbu) nomaiņai.

Administratora lapa jauna lietotāja pievienošanai user_add.php demonstrē funkcijas admin_create_user() izmantošanu.

Lietotāja lapa savas paroles nomaiņai change_pass.php

 

Cerams, ka kodā kļūdu nav un, nevajadzētu arī darboties SQL injekcijām. Šīs autentifikācijas metodes plusi:

Uz servera nav jāglabā sesijas dati (tam ir paredzēts $user_data[5]), līdz ar to var vienkāršāk veidot klāsterus (jo savā starpā nav jāsinhronizē sesijas dati).

Cookiju var izmantot tikai no tās pašas IP adreses.

Paroles maiņa nākošās darbības veikšanas reizē liek pārlogoties pilnīgi visiem konkrētā lietotāja aktīvajiem pieslēgumiem.

Dati cookijā glabājas lietotājam nepieejamā veidā un ir aizsargāti pret manipulāciju.

Mīnusi:

Nav nojausmas par to cik reizes konkrētais lietotājs ir pieslēdzies.

 

Kas būtu vēl darāms:

Jāizveido stored procedures/funkcijas, kurām vienīgajām ir piekļuve laukiem salt/password - visiem pārējiem web-aplikācijā izmantotajiem sql lietotājiem liegt pieeju šiem laukiem un tikai īpašiem autentifikācijas lietotājiem ļaut darbināt stored procedūras.

Edited by Aleksejs
Link to comment
Share on other sites

Vai šis būtu vienīgais lielais iemesls, lai nelietotu sesijas?

...Uz servera nav jāglabā sesijas dati (tam ir paredzēts $user_data[5]), līdz ar to var vienkāršāk veidot klāsterus (jo savā starpā nav jāsinhronizē sesijas dati)...
Link to comment
Share on other sites

Nē, nav vienīgais.

Vēl daži argumenti no manis daudzinātā "Hardened stateless session cookies"[1][2]:

...

Also, unless users explicitly log

out, the server state associated with a session must be retained until the session

times out. This means that the space required on the server for maintaining state

can grow much faster than the number of users. This also introduces a denial

of service vulnerability, in that attackers could create many sessions and fill up

the filesystem.

...

...

Even though it

is likely that many users will select poor passwords, the inclusion of a large salt

prevents operation (3) being enough to brute-force the password. This property

is desirable because rate-limiting, to resist online brute-force attacks, need only

be applied to the login procedure (2), not every page that requires authentica-

tion. This could be particularly valuable in load-balanced situations with one

login server and multiple application servers – only the login server need retain

state on the number of failed login attempts.

...

...

If the attacker is able to read the database, e.g. through unsecured backups

or SQL injection, it can discover a user’s authenticator, salt and global MAC

key. This is still insufficient to generate a valid cookie, as doing so would be

equivalent to discovering the pre-image of a hash output.

Būtībā, nav problēma arī šo sistēmu papildināt ar sesijām raksturīgajām lietām - šīs pašas funkcijas sakombinējot ar:

http://lv.php.net/manual/en/function.sessi...ave-handler.php

iegūstam apvienojumu no abiem - iespēju darboties ar $_SESSION mainīgajiem un šīs shēmas plusus.

Pie kam, ja pareizi izveidojam, tad iegūstam, ka jaunu sesiju (PHP izpratnē) izveidot var tikai autentificēts lietotājs, kas neļauj notikt ar pirmo pieminēto citātu saistītajām resursu pārpildīšanās problēmām.

Link to comment
Share on other sites

IMHO pārāk bloatēts kods.

Vismaz tie nestotie if-i kaut kā neizskatās smuki (proti uzskatu ka statusu var/vajag returnot tikai vienreiz). Bez tam nav pārdomāts arī pašas statusu vērtības - proti:

 

return 7; //viss OK <- nozīmē ka es nekad nevarēšu izpildīt if(user_change_pw(..)) .. jo ir arī šāds 'return 4; //nav izdevies piesaistīt mainīgos' kas nozīmē == 7 .. kas nozīmē ka ja uzrodas jauns statuss tad vai nu viss jābīda uz leju vai arī sanāks ka 7 ir OK bet 8 vairs nav OK :)

 

 

Smukumam prasītos ja jau izmantojam "state of the art" mysqly nu tad izmantojam funkcijas/procedūras nevis kadreiz prepārojam vienu un to pašu kveriju :)

 

Bez tam (varbūt esmu neuzmanīgs) nemaniju nekādu datu kompresiju - problēma ir tāda ka klientam cookijs jāsūta uz katru requestu. It īpaši ja vēl, piemēram, statiskajam kontentam nav savs domēns tad visi cookija dati gāžas arī uz citiem elementiem kas atrodas piemēram zem domain.lv/img/ .... kas galā var rezultēties un diezgan lielu augšupejošu trafiku.

 

Trešā lieta - pie mums varbūt mazāk, bet lielākoties visur pasaulē vispār atsakās no statiskas IP izmantošanas autorizācijai. To protams pielogo utt, bet tas nav kritērijs pārbaudei (var patestēt google / facebook utt). Tas saistīts ar to ka kaut kādam procentam no lietotājiem ir mainīgas IP (slavens un tā iesācējs ir AOL) .. (korporatīvie proxy, roamings utt utt).

 

 

.. tās tādas pārdomas.

Link to comment
Share on other sites

Nu jā, par koda estētiskumu galīgi nestrīdos - šis jau tikai tāds koncepts, lai paskatītos, kā/vai vispār darbojas. Par statusu returnošanu arī taisnība, pašlaik ir ideja pārtaisīt, ka funkcijas atgriež true/false un attiecīgās vērtības, lai piešķir padotajiem parametriem + vēl kā parametru padot $error_log masīvu, kuram tad kabināt visuas excepcijas, lai beigās varētu korekti sažurnalēt/atgriezt kļūdas paziņojumu.

 

Pie mysql storēto funkciju/procedūru izmantošanas tieši šobrīd darbojos. :)

 

Par kompresiju arī - vakar sāku pētīt, ko var darīt lietas labā, principā jau nekas īpaši vairāk nav - 1 rindiņa gzcompress($data) un viss... Vienkārši atkal sakarā ar to, ka tas bija tikai koncepts, neko īpaši vairāk neveidoju. Kādu kompresijas metodi ieteiktu?

 

Par IP adreses izmantošanu/neizmantošanu arī esmu daudz domājis... Faktiski ar atgriesto statusu jau redz, vai ir mainījusies tikai adrese 6 vai arī nekas nav mainījies 7... Līdz ar to, pēc vajadzības var IP adreses pārbaudi neņemt vērā.

Link to comment
Share on other sites

...Uz servera nav jāglabā sesijas dati (tam ir paredzēts $user_data[5]), līdz ar to var vienkāršāk veidot klāsterus (jo savā starpā nav jāsinhronizē sesijas dati)...

 

Manuprāt labāk ir izmantot DB priekš sesiju glabāšanas. Tas arī daudz efektīvākā veidā vienkāršo klāsterēšanu.

 

Un smuks kods, lai to izdarītu:

 

http://lv2.php.net/manual/en/function.sess...ndler.php#81761

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...