Login og sikkerhed

Tags:    php
Skrevet af Bruger #1435 @ 26.10.2002
Login og sikkerhed

De fleste har vel brugt uanede mængder af tid, på at finde en mulig sikkerheds fejl, her vil jeg personligt beskrive en metode, som kan gøre din side lidt mere sikker, jeg siger ikke at min metode er en sikkerhed, men blot at det hjælper på sagen, og der kan godt være at jeg ikke har ret i alt, men det er ikke derfor jeg har skrevet denne artikel.

Til dette skal der bruges MySql og PHP, MySql er ikke krævet, da det kan udskiftes med almindelige filer. Der kræves også et mindre kendskab til session, da det hele virker efter det konsept, mere info om session i bunden.

Vi skal bruge 5 filer, eller kun 4 filer.
Vi skal bruge en tabel ved navn user (eller efter eget ønske, noget andet), samt felterne username og password, i denne tekst er det begrænset til 30 tegn hver, de er begge varchar med 30 i længde.
Vi skal også bruge et felt der hedder id, denne er int og 11 lang, desuden skal den have auto_increase og primary key.

Config.php

Vi starter med den første fil, som indeholder de tekniske data, som hvordan vi finde vores MySql database. I tilfælde hvor der bruges filer, så er denne ikke nødvendig. Hvis man har disse data tilføjet, så behøves denne fil heller ikke.
<?php
$mysql = mysql_connect("localhost","brugernavn","adgangskode");
$db = mysql_select_db("database",$mysql);
?>
Denne fil gør rent faktisk ikke andet, end at tilslutte til en database i dit MySql, hvis man gerne vil have noget som fortæller dig, at det ikke lykkedes, så kan det laves ved hjælp af en simpel IF-sætning.

Reg.php

