https://a.storyblok.com/f/270183/1368x665/9cf2bb9c91/25oct_dev-blog_sim-swap-go.jpg

SIM-Swap-Betrug mit Go und Vonage aufdecken

Zuletzt aktualisiert am October 23, 2025

Lesedauer: 5 Minuten

Die meisten Online-Konten verlassen sich immer noch auf SMS für die Zwei-Faktor-Authentifizierung (2FA). Aber was passiert, wenn ein Betrüger Ihren Anbieter dazu bringt, Ihre Nummer auf seine SIM-Karte zu übertragen (SIM-Austausch-Angriff)? Plötzlich werden diese Sicherheitscodes, die Sie schützen sollen, zu einem Werkzeug, das gegen Sie eingesetzt wird.

Eine SIM-Swap-Prüfung ersetzt nicht 2FA, sondern teilt Ihrer App mit, ob SMS immer noch ein sicherer Kanal ist, der verwendet werden kann. In diesem Tutorial zeigen wir Ihnen, wie Sie die Identity Insights API von Vonage mit Go (Golang) integriert wird, um SIM-Swaps in Echtzeit zu erkennen und Ihre Nutzer vor Account-Hijacking zu schützen.

>> TL;DR: Holen Sie sich den vollständigen funktionierenden Code auf GitHub.

Voraussetzungen

Um mitzumachen, brauchen Sie:

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.

Projekt einrichten

Erstellen einer Vonage-Anwendung

  • Um eine Anwendung zu erstellen, gehen Sie auf die Seite Erstellen einer Anwendung auf dem Vonage Dashboard und legen Sie einen Namen für Ihre Anwendung fest.

  • Wenn Sie eine API verwenden möchten, die Webhooks nutzt, benötigen Sie einen privaten Schlüssel. Klicken Sie auf "Generate public and private key", der Download sollte automatisch starten. Bewahren Sie ihn sicher auf; dieser Schlüssel kann bei Verlust nicht erneut heruntergeladen werden. Er folgt der Namenskonvention privat_<Ihre App-ID>.key. Dieser Schlüssel kann nun zur Authentifizierung von API-Aufrufen verwendet werden. Hinweis: Ihr Schlüssel funktioniert erst, wenn Ihre Anwendung gespeichert ist.

  • Wählen Sie die benötigten Funktionen (z. B. Voice, Nachrichten, RTC usw.) und stellen Sie die erforderlichen Webhooks bereit (z. B. Ereignis-URLs, Antwort-URLs oder URLs für eingehende Nachrichten). Diese werden im Lernprogramm beschrieben.

  • Zum Speichern und Bereitstellen klicken Sie auf "Neue Anwendung generieren", um die Einrichtung abzuschließen. Ihre Anwendung ist nun bereit für die Verwendung mit Vonage-APIs.

Die Identity Insights API ist auf Live-Mobilfunknetzdaten angewiesen, um SIM-Wechsel zu erkennen. Aktivieren von Netzwerk-Registrierung in Ihrer Vonage Anwendung ermöglicht den Zugriff auf diese Datenquelle. In der Produktion erfordert dies die Zustimmung des Betreibers, was einige Zeit in Anspruch nehmen kann, aber im Playground-Modus können Sie sofort mit dem Testen beginnen.

Erstellen Sie dazu eine Vonage-Anwendung im Vonage Dashboard mit:

  1. Netzwerkregistrierungsfunktion aktiviert, und wählen Sie "Playground".

  2. Erzeugen Sie einen privaten.Schlüsselmüssen Sie diesen im folgenden Abschnitt in das Stammverzeichnis verschieben

Einrichten Ihrer Go-App

Führen Sie in Ihrem Terminal die folgenden Befehle aus, um ein Projektverzeichnis und die erforderlichen Dateien zu erstellen:

mkdir go_sim_swap_checker
cd go_sim_swap_checker
touch main.go .env

>> Sie können nun Ihre heruntergeladene privat.schlüssel in den go_sim_swap_checker Verzeichnis

Abhängigkeiten installieren

