• Rezultati Niso Bili Najdeni

4.4 Razvoj sistema registracije in prijave

4.4.1 Registracija brez Facebooka

Najprej si poglejmo postopek klasiˇcne registracije. Na sliki 4.10 je prikazan obrazec za klasiˇcno registracijo brez uporabe Facebook raˇcuna uporabnika.

Od uporabnika zahtevamo vnos veljavnega enoliˇcnega naslova spletne poˇste, enoliˇcnega uporabniˇskega imena, dvakratni vnos gesla in zaˇsˇcito pred smeten-jem s tehniko CAPTCHA.

Slika 4.10: Klasiˇcen vmesnik za registracijo novih uporabnikov.

Pri poljih uporabniˇsko ime in spletna poˇsta uporabljamo tehnike AJAX, za preverjanje enoliˇcnosti vnosov ter tako uporabnika opozorimo na ˇze uporab-ljene vrednosti ˇse pred konˇcno oddajo obrazca. Koda za preverjanje enoliˇcnosti je hitra, preprosta, varna in razˇsirljiva na preverjanje razliˇcnih vrednosti polj iz tabele uporabnikov.

1 @require("ajax_header.php") ; 2 try {

3 if("email" == $_POST['type'] ) {

4 $field = "user_email"; $q = $_POST['user_email'] ;

5 }

6 else if("username" == $_POST['type'] ) { 7 $field = "user_username";

8 $q = $_POST['user_username'] ;

9 }

10 . . .

11 $sql = "SELECT COUNT(userID) FROM " . DB_USERS_TABLE . "

12 WHERE {$field} = {$db->qstr($q)}";

13 $res = $db−>Execute($sql) ;

Izpis 4.4: Preverjanje vnosov z uporabo tehnik AJAX.

Izvajanje programa v izpisu 4.4 zaˇcnemo z vkljuˇcitvijo datotekeajax header-.php, skupne vsem programom PHP, ki jih uporabljamo v navezi s tehniko AJAX. V datotekiajax header.phpizvedemo vse pogoste in potrebne vkljuˇcitve datotek, kot so datoteka s konstantami, datoteka z nastavitvami in nekatere da-toteke z razredi. Vzpostavimo tudi povezavo s SUPB-jem, uporabniˇsko sejo in varnostno shemo. Ker je dobro vodilo pri varnosti spletnih aplikacij nezaupanje vsem uporabniˇskim vnosom, vrednosti poljafieldnastavimo eksplicitno med izvajanjem programa na poznane vrednosti. Prav tako za preverjanje obstoja vrednosti iskanega niza uporabljamo metodo qstr() razreda ADOConnec-tion, ki zagotavlja ustrezno filtriranje pred napadi z vrivanjem. S klicem me-todeExecute() izvedemo poizvedbo SQL in v naslednjih korakih preprosto preverimo koliˇcino zadetkov. Program kot rezultat izpiˇse vrednosti v notaciji JSON, kar priˇcakujemo pri izvajanju JavaScripta v uporabnikovem brskalniku.

Za kodiranje v notacijo JSON uporabljamo PHP funkcijojson encode().

Ce je obrazec pravilno izpolnjen in Facebook potrdi pravilno reˇsitev iz-ˇ ziva CAPTCHA, potem nadaljujemo z obravnavno registracije na streˇzniku v programu user register.php. Podatke za registracijo prejmemo v obliki podpisane zahteve (angl. signed request) preko vmesnika za registracijo s Fa-cebookom. Z uporabo naˇse knjiˇznice za delo s Facebookom, skrivnim in javnim nizom za Facebook aplikacijo iz podpisane zahteve razberemo vsebino. Upo-raba metode parseSignedRequestje prikazana v izpisu 4.5

1 $fb = new FBInterface($_CONFIG['fb'] ['appID'] , $_CONFIG['fb'] 2 ['app_secret'] , "", $_CONFIG['fb'] ['permissions'] , 3 "", $_CONFIG['salt'] ) ;

4

5 if(null == $response = $fb−>parseSignedRequest($_POST['signed_request'] ) ) 6 {

7 throw new Exception("Malformed facebook input.",

8 USER_REG_TRANSACTION_ERROR) ;

9 }

Izpis 4.5: Uporaba metode parseSignedRequest za obdelavo podatkov prejetih s strani Facebooka.

4.4 Razvoj sistema registracije in prijave 49

Nato z uporabo razreda za preverjanje veljavnosti obrazcev preverimo vel-javnost podatkov, ki jih je vnesel uporabnik. Razred za preverjanje veljav-nosti obrazcev formValidator uporabimo tako, da konstruktorju podamo polje objektovvalidatorItem, ki predstavljajo polja obrazca. Prva dva ar-gumenta konstruktorja objekta validatorItem skrbita za preslikavo imen spremenljivk v obrazcu v ustrezna polja v podatkovni bazi. ˇCe je tretji ar-gument postavljen na logiˇcni res, potem je to polje obvezno, sicer pa ne.

Ostali argumenti niso obvezni, z njimi pa lahko doloˇcimo ˇse naprimer podat-kovno vrsto polja in privzete vrednosti. V izpisu 4.6 najprej izdelamo objekt formValidatorin ga napolnimo z ustreznimi elementi, nato pa uporabimo metodo validateInput, ki kot argument sprejme polje uporabniˇskih vno-sov.

1 // Verify registration data 2 $fv = new formValidator(array(

3 new validatorItem("name", "user_displayName", false) , 4 new validatorItem("email", "user_email", true) , 5 new validatorItem("username", "user_username", true) , 6 new validatorItem("password", "user_password", true) 7 ) ) ;