Den næste fil vi skal kigge på, indeholder oprettelse af brugere. Dette er endnu en vigtig ting, vi skal stadig sørge for at ingen kan bruge det samme navn, og det skal stadig verificere brugerens adgangskode.
<?php
if (!isset($send)) {
?>
Registrering af en ny bruger<br>
<form action=<?php $php_self ?> method=post>
Indtast ønsket brugernavn!<br>
<input type=text name=name size=30 maxlength=30><br>
Indtast adgangskode!<br>
<input type=password name=passa size=30 maxlength=30><br>
Indtast adgangskode igen!<br>
<input type=password name=passb size=30 maxlength=30><br>
<input type=submit name=send>
</form>
<?php
} else {
$result = mysql_query "SELECT * FROM user WHERE username = ’$name’";
if (!$result) {
if ($passa === $passb) {
$result = mysql_query "INSERT INTO user SET username = ‘$name’, password = ‘$passa’";
if (!$result) {
echo "Du kunne ikke registreres!";
} else {
echo "Du er nu registreret!";
}
} else {
echo "Du har ikke indtastet den samme adgangskode";
}
} else {
echo "Det valgte brugernavn er allerede oprettet";
}
}
?>
Vi lægger ud med en IF-sætning, denne IF-sætning bestemmer hvorvidt vi skal behandle data der er sendt eller ej. Så kommer der formularen, hvis der ønskes flere data, kan dette tilføjes. Alle data der bliver sendt, får automatisk den variabel, som skrevet under name="variabelnavn", disse variabler kommer til at hedde $"det valgte navn". Vi finder herefter en } else { den siger at vi skal kigge på disse data, hvis IF-sætningen er lig 0, eller i dette tilfælde 1. Vi kigger i databasen om brugernavnet allerede er optaget, i dette tilfælde vil der blot blive vist meddelelse herom. Hvis vores fine søgeresultat ikke findes, så går vi videre. Vi ser om de intastede passwords er identisk, og ikke ens som mange vil sige, desuden giver det en stører sikkerhed hvis man bruger identiske passwords, hvis denne handling er 1, så bliver brugeren tilføjet, hvis ikke, er det bare syndt, og prøv venligst igen. Resten er afslutninger på alle de brugte IF-sætninger, samt meddelelser om hvorfor ikke.

Supplerende: ! vender 1 til 0 og omvendt, dette er en god funktion, da der er nogle (som mig selv) som godt kan lide at bruge formularen før noget andet, og en tom variabel vil altid give et 0.
Supplerende: $php_self er predefineret til den url som står skrevet i adresse linien.
Supplerende: * i dit mysql_query, betyder alle felter.

Login.php

Den næste fil indeholder selve login funtionen, man logger ind og får et par globale variabler, det er så det.
<?php
if (!isset($send)) {
?>
Login
<form action=<?php $php_self ?> method=post>
Brugernavn!<br>
<input type=text name=name size=30 maxlength=30><br>
Adgangskode!<br>
<input type=password name=pass size=30 maxlength=30><br>
<input type=submit name=send>
<?php
} else {
$password = md5($pass);
$result = mysql_query "SELECT * FROM user WHERE username = ‘$name’";
if (!$result) {
echo "Det indtastede brugernavn eksisterer ikke!";
}
while ($row = mysql_fetch_array ($result)) {
$check = $row["password"];
}
if (md5($password) === md5($check)) {
session_register("username");
session_register("password");
echo "Du er nu logget ind I vores system!";
} else {
echo "Du kunne ikke logge ind!";
}
?>
Vi har meget af det fra før, det der er nyt her er session_register, den registrerer de informationer som er i variablen på nuværende tidspunkt, alle variabler som bliver registreret er globale, de kan findes ved at bruge variablen, dette kan fjernes ved at bruge session_unregister. Vi ser også en while, den bliver ved med at lave et loop, indtil den er falsk dvs. 0.

Supplerende: session kan stoppes komplet ved at bruge session_destroy.

Logout.php

Den næste fil er til at logge ud, den sletter en session, samt de data man har liggende i den.
<?php
$end = session_destroy();
if ($end) {
echo "Du er nu logget ud!";
} else {
echo "Du kunne ikke logges ud";
}
?>
Der er sådan set ikke noget nyt her, session_destroy sletter en session, din session herefter er komplet ny.

Check.php

Den næste fil er et check, denne fil fortæller ikke noget, men gør livet et helvede for folk, og med god grund.
<?php
$result = mysql_query "SELECT * FROM user WHERE username = ‘$username’";
while ($row = mysql_fetch_array ($result)) {
$check = $row["password"];
}
if ($password !== md5($check) OR !$result) {
session_destroy();
echo "<meta http-equiv=refresh content=0;URL=index.php>";
}
?>
Der er så mesterværket, det som er kedeligt for en almindelig bruger, hvis folk ikke vidste bedre, så ville de sige at du ikke ville have folk på siden. Her er grunden, den sender nemlig folk videre til forsiden (index.php), dette gøres kun hvis en af dem er falsk. Vi bruger en OR i vores IF-sætning, det betyder eller og virker, ved at kun en af dem giver det falske resultat (som altså er sandt) og sender folk videre.

Som konklusion: Kan vi drage nytte af alt, vi har et sikkert login og det er næsten umuligt for folk at logge ind, med mindre at de har oprettet en bruger, vi beskytter også en del andet. Noget som ikke er nævnt, er at vi bruge en md5 encryption, og vi krypterer de sensitive data som vi skal bruge.

Supplerende: session startes ved at bruge session_start, og skal være før alt andet kode, hvis du bruger include, så er det ikke nødvendigt at tilføje på den fil du inkluderer, bare det er på den fil som filen bliver inkulderet i.

Supplerende: Vi encrypterer kun de data vi henter, med andre ord, de encrypterede data eksisterer stadig urørt i databasen.

Som installation: Man kan installere alt dette nemt, for at bruge de globale variabler, skal der være en <?php session_start(); ?> i toppen af siden, denne sørger for at folk har adgang til det de skulle have adgang til. Config.php skal includeres på hver side hvor du skal bruge databasen. Login.php, Logout.php og reg.php kan inkluderes hvor som helst, der er ikke nogen krav til det. Check.php kan inkluderes hvor som helst, men helst først efter body elementet.

Som ændring: Kan det foreslås at skifte variabel-, tabel- og kolone-navne, af sikkerhedsmessige årsager.




Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (18)

User
Bruger #2977 @ 09.02.03 21:28
Skal session_start stå der så den blive kørt hver gang siderne bliver åbnet? Altså skal man ikke først tjekke om man er logget ind før man kører session_start? For hvis man er logget ind bliver den jo kørt for 2. gang og det kan vel godt gå hen og blive noget rod eller hvad? Og hvis man skriver $username = "wee"; session_register("username";); kan man så bare bruge $username til at hente brugernavnet?
User
Bruger #2737 @ 18.02.03 09:49
Hmm.. Det er ikke første gang jeg læser denne artikel, og det undrer mig at min tidligere kommentar ikke er blevet taget til eftertanke.. Anyways.. Det er IKKE sikkerhed, når man tager en brugerangiven variablen (fx $name) og hælder direkte ind i MySQL-query'en.. brug mysql_escape_string($name)..!
Og desuden kræver dette script at register_globals er slået til, hvilket igen er en sikkerhedsrisiko... Inspiration kan evt hentes på
http://xyborx.dk/index.php?g=&p=source&f=./lib/usersys.inc (et system jeg i øjeblikket er igang med at udvikle)
User
Bruger #2737 @ 18.02.03 09:58
Har også skrevet om det her:
http://www.udvikleren.dk/show.php?mode=tip&id=300
User
Bruger #2737 @ 18.02.03 10:15
Ok, jeg har nu lagt mærke til at det bare er kommentarene der er blevet slettet.. (undrer mig lidt ,men skidt pyt).. Troede lige at artiklen var blevet dobbelt-posted ;o)
User
Bruger #4003 @ 11.11.03 11:18
Hmmm....som nævnt, så kræver scriptet register_globals = on, hvilket bør ændres...det er dog en mindre sag...

Hvis et system skal være sikkert, så er der især én ting jeg mener er ufravigeligt! Det er, at password gemmes krypteret i databasen, og IKKE råt som det er tilfældet her. Jeg ville være påpasselig med at anvende dette script hvis målet er et sikkert website.

Brugen af md5 krypteringen skaber falsk tryghed i dette script, da det faktisk anvender det "rå" password fra brugerindtastning og det "rå" password fra databasen, og SÅ krypterer dem begge når de skal sammenlignes??? -man kunne ligeså sammenligne de rå passwords så...det ville være lige så (u)sikkert.

Mit forslag: Ved oprettelse, krypter password med md5 og gem den krypterede værdi i databasen!!! Ved login, krypter brugerinput med md5 og sammenlign det med den allerede krypterede værdi i databasen...i den forslåede løsning kan de anvendelige passwords læses lige ud af databasen, hvilket er alt for usikkert efter min mening!
User
Bruger #4887 @ 11.12.03 22:13
Kan ik få det til at virke? når jeg gåt ind i Reg.php står der: Parse error: parse error, unexpected '\\"' in /customers/clan-furious.dk/clan-furious.dk/httpd.www/emil/Reg.php on line 16
User
Bruger #7500 @ 10.04.05 13:27
Hej jeg er nu på siden og ny i php og jeg prøvede at få de scrips i dette dokument til at virke men da jag efter en 6 timer havde løse alle script fejelende og det stadig ikke virkede blev jeg sku lidt "pist". Jeg mener du burte ligge noget op det virker eller helt lade vær med at have denne artiklel postet.
mvh. thorbjørn
User
Bruger #7603 @ 22.09.05 22:36
Hvad gør $PHP_SELF
User
Bruger #7603 @ 02.10.05 18:01
En lille kommentarer mere!!

Artiklen er ikke speciel Go' da du ikk forklarer det som du vil skrive om, ret godt
User
Bruger #8692 @ 24.01.06 21:54
Artiklen er ikke ret godt beskrevet. Jeg har selv lige prøvet at få det til at virke. Uden held, det skal så lige siges jeg ikke er den store php haj. Men i min reg.php så få får jeg felterne frem, men når jeg udfylder nogle felter, så sker der intet. Det er som om den bare refresher siden, og ja, jeg har husket min database connection...
User
Bruger #10615 @ 01.10.06 13:04
Jeg har et site som skal indeholde disse scripts. De er uploaded til det directory hvor de skal bruges.
Problemet er bare hvor skal disse scrips indsættes ?

Jeg har en indexeringsside i bibliotektet som henviser til et banner og en velkomstside lige nu.

Men hvor skal disse scrips sættes ind ?; login.php, reg.php, check.php og logout.php.

mvh

John
User
Bruger #10615 @ 01.10.06 13:08
Jeg har et site som skal indeholde disse scripts. De er uploaded til det directory hvor de skal bruges.
Problemet er bare hvor skal disse scrips indsættes ?

Jeg har en indexeringsside i bibliotektet som henviser til et banner og en velkomstside lige nu.

Men hvor skal disse scrips sættes ind ?; login.php, reg.php, check.php og logout.php.

mvh

John
User
Bruger #11991 @ 20.06.07 17:39
Jeg har fulgt de 2 første trin, men allerede ved den 2. gik der noget galt.
Jeg kopierede og satte ind i notepad, så gik jeg ind og så den lokalt på min computer, og den så fin ud, men lige så snart jeg lagde den ud på nettet, så var der bare hvid skærm.
Hvad er der galt? Noger der kan svare på det???

Min hjemmeside er: <a href="http://www.fambi.dk/reg.php">www.fambi.dk/reg.php</a>

Håber i kan hjælpe.

M.V.H.

Anne-Katrine
User
Bruger #11991 @ 20.06.07 17:43
ups! Min sider er kun www.fambi.dk/reg.php :P
User
Bruger #14983 @ 15.05.09 13:12
Hehe nu har jeg også lige prøvet den. synes heller ikke der står meget om hvad der sker og sådan, men får da også en dejlig syntax fejl. det kan jeg ikke ikke forstå da jeg laver det hele efter min database. :S så hvis nogle af jer kan se hva fejlen er i denne sætning vil jeg blive meget glad
$result = mysql_query "SELECT * FROM admin WHERE username = '$user'";

vel og mærket hedder min tabel admin og feltet hedder username
User
Bruger #14855 @ 26.05.09 08:59
En tre fra mig :) Vil have givet dig mere vis du VISTE hvordan man lavede tabels og lign :) vis i gerne vil vide det så gå ind på http://phpartikler.dk
User
Bruger #9812 @ 16.12.09 13:16
Hej Ralph

