22. januar 2003 - 15:51Der er
14 kommentarer og 2 løsninger
WWW-Authenticate med users fra database
lige nu bruger jeg følgende script til login-script til min admin-side, men jeg har brug for at det henter de(t) korrekt usernames/passwords fra en mysql database. hvordan kan den laves om til det, istedet for som mu kun at have ét korrekt username og password. ---connectdb.php starts here:--- <? if ((!isset( $PHP_AUTH_USER )) || (!isset($PHP_AUTH_PW))) { header( 'WWW-Authenticate: Basic realm="site administration"' ); header( 'HTTP/1.0 401 Unauthorized' ); echo 'Authorization Required.'; exit; } else {
I dette særtema ser vi på, hvordan cloud og AI bliver fundamentet for virksomhedernes digitale forretning, og hvordan de nye muligheder for automatisering og forretningsværdi kan udnyttes uden at miste overblik, sikkerhed og menneskelig kontrol.
1) Først sikrer du dig at den der logger ind ikke har lavet numre med brugernavnet: $user = addslashes($PHP_AUTH_USER); (Det er for at undgå at brugeren kan ødelægge din sql sætning der følger om lidt)
2) Så laver du først en søgning i databasen på brugernavnet { connect kode som du skriver den, men med $link = mysql_connect... } $qry = mysql_query('select username, password from usertabel where username = '.$user.', $link);
3) Så chekker du at du kun fandt een række vha. mysql_num_rows($qry);
4) Så henter du rækken vha. mysql_fetch_row();
5) Så sammenligner du det password du har fundet med det brugeren har indtastet.
Hvis noget ikke chekker ud ok undervejs afviser du brugeren.
Den besværlige fremgangsmåde er for at sikre at brugeren ikke kan fuske med passwordet. Hvis du nu havde slået op i databasen med "where username = '".$PHP_AUTH_USER."' and password = '".$PHP_AUTH_PASSWD."'" og brugeren har indtastet passwordet "' OR 1=1" så ville databasen returnere at den fandt noget og brugeren ville kunne logge på uden et korrekt password.
(Man kan chokeres over hvor mange sites der indeholder denne usikkerhed)
Hvis der er nogen af trinene du vil have uddybet, så bare sig til..
følgende kode omgår det samme problem på en lidt anden måde. til gengæld er det ikke så smart, hvis der er mange brugere i databasen (altså hvis du f.eks har flere hundrede) <? if ((!isset( $PHP_AUTH_USER )) || (!isset($PHP_AUTH_PW))) { header( 'WWW-Authenticate: Basic realm="site administration"' ); header( 'HTTP/1.0 401 Unauthorized' ); echo 'Authorization Required.'; exit; } else {
mysql_connect("localhost","adminusername","adminpassword"); mysql_select_db("site_dk_db"); // forudsætter en tabel "brugere" med to felter "brugernavn" og "password" $query = 'SELECT `brugernavn`,`password` FROM `brugere`'; $result = mysql_query($query) or die(mysql_error()); while ($row = mysql_fetch_array($result)) { if ($PHP_AUTH_USER==$row['brugernavn'] && $PHP_AUTH_PW==$row['password']) { ?> <? } else { header( 'WWW-Authenticate: Basic realm="site administration"' ); header( 'HTTP/1.0 401 Unauthorized' ); echo 'Authorization Required.'; exit; } } ?>
det ser meget interessant ud, men nogen speciel grund til at det ikke er så smart med flere hundrede brugere? (for realistisk set kunne min side meget vel gå hen of få flere hundrede brugere - måske endda tusinde.)
Ja. Problemet er at metoden henter ALLE brugere i databasen og chekker hver eneste af dem.
Det der er smart ved en database er netop at den hurtigt kan finde en bestemt post i databasen (altså en bestemt bruger). En metode der bruger en database vil kun blive lidt langsommere når antallet af brugere fordobles.
Den viste metode vil (ca. og i snit) blive ca. dobbelt så langsom med dobbelt antal brugere.
Men det er først et problem når man kommer rigtig højt op, for man kan løbe mange brugere igennem i sekundet.
Men hov, der er vist en lille bug: Den vil afvise alle brugere undtagen den første i databasen, fordi den afviser den første gang en funden bruger ikke matcher.
Giv mig lige et øjeblik så skal jeg sende et eksempel på den metode jeg beskrev længere oppe.
>Den viste metode vil (ca. og i snit) blive ca. dobbelt så langsom med dobbelt antal brugere.
deeeet er jo nok en grov overdrivelse, men jeg ville ikke bruge det med flere end 100 brugere. alternativt kunne man nøjes med at teste imod database første gang, og herefter gemme data i session. så gør det ikke så meget at det tager lidt tid. men du har da ret miraculix, det ville være mere korrekt at nøjes med at udtage den post man har brug for, det var bare lige noget kode jeg alligevel havde liggende ...
> Men hov, der er vist en lille bug ... nåja ... der skulle nok have stået noget a la
if ((!isset( $PHP_AUTH_USER )) || (!isset($PHP_AUTH_PW))) { afvis(); exit; } // følgende har kun effekt hvis brugeren har indtastet plinger (') el. lign i brugernavn: $user = addslashes($PHP_AUTH_USER);
// forudsætter en tabel "brugere" med to felter "brugernavn" og "password" // samt at brugernavne er unikke...
$query = "SELECT `brugernavn`,`password` FROM `brugere` where `brugernavn` = '".$user."'";
$result = mysql_query($query) or die(mysql_error());
if ( mysql_num_rows($result) != 1 ) { afvis(); exit(); }
if ($row = mysql_fetch_array($result) ) { if ($PHP_AUTH_USER==$row['brugernavn'] && $PHP_AUTH_PW==$row['password']) { ?> VELKOMMEN TIL MIN SIKRE SIDE <? } else { afvis(); exit; } } else { afvis(); exit; } ?>
swaxi: Kan du ikke lige forklare mig hvorfor det er en _grov_ overdrivelse? Det gælder naturligvis kun ved højt antal brugere (altså hvor gennemløbet af løkken bliver den dominerende faktor) Jeg har aldrig været en ørn til kompleksitetsberegning, men jeg synes da logisk at det må være rigtigt alligevel? No hard feelings, jeg er bare nysgerrig ;-)
jeg mente ikke noget særligt med ordet grov .. bare at det var lidt ... hm ... det er en stor overdrivelse. altså ... jeg mente ikke at _du_ var grov ... :)
det der tager længere tid ved denne metode er primært at flytte data mellem mysql og php, og siden det er to processer, der kører samtidig og vi måske taler om nogle få kilobytes, tager det nok ikke mange clockcycles. til gengæld tager det nok væsentligt længere tid at forbinde til databasen, starte processerne op etc. så derfor bliver slutresultatet nok ikke så forskelligt igen.
Der har du helt ret. Det var også derfor jeg skrev det med:
"Men det er først et problem når man kommer rigtig højt op, for man kan løbe mange brugere igennem i sekundet."
Men når du så kommer der op af så er den også lineær.
Jeg forstod godt det med at _grov_ gik på overdrivelsen og ikke på mig. No offence taken, jeg troede bare jeg havde regnet helt fuldstændigt galt.. ;-)
I øvrigt er databaseudgaven også lineær, hvis brugernavns-feltet ikke er indexeret. Men det kan løses med et snuptag.
mkay ... moderne processorer kan levere noget i retning af et par miliarder instruktioner pr. sekundt. derfor er det meget sjældent at flaskehalsen i et phpscript ligger i beregningsdelene. istedet kan det betale sig at minimere antallet (og omfanget) af IO-bursts. dvs. filsystemet primært. jeg vil tro at mysql skal læse de samme mængder data ind fra filsystem hvad enten den skal lave en select og returnere een række eller om den skal blot returnere alle rækker (fra den samme tabel forstås). det der tager længere tid bliver så overførelsen af data mellem mysql og php. det tror jeg som nævnt hellerikke der er det store påstyr ved, da vi - selv med flere tusinde brugere - taler relativt få data, der jo bare skal kopieres rundt i maskinens ramkredse. herefter bruger php-scriptet self. lidt tid på løkken, men det er jvf ovenstående en dråbe i havet. (desuden svarer det omtrent til den tid mysql eksekverer hurtigere, pga. et simplere query)
derfor tror jeg at eksekveringstiden forbliver ganske lav, selv ved mange brugere, men derudover syntes jeg da personligt at det ser smukkere ud, hvis man kan lægge så meget arbejde over i databasen som muligt.
for lige at konkludere lidt, så tror jeg altså at, hvis man virkelig vil speede det lidt op, så skal man lade være med at checke brugeren hver gang siden loades (som det sker nu). istedet kan man nøjes med at checke første gang, og så gemme oplysningerne om bruger+pass i en sessionvariabel.
på den måde slipper man helt for at skulle igang med at slå op i database mere end een gang (og for den ene gangs skyld er det vel underordnet om det tager 1/10 eller 1/2 sekundt at eksekvere ...)
Jeg har delt points'ne lidt ud det virker som om miraculix var inspireret af swaxi, så derfor har swaxi fået de fleste points.
Tak for svaret, håber i er tilfreds med points'ne.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.