8 if( !$fv−>validateInput($response['registration'] ) ) { 9 throw new Exception("Missing required input.",

-USER_REG_TRANSACTION_ERROR) ; 10 }

Izpis 4.6: Preverjanje veljavnosti uporabniˇskih vnosov z razredom formValidator.

Ce so vneˇseni podatki v ustreznem formatu in vsa zahtevana polja ustreznoˇ izpolnjena, potem ˇse enkrat preverimo enoliˇcnost uporabniˇskega imena in e-poˇstnega naslova s poizvedbo SQL, saj preverjanje v brskalniku s tehnikami AJAX ni zagotovilo za ustreznost podatkov, ker lahko napadalec na primer enostavno onemogoˇci izvajanje JavaScripta. V naslednjem koraku zaˇsifriramo uporabnikovo geslo z uporabo statiˇcne metode encodePassword razreda User:

1 $encodedPass = User: :encodePassword($response['registration'] ['password'← -] , $_CONFIG['salt'] ) ;

2 $fv−>items['password']−>setValue($encodedPass) ;

Sledi vnos novega uporabnika v sistem, generacija kode za aktiviranje raˇcuna in zapis te kode v tabelo za aktiviranje uporabnikov userActivate.

Ker zahtevamo, da se izvedeta obe operaciji vnosov v podatkovno bazo ali nobena, uporabimo transakcije. V izpisu 4.7 za vnos novega uporabnika proi-zvedemo ustrezen stavek SQL z uporabo metodegetInsertSQL() razreda formValidator, ki glede na prej podana polja proizvede ˇcist in ustrezen

stavek SQL.

1 $db−>StartTrans( ) ;

2 // Insert new user

3 $db−>Execute($fv−>getInsertSQL($db, DB_USERS_TABLE) ) ;

4

5 // Generate activation code

6 $code = sha1(mt_rand( 1 0 0 0 0 , 9 9 9 9 9 9 ) .time( ) . $_CONFIG['salt'] . 7 $response['registration'] ['email'] ) ;

8

9 $sql = "INSERT INTO " . DB_USER_ACTIVATE . "

10 (ua_userID , ua_timeSent , ua_code, ua_clientIP)

11 VALUES (LAST_INSERT_ID(), now(),

12 '{$code}', '" . getClientIP( ) . "')"; 13

14 $db−>Execute($sql) ;

15

16 // Complete transaction or rollback

17 if($db−>HasFailedTrans( ) ) {

18 $transFail = true; 19 }

20 $db−>CompleteTrans( ) ;

Izpis 4.7: Transakcija za aktiviranje novega uporabniˇskega raˇcuna.

Po uspeˇsnem vnosu v podatkovno bazo uporabniku poˇsljemo potrditveno e-poˇsto z uporabo metode mailUserActivationrazreda User, prikazano v izpisu 4.8. Metoda mailUserActivation pripravi ustrezno besedilo in naslovnika ter poˇsiljanje poˇste prepusti metodisendAsyncEmail. Z metodo sendAsyncEmailz uporabo PHP funkcijcurl poˇsljemo asinhrono zahtevo za poˇsiljanje poˇste programuasync mailer.php, ki izvede poˇsiljanje poˇste z uporabo knjiˇznice PHPMailer. Asinhrono poˇsiljanje doseˇzemo z nastavitvijo nizke vrednosti za parameterCURLOPT TIMEOUT MSfunkcijecurl setopt, kot je prikazano v izpisu 4.8. Takˇsen preprost asinhron sistem poˇsiljanja je na-domestek za bolj kompleksen sistem poˇsiljanja poˇste z uporabo vrst, vendar obˇcutno pohitri obravnavanje postopka registracije v uporabnikovem brskal-niku, saj uporabniku izpiˇsemo odgovor, ˇse preden se izvede poˇsiljanja poˇste.

1 // Send activation code via email 2 /* ... */

3 $user: :mailUserActivation($response['registration'] ['email'] , $code) ) 4 /* ... */

