Integratie van twee-factorenauthenticatie met CodeIgniter

Met de recente reeks van high-profile inbraken (hacks) bij Sony en andere bedrijven, wordt het tijd dat u de veiligheid van uw website opnieuw bekijkt. Twee-factor authenticatie is een stap in de goede richting om uw website te beveiligen tegen aanvallers. In deze zelfstudie bekijken we hoe we deze kunnen implementeren in onze CodeIgniter-toepassing.


Wat is twee-factorenauthenticatie?

Twee-factor-authenticatie vereist dat gebruikers iets dat ze kennen, zoals een gebruikersnaam en wachtwoord, en iets dat ze hebben, zoals een telefoon, gebruiken om in te loggen.

Bedrijven, zoals Google en Facebook, hebben de laatste tijd twee-factor authenticatie uitgerold voor hun gebruikers. Andere services, zoals MailChimp, gebruiken alternatieve vormen van tweefactorauthenticatie om aanvallers te dwarsbomen. Maar toch, wat specifiek tweeledige authenticatie is?

Twee-factor-authenticatie is een manier om uw identiteit te bewijzen op basis van uw gebruikersnaam en wachtwoord, evenals een fysiek apparaat dat u bij u kunt dragen.


De mobiele applicatie van Duo ondersteunt pushmeldingen voor authenticatie!

Dit maakt het voor boeven veel moeilijker om je identiteit te stelen, omdat ze toegang tot je telefoon of hardwaretoken nodig hebben - niet alleen je inloggegevens.

Gelukkig voor jou biedt Duo Security een gratis twee-factor-service die ideaal is voor iedereen die zijn website wil beschermen.

Duo is niet alleen gratis, maar zit boordevol functies. Ze laten je op verschillende manieren verifiëren, waaronder:

  • Phonecall-authenticatie
  • Op sms gebaseerde tokens
  • Generon voor mobiele app-token
  • Push-gebaseerde authenticatie
  • Hardware tokens beschikbaar voor aankoop

Stap 1: Setup

Setup CodeIgniter

Als je nog niet eerder met CodeIgniter hebt gewerkt, raad ik je aan eerst deCodeIgniter From Scratch-serie te bekijken.

Deze tutorial zal voortbouwen op de eenvoudige authenticatie met CodeIgniter-zelfstudie. Deze zelfstudie zal veel gemakkelijker voor u zijn om te begrijpen of u de vorige zelfstudie hebt voltooid voordat u verdergaat. We zullen de bestanden van die tutorial als uitgangspunt gebruiken.

Controleer alsjeblieft dat jouw config / autoload.php heeft de volgende helpers geladen.

$ autoload ['helper'] = array ('url', 'vorm');

Account aanmaken

Ga naar Duo Security en meld u aan voor een account.

Ze bieden een gratis abonnement voor open source-projecten en voor sites met minder dan 10 Duo-gebruikers (een Duo-gebruiker is iemand die de tweefactorauthenticatie gebruikt om in te loggen).

Maak een integratie

Na registratie moet u zich aanmelden bij Duo en een integratie maken. Eenmaal ingelogd, klik op integraties op het zijpaneel om de integratiespagina op te halen. Klik vanaf daar op de knop "Nieuwe integratie".

Zorg ervoor dat de integratie die u maakt een Web SDK-integratie is. Hiermee kunt u hun PHP API gebruiken met CodeIgniter.

De integratienaam wordt alleen gebruikt op de Duo-website. Dit is slechts een manier voor u om uw integratie te identificeren. Duo heeft een beknopte handleiding waarin wordt uitgelegd hoe u een integratie instelt.

Download de web-SDK

Naast het instellen van een integratie, moet u de web-SDK downloaden.

Er zijn twee delen van de SDK die we nodig zullen hebben: een PHP-bestand (duo_web.php) en een JavaScript-bestand. Houd er rekening mee dat JavaScript een jQuery-afhankelijkheid heeft en dat het gebundelde JavaScript wordt geleverd met jQuery.

We zullen het gebundelde JavaScript gebruiken, maar merk op dat als dat niet het geval is, jQuery moet worden geladen voordat het JavaScript wordt geleverd door Duo. Raadpleeg de documentatie op http://www.duosecurity.com/docs/duoweb voor meer informatie over de web-SDK en hoe deze werkt.


Stap 2: Wijzigingen voor beveiliging