Initialisieren Sie in Ihrem Projektverzeichnis das Go-Modul und installieren Sie die erforderlichen Pakete:

go mod init sim_swap_checker
go get github.com/golang-jwt/jwt/v5
go get github.com/joho/godotenv
go get github.com/google/uuid
  • golang-jwt: Ermöglicht die Erzeugung von JWT-Token für die API-Authentifizierung

  • godotenv: Lädt Umgebungsvariablen aus einer .env-Datei

  • uuid: Erzeugt eindeutige Bezeichner für jedes JWT, damit jedes Token sicher unterschieden werden kann

Konfigurieren Sie Ihr.env Datei

Öffnen Sie die .env-Datei in Ihrem Texteditor und fügen Sie Folgendes hinzu:

VONAGE_APPLICATION_ID=your_application_id
VONAGE_PRIVATE_KEY_PATH=./private.key
PHONE_NUMBER=+990123455
DEFAULT_HOURS=240

Fügen Sie Ihre Vonage-Anwendungs-ID, eine Standard-Telefonnummer und den Zeitraum in Stunden für die SIM-Wechselprüfung hinzu.

Die Virtuelle Vermittlungsstelle von Vonage stellt 9 gültige Telefonnummern zur Verfügung, die Sie zum Testen verwenden können, sowie eine, die eine "unbekannte" Antwort liefert.

Sie können in der API-Referenz für Identitätseinblicke sehen Sie, dass der Sim-Swap-Einblick auf einem einzigen Parameter namens ZeitraumWir nennen ihn Stunde und setzen den Standardwert auf 240. Bei einem Wert unter 500 erhält der virtuelle Betreiber die Antwort, dass die SIM-Karte nicht getauscht wurde. Werte über 500 führen zu einer positiven Sim Swap API-Antwort.

Schreiben des Go-Skripts zur Überprüfung eines SIM-Tauschs

Schritt 1: Einrichten der Importe und der Umgebung

Bevor wir API-Anfragen stellen können, müssen wir Go-Pakete für HTTP-Anfragen, JSON-Verarbeitung und die Verwaltung von Umgebungsvariablen einbinden. Außerdem werden wir unsere Anmeldeinformationen aus einer .env-Datei laden, damit wir keine sensiblen Informationen im Skript fest codieren.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

"github.com/golang-jwt/jwt/v5"
	"github.com/google/uuid"
	"github.com/joho/godotenv"
)

func loadEnv() {
	err := godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env file")
	}
}

Schritt 2: Authentifizierung mit JWT

Die Identity Insights API verwendet JWT (JSON Web Token) Authentifizierung. Ein JWT beweist Vonage, dass Ihre Anwendung die Erlaubnis hat, die Anfrage zu stellen.

Wir definieren eine Anmeldeinformationen Typ, um die Vonage Anwendungs-ID und den privaten Schlüssel zu speichern, und fügen eine NewCredentials Konstruktor hinzu, um sie zu laden, und verwenden dann eine Einzweckmethode GenerateJWT(ttl) um das Token zu erstellen und zu signieren. Auf diese Weise bleiben Datei-I/O, Validierung und Token-Erstellung sauber getrennt und sind leicht zu testen.

type Credentials struct {
  ApplicationID string
  PrivateKeyPEM []byte
}

func NewCredentials(applicationID, privateKeyPath string) (*Credentials, error) {
  if applicationID == "" {
    return nil, fmt.Errorf("missing VONAGE_APPLICATION_ID")
  }
  if privateKeyPath == "" {
    return nil, fmt.Errorf("missing VONAGE_PRIVATE_KEY_PATH")
  }
  pem, err := os.ReadFile(privateKeyPath)
  if err != nil {
    return nil, fmt.Errorf("read private key: %w", err)
  }
  return &Credentials{ApplicationID: applicationID, PrivateKeyPEM: pem}, nil
}

