Skip to content

Yubikey als 2FA

PHP
  • Heute mal was Praktisches 😉

    Wir haben eine Webseite, dazu benutzen wir ein Loginscript. Diese Funktion möchten wir jetzt um einen 2FA erweitern. Da ich schon viele Jahre einen Yubikey benutze, wollte ich das natürlich einbauen.

    IMG_20190622_093022_ergebnis.jpg

    Der Yubikey kann mit zwei Slots bestückt werden, Standard ist auf Slot 1 ein OTP, Slot 2 habe ich mit einem statischen Passwort versehen, doch das soll hier ja nicht das Thema sein.

    Also, der Plan 🙂

    Nach dem Login mit EMail und Passwort kommt man auf eine Seite wo man nach dem Yubikey gefragt wird. Dazu muss dieser eingesteckt werden und die Taste berührt werden. Wenn der OTP zu dem vorher angelegten YubiKey passt, erfolgt der Login, wenn nicht wird er verweigert.

    Installation

    Komplette Installation, da ich nach Serverumzug danach gesucht habe, hier in drei Zeilen! (Update: 21. August 2019)

    apt install php-pear
    wget https://developers.yubico.com/php-yubico/Releases/Auth_Yubico-2.6.tgz
    pear install Auth_Yubico-2.6.tgz
    

    Für PHP-Coder gibt es auf der folgenden Seite Informationen zu der Installation und Nutzung.
    https://developers.yubico.com/php-yubico/

    Ich hatte so ein wenig Probleme, das vernünftig zu installieren, kann mich aber nicht mehr an alles so genau erinnern. Mist, sonst schreibe ich immer alles mit. Es ging um ein paar .dll Dateien, die im falschen Verzeichnis lagen. Ein kopieren von Hand hatte dieses Problem aber gelöst. Also, nicht aufgeben, mal die Fehlermeldungen genau lesen.

    Solltet Ihr mal eine neue Version von Auth_Yubico installieren wollen, so müsst Ihr erst die alte deinstallieren.

     root@one /home/frank # pear install Auth_Yubico-2.6.tgz
     Skipping package "pear/Auth_Yubico", already installed as version 2.5
     No valid packages found
     install failed
    

    So, sah das aus.

    root@one /home/frank # pear install Auth_Yubico-2.6.tgz
    install ok: channel://pear.php.net/Auth_Yubico-2.6
    

    Erledigt 🙂

    Beispiel Code

    Hier das Beispiel von Yubico zur Implementierung in den Code.

    <?php
     require_once 'Auth/Yubico.php';
     $otp = "ccbbddeertkrctjkkcglfndnlihhnvekchkcctif";
    
     # Generate a new id+key from https://upgrade.yubico.com/getapikey
     $yubi = new Auth_Yubico('42', 'FOOBAR=');
     $auth = $yubi->verify($otp);
     if (PEAR::isError($auth)) {
        print "<p>Authentication failed: " . $auth->getMessage();
        print "<p>Debug output from server: " . $yubi->getLastResponse();
     } else {
        print "<p>You are authenticated!";
     }
    ?>
    

    Mich hatte mal interessiert, wo das Auth/Yubico.php auf dem Server liegt

    root@one / # find -name Yubico.php
    ./usr/share/php/Auth/Yubico.php
    

    Gut, der Code sollte soweit ja kein Problem sein.

    $otp = "ccbbddeertkrctjkkcglfndnlihhnvekchkcctif";    
    

    Das ist der OTP, den man bekommt wenn man die Taste auf dem Yubikey berührt.

    $yubi = new Auth_Yubico('42', 'FOOBAR=');
    

    Um die API von Yubico benutzen zu können, muss man sich einen Account anlegen. Auf https://upgrade.yubico.com/getapikey bekommt man die benötigten Daten.

    Der Rest sollte selbsterklärend sein.

    Praxis

    Auswertung

    // Auswertung!! 
    
    if(isset($_GET['login'])) {
     $email = **gekürzt**;
     $yubikey = htmlspecialchars($_POST['yubikey']);
         
     $statement = $pdo->prepare("SELECT * FROM users WHERE email = :email");
     $result = $statement->execute(array('email' => $email));
     $user = $statement->fetch();
     
    
    // YubiKey Auswertung
    if(!$user['otpKey'] == NULL) {
    
      $otp = strtolower($yubikey);
      require_once 'Auth/Yubico.php';
      
    
      # Generate a new id+key from https://upgrade.yubico.com/getapikey
      $yubi = new Auth_Yubico('******', '******');
      $auth = $yubi->verify($otp);
      if (PEAR::isError($auth)) {
        //Error Auswertung
               header('Location: yubi_error.php');
              die();
           
      } else {
        //Erfolg
        **GEKÜRZT**
                    }
        header('Location: /ziel.php');
        die();
        
      }
    }
    
    
    }
    ?>
    

    Kurzerklärung

    Was macht man? Der User loggt sich mit EMail & PW ein, man merkt sicht die EMail, wenn das PW stimmt. Springt auf die Yubikey Abfrage. Dort liest man den OTP ein, schaut in der Datenbank nach dem hinterlegten Yubikey. Wenn hinterlegt ist, wird der OTP auf Gültigkeit abgefragt. Danach erfolgt der Login, wenn nicht kommt einen Fehlermeldung.

    Wie ich das gelöst habe, mit der Speicherung des Yubikeys im Backend, erkläre ich im nächsten Beitrag.

    Es sind oben im Code ein paar Sachen gekürzt. Wer damit Probleme hat, kann mir gerne eine PN schreiben, ich erkläre das Gerne. Möchte das aber hier nicht öffentlich stehen haben, weil ich nicht 100% weiß ob das perfekter Code ist 🙂

  • Das passende Backend dazu.

    Hiermit wird der Yubikey festgelegt.

    Yubi_2.png

    Wenn er angelegt wurde, kann man ihn hiermit wieder löschen.

    Yubi_1.png

  • Die ersten 12 Stellen eines Yubikeys sind immer gleich. Diese 12 Stellen speichern wir in einer Datenbank.

    $otp = substr ($otpKey, 0, 12);
    

    In der Datenbank speichern.

    //SQL
          $statement = $pdo->prepare("UPDATE users SET otpKey = :otpKey_neu WHERE id = :id");
          $statement->execute(array('otpKey_neu' => $otp, 'id' => $userid));
    
    //Überwachung auf Erfolg
          if ($statement->execute()) {
              // DB Eintrag erfolgreich geschrieben  
              echo "YubiKey Passwort erfolgreich gespeichert!";
          } else {
              echo "Datenbank Fehler! Bitte informieren Sie den Administrator.";
          }
    

    Ich hoffe, es hilft dem ein oder anderen sich mit diesem Thema etwas zu beschäftigen.

  • PHP - ChatGPT

    PHP
    1
    0 Stimmen
    1 Beiträge
    63 Aufrufe
    Niemand hat geantwortet
  • PHP Webseite lokal einhängen mit sshfs

    PHP
    1
    0 Stimmen
    1 Beiträge
    39 Aufrufe
    Niemand hat geantwortet
  • PHP Data Objects

    Linux
    4
    0 Stimmen
    4 Beiträge
    271 Aufrufe
    FrankMF
    Datensatz löschen

    Voraussetzung ist, das man die ID des zu löschenden Eintrages kennt.

    $statement = $pdo->prepare("DELETE FROM feinstaub WHERE id = ?"); $statement->execute(array($id)); if ($statement->execute()) { echo "Der DB-Eintrag wurde erfolgreich gelöscht!"; } else { echo "Bitte den Administrator informieren!"; }
  • Wichtige Info

    Angeheftet PHP
    1
    0 Stimmen
    1 Beiträge
    195 Aufrufe
    Niemand hat geantwortet
  • Geo Loacation

    PHP
    1
    0 Stimmen
    1 Beiträge
    286 Aufrufe
    Niemand hat geantwortet
  • PHPMailer

    Verschoben PHP
    1
    0 Stimmen
    1 Beiträge
    412 Aufrufe
    Niemand hat geantwortet
  • Wichtige Links zum Coden

    PHP
    1
    0 Stimmen
    1 Beiträge
    355 Aufrufe
    Niemand hat geantwortet
  • Reload einer PHP Seite verhindern

    PHP
    1
    0 Stimmen
    1 Beiträge
    687 Aufrufe
    Niemand hat geantwortet