Na het voltooien van de Easy Authentication met CodeIgniter zelfstudie, zou u een eenvoudig inlogsysteem moeten hebben.

Betere hashes

Als eerste stap zullen we een sterke hash-functie aan de database toevoegen. Openwall heeft een mooie PHP-hashingbibliotheek die wordt geïmplementeerd bcrypt. De nieuwste versie van phpass is 0.3 ten tijde van dit artikel.

Ga je gang en download phpass van hun website: http://openwall.com/phpass/. Na het downloaden en het opnieuw archiveren van de map, moet u deze in uw bibliothekenmap plaatsen.

We zullen nu ons eigen bibliotheekbestand moeten maken als een interface voor phpass. Maak een nieuw bibliotheekbestand met de naam password.php. Onze bibliotheek heeft twee functies:

  • een hash-functie om de oude wachtwoorden opnieuw te maken
  • een check_password-functie om hashes te vergelijken met leesbare wachtwoorden.
require_once (phpass-0,3 / PasswordHash.php); class-wachtwoord var $ hasher; function __construct () // 8 is de hash-sterkte. Een hogere waarde kan worden gebruikt voor extra beveiliging. // TRUE maakt de wachtwoorden draagbaar. FALSE is veel veiliger. $ this-> hasher = nieuwe PasswordHash (8, TRUE);  functie hash ($ pass) return $ this-> hasher-> HashPassword ($ pass);  function check_password ($ pass, $ hash) return $ this-> hasher-> CheckPassword ($ pass, $ hash); 

De eenmalig benodigd() verklaring zorgt ervoor dat we het kunnen gebruiken PasswordHash klasse van phpass.

PasswordHash neemt twee argumenten in zijn constructor:

  • een getal dat de hashsterkte aangeeft
  • een boolean over de vraag of de wachtwoorden draagbaar moeten zijn of niet.

In dit geval gaan we onze wachtwoorden overdraagbaar maken.

Dit betekent in feite dat de hash niet zo sterk is, maar als we ooit van server moeten wisselen of de database moeten verplaatsen, kunnen we een kopie maken. Als we geen draagbaar hash-schema gebruiken, lopen we het risico dat al onze gebruikers nieuwe wachtwoorden maken als de database wordt verplaatst.

Notitie: Hoewel we een sterkere hash-functie implementeren, moet je nog steeds van gebruikers verlangen dat ze een sterk wachtwoord hebben.

Het Admin-model wijzigen

 public function verify_user ($ email, $ password) $ q = $ this -> db -> where ('email_address', $ email) -> limit (1) -> get ('users'); if ($ q-> num_rows> 0) $ result = $ q-> row (); $ This-> load-> library ( 'password'); // Zorg dat de hashes overeenkomen. if ($ this-> password-> check_password ($ password, $ result-> password)) return $ result;  return false; 

Eerder selecteerden we de gebruiker op basis van het e-mailadres en het hash-wachtwoord. Nu trekken we de gebruiker uit de database op basis van het e-mailadres. Dit betekent dat we het wachtwoord moeten valideren voordat we de gebruiker kunnen retourneren.

Nadat we de gebruiker uit de database hebben gehaald, laden we de wachtwoordbibliotheek die we zojuist hebben gemaakt en controleren we of het ingevoerde wachtwoord overeenkomt met het gehashte wachtwoord.

Als de twee wachtwoorden overeenkomen, gaan we verder met het retourneren van de gebruiker, anders komen we terug vals.

Zorg ervoor dat u de wachtwoordbibliotheek gebruikt om een ​​nieuw wachtwoord voor uzelf te hashen. De wachtwoorden in uw database zijn nu ongeldig!

De tabel Gebruikers wijzigen

We gaan een basistoestemmingsveld toevoegen aan de database. Deze toestemming bepaalt of de gebruiker zich zal aanmelden met tweefactorauthenticatie.

We moeten een kolom toevoegen aan de tabel met gebruikers voor machtigingen voor twee factoren. U kunt dit doen via phpMyAdmin of door de volgende SQL uit te voeren.

ALTER TABLE gebruikers ADD two_factor_permission BOOLEAN NOT NULL;

Een waarde van 1 in de toestemmingskolom zorgt ervoor dat de gebruiker two-factor authenticatie gebruikt.

De SQL voegt een Booleaanse kolom toe aan de tabel met gebruikers. We zullen dit gebruiken om gebruikers te verplichten om tweefactorauthenticatie te gebruiken of om het te omzeilen.