func (c *Credentials) GenerateJWT(ttl time.Duration) (string, error) {
  key, err := jwt.ParseRSAPrivateKeyFromPEM(c.PrivateKeyPEM)
  if err != nil {
    return "", fmt.Errorf("parse rsa key: %w", err)
  }

  now := time.Now()
  claims := jwt.MapClaims{
    "iat":            now.Unix(),
    "exp":            now.Add(ttl).Unix(),
    "jti":            uuid.NewString(),         
    "application_id": c.ApplicationID,
  }

  tok := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
  signed, err := tok.SignedString(key)
  if err != nil {
    return "", fmt.Errorf("sign jwt: %w", err)
  }
  return signed, nil
}

Schritt 3: Definieren von Sim-Swap-Strukturen

Um die JSON-Antwort der API sauber in Go zu verarbeiten, definieren wir eine Reihe von Structs, die die Struktur der SIM-Swap-Daten der Identity Insights API widerspiegeln.

Mit diesen Strukturen können wir die API-Antwort direkt in typisierte Go-Objekte zerlegen, was die Arbeit mit den Daten erleichtert:

type SimSwapStatus struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

type SimSwapDetails struct {
	Swapped       *bool         `json:"swapped,omitempty"`
	LastSimSwapAt string        `json:"latest_sim_swap_at,omitempty"`
	Status        SimSwapStatus `json:"status"`
}

type SimSwapResponse struct {
	RequestID string `json:"request_id"`
	Insights  struct {
		SimSwap SimSwapDetails `json:"sim_swap"`
	} `json:"insights"`
}

Schritt 4: Core-Sim-Swap-Funktion definieren

Nachdem die Authentifizierung geklärt ist, können wir uns mit der API verbinden. Die Funktion checkSimSwap bringt alles zusammen: Sie akzeptiert eine Telefonnummer, ein Zeitfenster (in Stunden), die API-URL und das JWT-Token, das Sie zuvor erzeugt haben.

Es geht um Folgendes:

  1. Bereiten Sie die Anfrage vor: Erstellen Sie einen JSON-Body, der die Telefonnummer, den Zweck der Betrugsprävention und den Zeitraum des SIM-Tauschs enthält.

  2. Sicherer Versand: Verwenden Sie http.NewRequest um eine POST-Anfrage zu erstellen, fügen Sie den JWT in der Autorisierung Header an und legen Sie den Inhaltstyp fest.

  3. Parsen der Antwort: Dekodieren des JSON in unsere SimSwapResponse Struktur, damit wir mit typisierten Feldern anstelle von rohem JSON arbeiten können.

  4. Interpretieren Sie das Ergebnis: Anhand des Statuscodes (OK, NO_COVERAGE, INTERNAL_ERROR)

func checkSimSwap(phoneNumber, hours, apiURL, jwtToken string) {
  reqBody := map[string]interface{}{
    "phone_number": phoneNumber,
    "purpose":      "FraudPreventionAndDetection",
    "insights": map[string]interface{}{
      "sim_swap": map[string]interface{}{
        "period": hours,
      },
    },
  }

  body, err := json.Marshal(reqBody)
  if err != nil {
    log.Fatal("Error marshaling request body:", err)
  }

  req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(body))
  if err != nil {
    log.Fatal("Error creating request:", err)
  }

  req.Header.Set("Authorization", "Bearer "+jwtToken)
  req.Header.Set("Content-Type", "application/json")

  client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
    log.Fatal("Error sending request:", err)
  }
  defer resp.Body.Close()

  var res SimSwapResponse
  if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
    log.Fatalf("Error decoding API response: %v", err)
  }

  switch res.Insights.SimSwap.Status.Code {
  case "OK":
    if res.Insights.SimSwap.Swapped != nil {
      if *res.Insights.SimSwap.Swapped {
        t, err := time.Parse(time.RFC3339, res.Insights.SimSwap.LastSimSwapAt)
        formatted := res.Insights.SimSwap.LastSimSwapAt
        if err == nil {
          formatted = t.Format("January 2, 2006 at 3:04 PM")
        }
        fmt.Printf("\n🚨 ALERT: SIM swap detected!\nLast swap occurred around: %s\n", formatted)
      } else {
        fmt.Println("\n✅ No SIM swap detected. The phone number appears to be secure.")
      }
    } else {
      fmt.Println("\n⚠️ Status was OK but swap status was missing.")
    }
  case "NO_COVERAGE":
    fmt.Println("\nℹ️ This phone number is not supported by the SIM swap check service.")
  case "INTERNAL_ERROR":
    fmt.Println("\n❌ An unexpected error occurred while checking the phone number. Please try again later.")
  default:
    fmt.Printf("\n❌ An unknown error occurred: %s\n", res.Insights.SimSwap.Status.Message)
  }
}

