In diesem Leitfaden für Entwickler zeigen wir Ihnen Schritt für Schritt, wie einfach die SMS-Zwei-Faktor-Authentifizierung mit GatewayAPI eingerichtet werden kann. Wenn Sie noch kein Nutzer sind, können Sie sich ganz einfach und kostenlos hier anmelden!
Eine Möglichkeit, Ihr Authentifizierungsverfahren sicherer zu machen, besteht darin, weitere Authentifizierungsschritte hinzuzufügen. Eine Methode, die wegen ihrer Bequemlichkeit weit verbreitet ist, sind einmalige SMS-Codes. Diese werden an die Telefonnummern der Kontoinhaber gesendet, sobald ein gültiges Passwort eingegeben wurde. Dies wird auch als SMS-Zwei-Faktor-Authentifizierung, SMS-Passwort oder OneCode bezeichnet und kann u. a. von Authy oder ähnlichen Diensten bereitgestellt werden.
Erstellung einer Verbindung mit API
Bevor wir mit der Authentifizierung von Kontoinhabern über ein Zwei-Faktor-Verfahren beginnen können, müssen wir zunächst festlegen, wie wir eine SMS über die GatewayAPI senden möchten.
Hier verwenden wir Python für die Codebeispiele. Für Ruby- und PHP-Entwickler finden Sie in unserer Dokumentation auch Beispiele für die Verwendung von GatewayAPI mit diesen und vielen anderen Sprachen.
GatewayAPI bietet verschiedene Möglichkeiten, ein Authentifizierungsverfahren durchzuführen. Wir werden uns auf die Verwendung des Protokolls OAuth1 konzentrieren, da es sowohl unterstützt wird als auch einfach zu handhaben ist.
Gehen Sie zu Ihrem Dashboard und wählen Sie in der Seitenleiste Einstellungen -> OAuth-key. Ein Schlüsselsatz sollte bereits mit einer Kennzeichnung vorhanden sein, die angibt, dass er vom System erstellt wurde. Klicken Sie auf die Schlüssel-Schaltfläche auf der rechten Seite, und Sie erhalten Ihren Schlüssel und Ihr Secret. Dies benötigen Sie, um die Authentifizierung über die API durchzuführen.
Jetzt sollte es ganz einfach sein, eine SMS zu versenden. Mit Python lässt sich das folgendermaßen bewerkstelligen:
Installieren Sie die Abhängigkeiten mit: pip install requests_oauthlib
from requests_oauthlib import OAuth1Session
key = '**********YOUR KEY**********'
secret = '**********YOUR SECRET**********'
gwapi = OAuth1Session(key, client_secret=secret)
req = {
'recipients': [{'msisdn': 4512345678}], # remember to change
'message': 'First SMS sent using GatewayAPI',
}
res = gwapi.post('https://gatewayapi.com/rest/mtsms', json=req)
res.raise_for_status()In unserer Dokumentation finden Sie Beispiele, wie Sie eine SMS in anderen Sprachen versenden können.
SMS-Zwei-Faktor-Authentifizierung einrichten
Da wir nun wissen, wie man eine SMS sendet, können wir zum nächsten Schritt übergehen.
Das Zwei-Faktoren-Verfahren umfasst zwei Schritte: Der erste Schritt ist die Authentifizierung mit einem Benutzernamen und einem Passwort, und bei Erfolg ist der zweite Schritt die Authentifizierung mit einem einmaligen Code, der Ihnen über die Rest-API von GatewayAPI als SMS zugeschickt wird.
Da es sich um ein Zwei-Faktor-Verfahren handelt, müssen wir in der Lage sein, Daten zwischen den beiden Schritten zu speichern. Hierfür werden wir einen Redis-Server verwenden, aber es kann auch ein session object, eine MySQL-Datenbank oder eine andere Methode sein, um Informationen zwischen den beiden Schritten zu speichern.
Wir verwenden auch PyOTP, eine Bibliothek, die unter anderem die Erstellung von einmaligen Codes erleichtert. Für Ruby-Entwickler gibt es eine PyOTP-ähnliche Bibliothek namens ROTP. Für PHP-Entwickler gibt es OTPHP.
Was sind die nächsten Schritte?
Schritt 1
Wir erstellen zuerst einen AuthClient, der die gesamte schwere Arbeit übernimmt.
def step_one(self, username, password, phone):
# code that authorizes username and password goes here
# at this point, it should have been established that username and
# password is legit and a user id should have been acquired
user_id = 1
# Generate a random secret for the user, recommended in a 2FA setup
self.redis.setnx('secret:{}'.format(user_id), pyotp.random_base32(length=32))
secret = self.redis.get('secret:{}'.format(user_id))
# Counter that increases for each auth attempt for the particular user
count = self.redis.incr('counter:{}'.format(user_id))
hotp = pyotp.HOTP(secret, digits=6)
sms_code = hotp.at(count)
self.send_sms(sms_code, phone)
return user_idWir verwenden auch einen Zähler in unserer Redis-Datenbank, der sich bei jedem Authentifizierungsversuch für diesen Benutzer erhöht. Diese Anzahl seedes wird an unsere PyOTP-Instanz weitergegeben, um sicherzustellen, dass sie eindeutig ist. Wir erhalten dann einen neuen Code von PyOTP. Damit geben wir im zweiten Schritt den SMS-Code frei.
Anschließend senden wir den SMS-Code an die Telefonnummer des Nutzers, wobei wir eine Funktion verwenden, die fast identisch mit unserem vorherigen Beispiel für den SMS-Versand ist. Schließlich senden wir die ID des Nutzers zurück, der mit dem Benutzernamen und dem Passwort übereinstimmt.
Die Sicherheit steht immer an erster Stelle
Wir speichern ein zufälliges Secret für jeden Benutzer nach Bedarf in Redis, aber Sie können dieses Secret auf jede beliebige Weise erzeugen und speichern. Achten Sie nur darauf, dass es sicher ist. Mehr über den Umgang mit Secrets erfahren Sie hier.
def step_two(self, auth_user_id, sms_code):
secret = self.redis.get('secret:{}'.format(user_id))
hotp = pyotp.HOTP(secret, digits=6)
count = self.redis.get('counter:{}'.format(auth_user_id))
if not hotp.verify(sms_code, count):
raise Exception('Not a valid SMS code for user')Schritt 2
Schritt 2 ist noch einfacher. Wir liefern die erhaltene Benutzer-ID, die in Schritt 1 zurückgesendet wurde, und den SMS-Code, der an die Telefonnummern der Nutzer gesendet wurde. Dann können wir uns den aktuellen Zähler in Redis ansehen und sicherstellen, dass der SMS-Code übereinstimmt.
Mit all dem könnte unser Flow im ersten Schritt wie folgt aussehen:
try:
ac = AuthClient()
user_id = ac.step_one('username', 'password', 4521324354)
print("SMS code sent")
except:
print("Failed to sent SMS code")Und so für Schritt 2:
try:
ac = AuthClient()
token = ac.step_two(user_id, sms_code)
print("Authentication succeeded")
except Exception as e:
print("Authentication failed")Wenn die Authentifizierung abgeschlossen ist, wurde der Nutzer mit einem Zwei-Faktor-Verfahren authentifiziert und ein Authentifizierungstoken erhalten.
Das Beispiel dient dazu, die Technik über GatewayAPI und die Verwendung von Einmalpasswörtern zu demonstrieren.
In einer Produktionsumgebung sollten zudem moderne Sicherheitsmaßnahmen wie die Vorbeugung von brute force und Verschlüsselung aller sensiblen Daten zum Einsatz kommen. Sehen Sie sich die Vorschläge von RFC4226 an und worauf Sie bei der Verwendung von PyOTP oder ähnlichen Bibliotheken und Techniken achten sollten.
Es gibt viele Möglichkeiten, wenn Sie SMS in Ihre Anwendungen einbeziehen. Die SMS-Zwei-Faktor-Authentifizierung, bestehend aus einem Passwort und einem SMS-Code, ist nur eine davon.
Codebeispiel
import pyotp
import redis
from requests_oauthlib import OAuth1Session
class AuthClient(object):
def __init__(self):
self.redis = redis.StrictRedis(host='localhost', port=6379, db=0)
def send_sms(self, sms_code, phone):
key = '**********YOUR KEY**********'
secret = '**********YOUR SECRET**********'
gwapi = OAuth1Session(key, client_secret=secret)
req = {
'recipients': [{'msisdn': phone}],
'message': 'Your code is {}'.format(sms_code),
'sender': 'SMS Verify',
}
res = gwapi.post('https://gatewayapi.com/rest/mtsms', json=req)
res.raise_for_status()
def step_one(self, username, password, phone):
# code that authorizes username and password goes here
# at this point, it should have been established that username and
# password is legit and a user id should have been acquired
user_id = 1
# Generate a random secret for the user, recommended in a 2FA setup
self.redis.setnx('secret:{}'.format(user_id), pyotp.random_base32(length=32))
secret = self.redis.get('secret:{}'.format(user_id))
# Counter that increases for each auth attempt for the particular user
count = self.redis.incr('counter:{}'.format(user_id))
hotp = pyotp.HOTP(secret, digits=6)
sms_code = hotp.at(count)
self.send_sms(sms_code, phone)
return user_id
def step_two(self, auth_user_id, sms_code):
secret = self.redis.get('secret:{}'.format(user_id))
hotp = pyotp.HOTP(secret, digits=6)
count = self.redis.get('counter:{}'.format(auth_user_id))
if not hotp.verify(sms_code, count):
raise Exception('Not a valid SMS code for user')Globales SMS-Gateway
Wir haben die Implementierung von SMS-Diensten in Ihr Unternehmen vereinfacht, indem wir einige der weltweit besten Preise sowie eine einfache Integration, erstklassigen Kundensupport, eine intuitive Benutzeroberfläche und eine solide Betriebszeit von über 99,99% angeboten haben. Wenn Sie noch kein Konto haben, können Sie in weniger als zwei Minuten ein KOSTENLOSES Konto erstellen. Gehen Sie zu GatewayAPI oder wenden Sie sich an sales@gatewayapi.com.