Als u dit goed hebt gedaan, ziet u een nieuwe kolom in uw gebruikerstabel. U moet dan een huidig ​​record bijwerken of een nieuw record invoegen dat wordt ingesteld two_factor_permission naar waar (1).

Als deze kolom is ingesteld op vals (0), kan de gebruiker tweefactorauthenticatie omzeilen. Dit is ideaal voor gebruikers die niet hetzelfde beveiligingsniveau nodig hebben als een beheerder.


Stap 3: De machtigingsinstelling gebruiken

We hebben een manier nodig om secundaire authenticatie te omzeilen, evenals een manier om een ​​secundaire authenticatiestap in te voegen in het inlogproces.

Secundaire authenticatie omzeilen

Ten eerste hebben we een manier nodig om secundaire authenticatie te omzeilen. Dit betekent dat we de gebruiker moeten inspecteren in de beheercontroller.

 if ($ res! == FALSE) $ _SESSION ['gebruikersnaam'] = $ res-> email_address; if ($ res-> two_factor_permission) $ this -> _ second_auth ($ res-> email_address); terug te keren;  else $ _SESSION ['logged_in'] = TRUE; redirect ( 'welkom'); 

Hiermee wordt gecontroleerd of de gebruiker moet zijn aangemeld met ons tweefactorsysteem.

Als de gebruiker two-factor-authenticatie zou moeten gebruiken, willen we dat ze naar de secundaire authenticatiepagina gaan zonder ze in te loggen.

In plaats van de gebruiker om te leiden, kunnen we de gebruiker bellen _second_auth () functie en hebben die de pagina geladen. De "terugkeer"statement vermijdt het laden van het inlogformulier.

We hebben een nieuwe sessievariabele gemaakt ingelogd die we zullen gebruiken om te verifiëren dat de gebruiker is ingelogd. Dit betekent dat we een aantal wijzigingen in de omleidingen moeten aanbrengen.

De omleidingen herstellen

Er zijn twee omleidingen die moeten worden gewijzigd: de eerste bevindt zich in de indexfunctie van de beheercontroller.

if (isset ($ _ SESSION ['logged_in']) && $ _SESSION ['logged_in'] === TRUE) redirect ('welcome'); 

De andere is in de Welkom controller. We moeten ervoor zorgen dat de gebruiker niet is ingelogd voordat hij wordt omgeleid.

if (! isset ($ _ SESSION ['logged_in']) || $ _SESSION ['logged_in']! == TRUE) redirect ('admin'); 

Secundaire authenticatie invoegen

Nu moeten we de secundaire authenticatie afhandelen.

In de admin / index functie, we bellen _second_auth (), dus laten we een basisfunctie schrijven.

 openbare functie _second_auth ($ gebruikersnaam) echo "Welkom $ gebruikersnaam, u kijkt naar een secundaire authenticatiepagina."; 

Stap 4: De weergave construeren

Traditionele authenticatiesystemen behandelen logins als een proces in één stap.

Duo geeft ons een beetje JavaScript en HTML om tussen de twee stappen te injecteren. Dit betekent dat we een weergave moeten maken met de vereiste code.

Laten we een nieuwe weergave maken, genaamd second_auth.php in de keer bekeken map. We moeten het iframe en JavaScript van Duo invoegen om het te laten werken.

Maak een pagina met de eenvoudige HTML-structuur. Het volgende kan in de body worden geplaatst:

  

In een standaardinstallatie zou u al uw JavaScript in een bronmap bewaren. Hier hebben we een geplaatst middelen map in de hoofdmap van onze site, met een 'js'submap die het Web SDK JavaScript-bestand bevat.

Onze src zal lijken op:

src ="resources / js / Duo-Web-v1.js"

We moeten dit tweede bit JavaScript toevoegen.

We zullen deze gegevens binnenkort van de controller genereren.

Een formulier invoegen

Als u de vorige zelfstudie hebt gevolgd, moet u CodeIgniter hebben geconfigureerd ter bescherming tegen CSRF.

Omdat het JavaScript gegevens naar onze controller verzendt, zoekt CodeIgniter naar het CSRF-token. Als we dit token niet hebben, krijgen we een foutmelding.

Het JavaScript dat we gebruiken, verzendt een formulier met het ID "duo_formAlles wat we moeten doen is het maken.

echo form_open ('admin', array ('id' => "duo_form")); echo form_close ();