Schritt 5: CLI-Wrapper für Interaktivität

Um das Skript praktisch zu gestalten, verpacken wir es in eine main() Funktion, damit Sie es direkt ausführen können. Der CLI-Wrapper fordert den Benutzer zur Eingabe einer Telefonnummer und eines benutzerdefinierten Zeitraums auf oder greift auf die Standardeinstellung zurück. Er sendet dann die Anfrage an die Identity Insights API durch checkSimSwap an die Identity Insights API und gibt ein eindeutiges Ergebnis auf Ihrem Terminal aus.

Auf diese Weise können Sie verschiedene Numbers und Zeitfenster interaktiv testen, ohne den Code jedes Mal neu bearbeiten zu müssen. Später könnte die gleiche Logik in einen Webdienst oder ein Backend-System integriert werden.

func main() {
  loadEnv()

  apiURL := "https://api-eu.vonage.com/v0.1/identity-insights"
  phoneNumber := os.Getenv("PHONE_NUMBER")
  defaultHours := os.Getenv("DEFAULT_HOURS")
  applicationID := os.Getenv("VONAGE_APPLICATION_ID")
  privateKeyPath := os.Getenv("VONAGE_PRIVATE_KEY_PATH")

  creds, err := NewCredentials(applicationID, privateKeyPath)
  if err != nil {
    log.Fatal("Credentials error:", err)
  }
  jwtToken, err := creds.GenerateJWT(15 * time.Minute)
  if err != nil {
    log.Fatal("JWT error:", err)
  }

  fmt.Println("=== Vonage Identity Insights - SIM Swap Checker ===")
  fmt.Printf("Enter phone number [Default: %s]: ", phoneNumber)
  var phone string
  fmt.Scanln(&phone)
  if phone == "" {
    phone = phoneNumber
  }

  fmt.Printf("Enter number of hours to check for SIM swap [Default: %s]: ", defaultHours)
  var hours string
  fmt.Scanln(&hours)
  if hours == "" {
    hours = defaultHours
  }

  checkSimSwap(phone, hours, apiURL, jwtToken)
}

Testen des Skripts

Um das Skript auszuführen, verwenden Sie den folgenden Befehl in Ihrem Terminal:

go run main.go

Schlussfolgerung

Mit nur wenigen Zeilen Go und der Vonage Identity Insights API können Sie SIM-Swap-Aktivitäten erkennen, bevor sie sich zu einer umfassenden Account-Übernahme ausweiten. Dieser Ansatz eignet sich perfekt für Tests und kann für die Produktion angepasst werden, sobald Ihre Anwendung bei der Network Registry registriert ist.

Haben Sie eine Frage oder möchten Sie uns mitteilen, was Sie gerade bauen?

Bleiben Sie auf dem Laufenden und halten Sie sich über die neuesten Nachrichten, Tipps und Veranstaltungen für Entwickler auf dem Laufenden.

Teilen Sie:

https://a.storyblok.com/f/270183/384x384/e4e7d1452e/benjamin-aronov.png
Benjamin AronovAdvokat für Entwickler

Benjamin Aronov ist ein Entwickler-Befürworter bei Vonage. Er ist ein bewährter Community Builder mit einem Hintergrund in Ruby on Rails. Benjamin genießt die Strände von Tel Aviv, das er sein Zuhause nennt. Von Tel Aviv aus kann er einige der besten Startup-Gründer der Welt treffen und von ihnen lernen. Außerhalb der Tech-Branche reist Benjamin gerne um die Welt auf der Suche nach dem perfekten Pain au Chocolat.