Detta är andra delen i bloggserien "Att bygga sitt egna PHP ramverk" - Första delen hittar ni här!
Något som de flesta sidor har, på ett eller annat sätt är någon form av användarhantering. Det kan vara allt från administratörer till kundregister. För dessa ändamål har jag i mitt ramverk skapat speciella klasser.
I grunden hittar vi klassen Person, som hanterar vanliga uppgifter så som för- och efternamn, födelsedatum, kön och så vidare. Detta är en väldigt enkel klass, men som kan ha många användningsområde.
En utbyggnad av denna klassen är User som hanterar användare. I klassen finns tillägg för bland annat lösenordshantering. Alla lösenord som hanteras envägskrypteras med en sträng unik för sidan i en SHA512-algoritm. Därtill läggs ännu ett lager med för användaren unik data in i krypteringen. För varje User genereras även en säkerhetsnyckel baserad på bland annat data om användaren, så som ip och webbläsare, som exempelvis kan synkroniseras med databasen för ett extra säkerhetslager. Detta för att exempelvis dubbelkolla så att användaren verkligen är samma som loggade in. Detta ska förhoppningsvis försvåra sessionsstölder, men samtidigt öppna upp för enklare och säker kommunikation mellan olika tjänster.
Båda dessa klasser implementerar ett interface som jag valt att kalla SessionsSycnable. Detta interface beskriver att det är möjligt att spara och hämta den aktiva användare från en server session. Detta för att underlätta överföring av information mellan sidladdningar och för att hålla reda på inloggning och dylikt.
Tanken är att allt som kan synkroniseras med session ska implementera SessionsSyncable.
Självklart finns det inga databas kopplingar från någon av dessa klasser då klasserna och objekten av dem ska vara helt oberoende av övrig struktur i systemet. Ett User-objekt är bara ramen och behållaren för information som sedan kan sparas och hämtas från exempelvis en MySQL-databas. Men själva databaslogiken sker uteslutande i Model-klassen och kan vara unik för varje projekt. Men det är ett sätt att försöka standardisera "användaren" och hanteringen av dessa oberoende av projekt.
Låt oss gå in på lite "nörd"-nivå och kolla på lite närmare på funktioner och källkod.
För att säkerställa användarens lösenord så använder vi oss av SHA512-krypering som är en en vägs kryptering. Dessutom slänger vi in två typer av "salt" för att försvåra eventuellt försök till lösa krypteringen med exempelvis en Rainbow-tabell.
Salt i sammanhanget är alltså en unik sträng som läggs ihop med lösenordet som sedan krypteras.
Exempel:
Om vi enbart krypterar ordet "lösenord" så får vi följande SHA512 hash; 4f4674b2f6d25aecb2192cc5351fbf1f79d53582b9b940ef8db87a77b6d1560995525bfd33b516834efee7805f71e46e61447705ba5862b6aa9923b6344d93f3
Denna hash-sträng är alltid samma för ordet "lösenord", vilket betyder att om man med en tabell av kända hash-strängar kan ta reda på själva lösenordet. Inte så bra.
Lägger man dock till "salt", en slumpmässig sträng tillsammans med lösenordet, så får vi ett unik lösenord. Dessutom blir två lösenord som egentligen är samma unika.
Exempel:
Om vi tar ordet "lösenord" och sedan lägger till "sja893haksm3" som salt; alltså "lösenordsja893haksm3" så får vi SHA512-hashen:
6203a2c0fe705aa70737d65622b874a150b66a1a5bba4bfd8de3bed109c9feb3178e65b6e9a88d11ce690270608e62dfc65397740d5867e079eba75eaa1f4888
Detta är såklart betydligt svårare att försöka lösa. Jag har dessutom valt att använda två "salt"-strängar. En helt unik och slumpmässig sträng för användaren och en för systemet. Användarens unika sträng sparas tillsammans med hans övriga uppgifter i databasen och systemets sparas i en konfigurations-fil.
För att göra det ännu svårare kan man även lägga till ytterligare information, allt för att göra det svårare för att "hacka".
Studerar man diverse "decrypters" som finns tillgängliga, som ganska effektivt kan lösa enklare lösenord så får man också en uppfattning om vad man behöver lösa.
De flesta hash avkrypterare fungerar på så vis att de arbetar mot en tabell av vanliga lösenord i kombination med vanligt förekommande salt-strängar. De testar olika kombinationer av salt + lösenord.
Exempel:
md5($pass.$salt)
md5($salt.$pass)
md5(md5($pass).$salt)
md5(md5($salt).$pass)
md5($salt.md5($pass))
md5($salt.$pass.$salt)
En annan metod är att programmet har en tabell med redan lösta hash-strängar (det finns stora databaser med detta) som den sedan jämför mot för att hitta lösenordet.
Sedan finns det såklart den mest tidsödande metoden, att programmet helt enkelt slumpar fram strängar som den sedan försöker jämföra med din hash-sträng. Denna metod är egentligen enbart effektiv mot korta lösenord, då det för varje tecken i ett lösenord ökar antalet kombinationer att prova. Skillnaden mellan att lösa ett lösenord på fem och åtta tecken för en snabb dator är enorm. Ett lösenord på fem tecken har 931151402 kombinationer och går att lösa inom två timmar. Medan ett lösenord på åtta tecken har hela 221919451578090 kombinationer och tar lite drygt 40 år för en dator som kan prova ca 170 000 tecken per sekund.
Så två salt-strängar kombinerat med ett lösenord gör att även korta lösenord blir mycket svåra att lösa. :)
Att bygga sitt egna PHP ramverk:
Att bygga sitt egna PHP ramverk:
Mer läsning:
Wikipedia om SHA-2 (elektroniskt) <http://en.wikipedia.org/wiki/SHA-2>
Testa ditt lösenord på Open Security Research (elektroniskt) <http://calc.opensecurityresearch.com/>
PHP manual om hash-funktionen (elektroniskt) <http://php.net/manual/en/function.hash.php>
Password Hashing, James McGlinn (elektroniskt) <http://phpsec.org/articles/2005/password-hashing.html>