Door de formulierklasse te gebruiken, zal CodeIgniter het token automatisch injecteren. Wanneer het formulier wordt gepost, zal CodeIgniter het token vinden en ons laten doorgaan.


Stap 5: De gegevens voorbereiden

Terug in de beheerder controller, we moeten wat gegevens genereren in onze _second_auth () functie.

De host is de API-URL die u heeft gekregen toen u zich aanmeldde bij Duo. Deze URL zou er ongeveer zo uit moeten zien api-xxxxxxxx.duosecurity.com (waarbij 'xxxxxxxx' een unieke reeks is die is gekoppeld aan uw Duo-account).

$ data ['host'] = "api-xxxxxxxx.duosecurity.com";

Vergeet niet om de host te vervangen door uw specifieke URL. De bovenstaande URL werkt niet.

De postactie is de URL die het antwoord verwerkt zodra de gebruiker heeft geprobeerd te verifiëren met Duo.

We zullen een andere functie in de beheercontroller maken om de post-back af te handelen. Voor nu noemen we de functie process_second_auth ().

 $ data ['post_action'] = base_URL (). "Admin / process_second_auth";

Laden van de PHP Web SDK

Zorg ervoor dat u 'duo_web.php' hernoemt in 'duo.php' om CodeIgniter-fouten te voorkomen.

Als je het laatste exemplaar van duo_web.php niet hebt gedownload, kun je het krijgen via Duo's Web SDK GitHub-pagina.

Omdat de Web SDK als een PHP-klasse komt, kunnen we de naam wijzigen in 'duo.php"en plaats deze in onze map" application / libraries ".

Nadat u het bestand in de bibliotheken map, kunnen we deze in onze controller laden.

 openbare functie _second_auth ($ gebruikersnaam) $ this-> load-> bibliotheek ('duo'); $ data ['host'] = "api-xxxxxxxx.duosecurity.com"; $ data ['post_action'] = base_URL (). "Admin / process_second_auth"; echo "Welkom $ gebruikersnaam, u kijkt naar een secundaire authenticatiepagina."; 

Het ondertekende verzoek genereren

Om te begrijpen hoe te genereren sig_request, je moet begrijpen wat we genereren.

De $ Akey variabele moet minimaal 40 tekens lang zijn, anders geeft de Duo-bibliotheek een foutmelding!

De Duo Web SDK maakt twee ondertekende tokens, één met de geheime sleutel die ze u geven, een andere met een applicatiesleutel die u verzint.

sig_request is een combinatie van de twee tokens.

Door uw eigen applicatiesleutel te maken heeft u een tweede beveiligingslaag. Een aanvaller heeft zowel de geheime sleutel van Duo als je persoonlijke applicatiesleutel nodig om een ​​token te vervalsen.

Nu zullen we de 'sig_request' genereren. Duo biedt u een integratiesleutel en geheime sleutel wanneer u een integratie maakt.

Zorg ervoor dat de onderstaande tekst wordt vervangen door de integratiesleutel en de geheime sleutel die aan u is verstrekt. U moet uw eigen geheime sleutel verzinnen. Het moet minimaal 40 tekens lang zijn en zo willekeurig mogelijk zijn.

openbare functie _second_auth ($ gebruikersnaam) $ this-> load-> bibliotheek ('duo'); // Duo Integration Key $ ikey = "REPLACE WITH YOUR DUO INTEGRATION KEY"; // Duo geheime sleutel $ skey = "VERVANG MET U DUO SECRET KEY"; // Personal Application Key $ akey = "CREËR EEN TOEPASSINGSLEUTEL"; $ data ['host'] = "api-xxxxxxxx.duosecurity.com"; $ data ['post_action'] = base_URL (). "Admin / process_second_auth"; $ data ['sig_request'] = $ this-> duo-> signRequest ($ ikey, $ skey, $ akey, $ username); echo "Welkom $ gebruikersnaam, u kijkt naar een secundaire authenticatiepagina."; 

Duo's signRequest () genereert de tokens en stuurt ze terug als een tekenreeks waarnaar moet worden doorgegeven sig_request.

Nu moeten we de gegevens laden in de weergave die we eerder hebben gemaakt.