5 return User: :sendAsyncEmail($sendTo, $subject, $body) ; 6 /* ... */

7 $ch = curl_init( ) ; 8 /* ... */

9 curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1 0 0 ) ; 10 $response = curl_exec($ch)

Izpis 4.8: Nekaj izsekov kode za poˇsiljanje e-poˇste.

4.4 Razvoj sistema registracije in prijave 51

Ce je med obravnavo registracije priˇslo do napake ali izjeme, uporabnika oˇ tem obvestimo z lokaliziranimi sporoˇcili:

1 catch (Exception $e) {

2 $smarty−>assign("FORM_ERROR_TRIGGERED", true) ; 3 $smarty−>assign("FORM_REGISTER_MSG",

4 $page−>localization−>localize("reg_error_msg_code_" .

5 $e−>getCode( ) , "ucp") ) ;

6 }

Uporabnik nato prebere e-poˇsto, ki mu jo sistem poˇslje v obliki HTML.

Potrditvena poˇsta vsebuje zahvalo, neposredno povezavo za aktiviranje raˇcuna z uporabo parametra code v obliki GET spremenljivke in kot alternativno moˇznost ˇse povezavo do strani za aktiviranje raˇcuna z ustrezno ˇsifro.

Ce uporabnik poˇste ni prejel, jo je izgubil ali pa je priˇslo do kakˇsne napakeˇ pri primerjavi ˇsifer, uporabniku ponudimo tudi preprost vmesnik za poˇsiljanje nove ˇsifre za aktiviranje raˇcuna. Pri tem od uporabnika zahtevamo e-poˇstni naslov, ki ga je uporabil pri registraciji. Za zaˇsˇcito pred zlorabo je obrazec zaˇsˇciten s tehniko CAPTCHA, ob obravnavanju zahteve za izdajo nove ˇsifre na streˇzniku pa obravnavamo le zahteve za uporabniˇske raˇcune, ki imajo ustrezen vnos v tabeli za aktiviranje raˇcunov s kodo v izpisu 4.9.

1 // Check if account not activated

2 $sql = "SELECT userID FROM " . DB_USERS_TABLE .", " . DB_USER_ACTIVATE 3 . " WHERE

4 userID = ua_userID AND

5 user_email = {$db->qstr($_POST['email'])}"; 6

7 $res = $db−>Execute($sql) ;

8 if( !$res | | $res−>NumRows( ) < 1 ) {

9 throw new Exception("No account to activate with email.", 10 NO_ACCOUNT_ACTIVATION_FOUND) ;

11 }

Izpis 4.9: Preverjanje veljavnosti postopka za aktiviranje uporabniˇskega raˇcuna.

Uporabniki lahko torej svoj raˇcun aktivirajo s poˇsiljanjem parametracode v obliki GET zahteve, kot v primeru aktiviranja preko povezave v e-poˇsti, ali pa s poˇsiljanjem POST zahteve v primeru uporabe obrazca za aktiviranje raˇcuna.

V obeh primerih se pred zlorabo s poskuˇsanjem aktiviranja zaˇsˇcitimo z uporabo izziva CAPTCHA, ki ga prikaˇzemo glede na neuspelo ˇstevilo poskusov iz istega naslova IP. Implementacija zaˇsˇcite je prikazana v izpisu 4.10.

1 $recaptchaResponse = recaptcha_check_answer( 2 $_CONFIG['recaptcha'] ['privateKey'] ,

3 getClientIP( ) ,

4 $_POST["recaptcha_challenge_field"] ,

5 $_POST["recaptcha_response_field"] ) ; 6

7 if ( !$recaptchaResponse−>is_valid) {

8 $recaptchaError = $recaptchaResponse−>error;

9 throw new Exception("Captcha mismatch", USER_REG_CAPTCHA_MISMATCH) ; 10 }

Izpis 4.10: Zagotavljanje veljavnosti uporabniˇske zahteve s preverjanjem reˇsitve izziva CAPTCHA.

Ce se ˇsifra ujema s tisto shranjeno v tabeliˇ userActivate, lahko nadal-jujemo z aktiviranjem raˇcuna. Iz tabele userActivate odstranimo vnos za aktiviranje raˇcuna, nato pa uporabnika dodamo v skupino registriranih uporabnikov:

1 $sql = "INSERT INTO " . DB_GROUP_HAS_USER_TABLE . " (groupID, userID) -VALUES (" . GROUP_REGISTERED_USERS . ", {$userID})";

2 $db−>Execute($sql) ;

Proces zakljuˇcimo z obvestilom uporabniku in sproˇzimo odklepanje doseˇzka za aktiviranje raˇcuna:

1 $achievements−>triggerAchievement(ACH_ACCOUNT_ACTIVATED) ;

Na koncu uporabnika preusmerimo na vmesnik za prijavo v sistem.