Et fint stykke arbejde du har gjort dig.

Der mangler dog et par ting:

1. Du må ikke opbevare ukrypterede passwords i din database, det er en meget dårlig ide, siden der ikke er nogen der skal vide hvad passwords'ene er!

2. Du bør i config.php kun have konfiguration og ikke lave alle mulige forskellige forbindelser til database eller lignende.

3. Når du skal kryptere passwords så gør det med SHA1 istedet for MD5, jeg ved udemærket at det er standarden, men det bevæger sig stille og roligt!

4. Og når du så har fundet den korrekte krypterings metode, så skal du tilføje en SALT, det besværliggør de såkaldte dictionary attacks, SALT'en er en lille tekststreng f.eks. en krypteret streng kun du kender(navnet på din hund). Denne tilføjer du så til passwordet hvergang inden du krypterer det og smider i databasen. Den samme streng tilføjer du til det indtastede password og krypterer og matcher.

Håber det kan hjælpe dig(kan se det er en lidt ældre artikel) og andre der kommer herind og gerne vil bruge koden

MVH Nicolai
User
Bruger #1435 @ 28.03.11 20:51
Jeg må da lige at jeg har lært en del siden at jeg skrev denne artikel (læs: jeg var ung og dum).

Men skal se om jeg i det hele taget kan opdatere artiklen, er trods alt blevet meget klogere siden den gang (red. 2002 er længe siden).

Nicolai: Jeg kan udemærket se dine point'er, Angående punkt 1 og 3 og 4:jeg anvender i skrivende en langt bedre kryptering end hash'ing, punkt 2: anvender også en samlet configurationsfil til alt det der er fast defineret. Men mange tak for de vise ord.

Desuden er register_globals et dødt emne (i min verden), ved ikke hvorfor at jeg ikke fik læst op på det inden at jeg skrev artiklen.

Jeg vil prøve at opdatere denne artikel, så den kan blive bedre.
Du skal være logget ind for at skrive en kommentar.
t