openbare functie _second_auth ($ gebruikersnaam) $ this-> load-> bibliotheek ('duo'); // Duo Integration Key $ ikey = "REPLACE WITH YOUR DUO INTEGRATION KEY"; // Duo Secret Key $ skey = "VERVANG MET UW DUO SECRET KEY"; // Personal Application Key $ akey = "CREËR EEN TOEPASSINGSLEUTEL"; $ data ['host'] = "api-xxxxxxxx.duosecurity.com"; $ data ['post_action'] = base_URL (). "Admin / process_second_auth"; $ data ['sig_request'] = $ this-> duo-> signRequest ($ ikey, $ skey, $ akey, $ username); $ this-> load-> view ('second_auth', $ data); 

Als u nu probeert in te loggen, zou u deze pagina moeten zien:

Dit is het inschrijvingsformulier. U kunt hier uw mobiele telefoon registreren, maar we hebben niets om de secundaire authenticatie te verwerken, zodat u niet wordt aangemeld.

Als u helemaal niets ziet, bekijkt u de paginabron voor foutmeldingen. Eventuele fouten met de gegevens worden weergegeven in de > label.

Als er 'Toegang geweigerd' staat, controleer dan of u de integratie- en geheime sleutel van de website van Duo Security hebt ingevoerd.


Stap 6: Verificatie van secundaire authenticatie

We hebben onze postactie ingesteld om te zijn admin / process_second_auth, dus we moeten een maken process_second_auth () functie.

public function process_second_auth () if (isset ($ _ SESSION ['logged_in']) && $ _SESSION ['logged_in'] === TRUE) redirect ('welcome'); 

Aangezien deze functie een eigen URL heeft, moeten ingelogde gebruikers worden omgeleid.

We moeten de Duo-bibliotheek opnieuw laden om de gegevens te valideren.

$ This-> load-> library ( 'duo'); // Dezelfde sleutels gebruikt in _second_auth () $ ikey = "REPLACE WITH YOUR DUO INTEGRATION KEY"; $ skey = "VERVANG MET UW DUO SECRET KEY"; $ akey = "REPLACE WITH YOUR APPLICATION KEY";

We zullen hetzelfde nodig hebben $ ikey, $ skey en $ Akey van de _second_auth () functie om de geposte gegevens te valideren.

De JavaScript-berichten a sig_response van de Duo-servers.

$ sig_response = $ this-> input-> post ('sig_response'); $ username = $ this-> duo-> verifyResponse ($ ikey, $ skey, $ akey, $ sig_response);

Als we eenmaal hebben getrokken sig_response uit de geposte gegevens zullen we het doornemen verifyResponse () functie. Hierdoor wordt NULL geretourneerd als de tokens niet overeenkomen, of een gebruikersnaam als ze geldig zijn.

if ($ gebruikersnaam) $ _SESSION ['logged_in'] = TRUE; redirect ( 'welkom');  else redirect ('admin'); 

Ten slotte controleren we of er een gebruikersnaam is geretourneerd en voltooi de aanmelding door de waarde in te stellen $ _SESSION [ 'logged_in'] naar waar.

Alles bij elkaar zou de functie er als volgt uit moeten zien:

public function process_second_auth () if (isset ($ _ SESSION ['logged_in']) && $ _SESSION ['logged_in'] === TRUE) redirect ('welcome');  $ this-> load-> library ('duo'); // Dezelfde sleutels gebruikt in _second_auth () $ ikey = "REPLACE WITH DUO'S INTEGRATION KEY"; $ skey = "REPLACE WITH DUO'S SECRET KEY"; $ akey = "REPLACE WITH YOUR APPLICATION KEY"; $ sig_response = $ this-> input-> post ('sig_response'); $ username = $ this-> duo-> verifyResponse ($ ikey, $ skey, $ akey, $ sig_response); if ($ gebruikersnaam) $ _SESSION ['logged_in'] = TRUE; redirect ( 'welkom');  else redirect ('admin'); 

Nu zou je moeten kunnen inloggen met two-factor authenticatie, ga je gang en probeer het uit!


Conclusie

Hopelijk hebt u uw eigen tweefactorauthenticatiesysteem voor CodeIgniter ingesteld!

Wat kan je nog meer doen? Er is genoeg te doen op het gebied van beveiliging, maar de grootste verbetering zou het volgen van gebruikersacties zijn.

Een goed beveiligingssysteem is niet alleen veilig: het helpt u te identificeren waar een kwetsbaarheid vandaan komt. U moet inlogpogingen en andere acties bijhouden om aanvallende aanvragers gemakkelijker te maken.

Bedankt voor het lezen! Als u problemen ondervindt, kunt u een bericht achterlaten in de opmerkingen.