
Teilen Sie:
Ehemaliger .NET Developer Advocate @Vonage, polyglotter Software-Ingenieur, AI/ML
Validierung eingehender Nachrichten von der Vonage Messages API
Lesedauer: 7 Minuten
Eine Einführung in Webhooks
Die Vonage Messages API ist phänomenal. Ich weiß, dass wir als Befürworter keine Lieblinge haben sollen, aber sie ist tatsächlich mein Favorit unter den Vonage APIs. Mit ihr können Sie zu senden. Nachrichten über WhatsApp, Facebook Messenger, Viber, SMS und MMS sehr einfach zu versenden. Und auf der anderen Seite können Sie damit empfangen. Nachrichten über die meisten dieser Kanäle empfangen (SMS-Nachrichten werden an die Endpunkte Ihres Accounts zurückgesendet).
Damit Ihre Anwendung eine eingehende Nachricht (oder den Status einer ausgehenden Nachricht) von Vonage empfangen kann, muss Ihre Anwendung über einen öffentlich zugänglichen HTTP-Endpunkt verfügen, an den Vonage die Nachricht senden kann. Diese Nachricht wird als Webhook bezeichnet. Es gibt viele Fragen zum Thema Sicherheit und Webhooks, daher werde ich Ihnen zeigen, wie Sie Ihre Messages-Webhooks absichern können. Wir werden dies mit einer Kombination aus Autorisierung des Überbringers und Validierung der Nutzdaten bewerkstelligen.
Bedenken bezüglich der Webhook-Sicherheit
Die größte Frage, die uns im Zusammenhang mit Webhooks gestellt wird, ist nicht nur, was sie sind, sondern auch, wie wir Webhooks absichern können, um sicherzustellen, dass böswillige Akteure keine bösartigen Webhooks senden. Was kann ein Angreifer tun, wenn er sich Zugang zu unseren Webhook-Endpunkten verschafft und über eine kritische Masse an Benutzerdaten verfügt, die er auf uns werfen kann? Das ist eine berechtigte Sorge.
Stellen Sie sich das folgendermaßen vor: Alice ist eine Anwendungsentwicklerin und möchte eine WhatsApp-Nachricht von Bob erhalten. Bob sendet eine WhatsApp-Nachricht an die Anwendung von Alice. Wenn diese WhatsApp-Nachricht empfangen wird, sendet Vonage eine Nachricht an den HTTP-Endpunkt von Alice, um ihre Anwendung über die eingehende Nachricht zu informieren. Dieser Endpunkt muss öffentlich zugänglich sein. Wenn Chuck, ein böswilliger Hacker, den Webhook-Endpunkt von Alice findet, kann er sich nun für eingehende Nachrichten als Bob ausgeben oder den Status von ausgehenden Nachrichten fälschen.
Eingehende Webhooks authentifizieren
Vonage verwendet JSON Web Token (JWT) Bearer-Autorisierung für Webhooks, die von der Messages API gesendet werden, damit Sie den Webhook einfach authentifizieren können. Das Bearer Token ist ein HMAC-SHA256 Token, d.h. die Verifizierung der Gültigkeit des JWT ist so einfach wie die Dekodierung des Tokens mit seinem Signiergeheimnis. Das Geheimnis, das Sie verwenden müssen, ist dasselbe, das auf der Einstellungsseite im Dashboard. Es wird empfohlen, dass dieses Signiergeheimnis mindestens 32 Bit lang ist, um einen Brute-Force-Angriff zu erschweren. Das Signaturgeheimnis Ihres Accounts ist ein gemeinsames Geheimnis zwischen Ihnen und Vonage.
signing secret
Validieren Sie die Nutzlast eines eingehenden Webhooks
Zusätzlich zur Autorisierung des Tokens ist es eine gute Idee, zu überprüfen, ob die Nutzlast des Webhooks mit dem übereinstimmt, was das Token vorgibt zu sein. JWTs haben nach der Dekodierung eine eigene JSON-Nutzlast - die Felder in diesem JSON werden als Ansprüche bezeichnet. Um zu verhindern, dass ein Angreifer einen Ihrer Token stiehlt und wieder abspielt, können Sie einen dieser Claims verwenden, den payload_hash. Die payload_hash ist ein SHA-256-Hash der Nutzlast des Webhooks. Indem Sie einfach die Nutzdaten der eingehenden Nachricht durch einen SHA-256-Hash laufen lassen und mit dem payload_hash Anspruch im Webhook vergleichen, können Sie sicher sein, dass das Token, das Sie erhalten, kein Replay ist.
Prüfen Sie die Zeit, zu der ein Token generiert wurde
Eine weitere wichtige Angabe ist die iatDies steht für "issued at" und ist der UTC-Unix-Zeitstempel, der angibt, wann das Token erzeugt wurde. Sie können den iat mit dem aktuellen UTC-Unix-Zeitstempel vergleichen, um zu prüfen, wie alt der Zeitstempel ist, um sich vor potenziell veralteten Token zu schützen.
In Code übersetzen
Nehmen wir diese Concepts und setzen sie in Code um. Ich zeige Ihnen, wie Sie dies in Node.js tun können, aber diese Techniken sind in praktisch jeder Programmiersprache verfügbar.
Vonage API-Konto
Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.
Sammeln von Abhängigkeiten
Erstellen Sie ein neues Verzeichnis namens signed_webhooks und cd an. Führen Sie in diesem Verzeichnis npm install dotenv jsonwebtoken js-sha256 express body-parser.
Dateien erstellen und Konfiguration hinzufügen
In unserem signed_webhooks Verzeichnis werden wir ein server.js und eine .env Datei. Die Datei server.js Datei wird unser Servercode gespeichert und unsere .env Datei ist der Ort, an dem unsere Konfiguration gespeichert wird. In der Datei .env Datei fügen Sie nur ein Feld hinzu, NEXMO_API_SIGNATURE_SECRETund setzen Sie es auf das Signaturgeheimnis aus Ihren Dashboard-Einstellungen Seite.
Abhängigkeiten initialisieren
Nachdem wir nun alle unsere Abhängigkeiten gesammelt und unseren Server konfiguriert haben, müssen wir den Servercode hinzufügen. Beginnen wir mit der Initialisierung unserer Abhängigkeiten. Fügen Sie folgendes zu server.js hinzu:
require('dotenv').config();
const jwt = require("jsonwebtoken");
const sha256 = require('js-sha256');
const app = require('express')();
const bodyParser = require('body-parser');
const NEXMO_API_SIGNATURE_SECRET = process.env.NEXMO_API_SIGNATURE_SECRET;
if(!NEXMO_API_SIGNATURE_SECRET){
throw "Missing Signature Secret";
}Dieser Code bringt alle unsere Abhängigkeiten ein und bezieht das Signaturgeheimnis aus unserer Umgebung.
Eingehende Nachrichtenroute hinzufügen
Als nächstes müssen wir die Route für inbound-message und einrichten. status. Wir gehen davon aus, dass die Webhooks, die wir empfangen werden, POST Anfragen sein werden, also fügen wir eine Route zu /webhooks/inbound-message und /webhooks/status und und einrichten POST Anfragen, die durch unsere handleWebhook Funktion geleitet werden.
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
app
.route('/webhooks/inbound-message')
.post(handleWebhook);
app
.route('webhooks/status')
.post(handleWebhook) Eingehende Nachrichten bearbeiten
Wenn wir eine eingehende Nachricht erhalten, ziehen wir den Body heraus und fügen ihn der Nutzlast hinzu. Dann teilen wir den Autorisierungs-Header an Leerzeichen auf (der Autorisierungs-Header hat die Form "Bearer Token", so dass das Aufteilen am Leerzeichen und der Token-Teil uns den JWT liefern).
Mit dem abgerufenen Token können wir das JWT mithilfe unseres Signaturgeheimnisses entschlüsseln. Wie bereits erwähnt, ist diese Dekodierung gleichbedeutend mit der Überprüfung der Authentizität des Tokens. Ist das JWT ungültig oder der Auth-Header fehlerhaft, wird bei der Dekodierung eine Ausnahme ausgelöst, und es wird ein 401 zurückgegeben. Wenn wir in der Lage sind, das Token zu dekodieren, haben wir die Authentizität des Tokens verifiziert. Wenn Sie also hinter TLS stehen und sich nicht um die Validierung der Nutzdaten kümmern, können Sie an dieser Stelle getrost ein 200 zurückgeben. Wie auch immer man sich entscheidet die Nutzdaten zu verifizieren, es ist so einfach wie die Ausführung eines JSON.stringify auf die Nutzdaten und vergleicht sie mit der payload_hash Anspruch des entschlüsselten JWT. Wenn Sie eine Manipulation feststellen, können Sie einen 401 vom Endpunkt zurückgeben, um den Leuten mitzuteilen, dass sie nicht autorisiert sind. Zum Schluss werden wir unsere Anwendung anweisen, auf einem bestimmten Port oder auf Port 3000 zu lauschen.
All dies wird durch die folgende Anfrage erreicht handleWebhook Anfrage:
function handleWebhook(request, response){
const payload = Object.assign(request.query, request.body)
try{
let token = request.headers.authorization.split(" ")[1]
var decoded = jwt.verify(token, NEXMO_API_SIGNATURE_SECRET, {algorithms:['HS256']});
if(sha256(JSON.stringify(payload))!=decoded["payload_hash"]){
console.log("tampering detected");
response.status(401).send();
}
else{
console.log("Success");
response.status(204).send();
}
}
catch(err){
console.log('Bad token detected')
response.status(401).send()
}
}
app.listen(process.env.PORT || 3000) Prüfung
Zu Testzwecken werden wir nur lokal arbeiten. Das Starten des Servers ist einfach: Führen Sie node server.jsaus, und der Server wird hochgefahren.
ngrok einrichten
Um Webhooks an unseren Server weiterzuleiten, werden wir ngrok verwenden. Mit Ngrok können wir einen Tunnel für unseren lokalen Server erstellen. Führen Sie den folgenden Befehl aus.
Dies führt zu einer ngrok-Sitzung, die wie folgt aussieht http://random.ngrok.io-auswechseln random mit dem zufälligen Hash am Anfang der URL, dann fügen Sie die Route zu /webhooks/inbound-message und Sie haben die URL für Ihre Webhooks.
ngrok
Webhooks konfigurieren
Da wir nun einen Tunnel zu unserem Server haben, müssen wir als Letztes unsere Webhooks konfigurieren, bevor wir Nachrichten empfangen können. Zu Testzwecken können Sie die Messages API-Sandbox verwenden - Anleitungen finden Sie in Martyns Blogbeitrag zu diesem Thema oder in den Messages API Sandbox-Dokumente.
Für die Produktion müssen Sie die Webhooks für Ihre Anwendung konfigurieren. Sie können dies tun unter ${CUSTOMER_DASHBOARD_URL}/applications/:appid/editund ersetzen Sie :appid durch Ihre Anwendungs-ID. Sie können sie auch mit der Nexmo CLI oder der Anwendungs-API.
Nach der Bearbeitung sollte die Webhook-Konfiguration Ihrer Anwendung für Nachrichten wie folgt aussehen:
application webhooks
Nun, da alles konfiguriert ist, können wir testweise eine Nachricht entweder an Ihre WhatsApp-, Viber- oder Facebook-Messenger-Nummer senden, und Ihr Server wird die eingehenden Webhooks validieren!
Validierung eingehender SMS
Die Validierung eingehender SMS liegt außerhalb des Rahmens dieses Beitrags, aber wir haben eine ähnliche Methodik für die Validierung eingehender SMS-Nachrichten. Wie das geht, können Sie in unserer Entwickler-Dokumentation.
Ressourcen
Der Code aus diesem Beitrag ist verfügbar auf GitHub.
Eine ausführlichere Erklärung, wie die JWT-Authentifizierung funktioniert, finden Sie in unseren Entwickler-Dokumente.
Wenn Sie ein JWT manuell dekodieren möchten, können Sie das ganz einfach mit jwt.io's Decoder.
