
Partager:
Benjamin Aronov est un défenseur des développeurs chez Vonage. C'est un bâtisseur de communauté qui a fait ses preuves, avec une formation en Ruby on Rails. Benjamin apprécie les plages de Tel Aviv, où il vit. Sa base à Tel Aviv lui permet de rencontrer et d'apprendre de certains des meilleurs fondateurs de startups du monde. En dehors de la technologie, Benjamin aime voyager à travers le monde à la recherche du parfait pain au chocolat.
Détecter les fraudes par échange de cartes SIM avec Go et Vonage
Temps de lecture : 5 minutes
La plupart des comptes en ligne reposent encore sur le SMS pour l'authentification à deux facteurs (2FA). Mais que se passe-t-il si un fraudeur convainc votre opérateur de transférer votre numéro sur sa carte SIM (attaque par échange de carte SIM) ? Soudain, ces codes de sécurité censés vous protéger deviennent l'outil même utilisé contre vous.
Une vérification de l'échange de SIM ne remplace pas le 2FA ; elle indique à votre application si le SMS est toujours un canal sûr à utiliser. Dans ce tutoriel, nous allons vous montrer comment intégrer l'API Identity Insights de Vonage avec Go (Golang) pour détecter les échanges de cartes SIM en temps réel et protéger vos utilisateurs contre le détournement de compte.
>> TL;DR: Obtenir le code complet code complet sur GitHub.
Conditions préalables
Pour suivre, vous aurez besoin de
Un compte de développeur Vonage
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
Configuration du projet
Créer une application Vonage
Pour créer une application, allez à la page Créer une application sur le tableau de bord de Vonage, et définissez un nom pour votre application.
Si vous avez l'intention d'utiliser une API qui utilise des Webhooks, vous aurez besoin d'une clé privée. Cliquez sur "Générer une clé publique et privée", votre téléchargement devrait démarrer automatiquement. Conservez-la en lieu sûr ; cette clé ne peut pas être retéléchargée si elle est perdue. Elle suivra la convention de nommage suivante private_<votre identifiant d'application>.key. Cette clé peut maintenant être utilisée pour authentifier les appels à l'API. Remarque : votre clé ne fonctionnera pas tant que votre application n'aura pas été sauvegardée.
Choisissez les fonctionnalités dont vous avez besoin (par exemple, Voice, Messages, RTC, etc.) et fournissez les webhooks requis (par exemple, URL d'événement, URL de réponse ou URL de message entrant). Ces éléments seront décrits dans le tutoriel.
Pour sauvegarder et déployer, cliquez sur "Générer une nouvelle application" pour finaliser la configuration. Votre application est maintenant prête à être utilisée avec les API de Vonage.
L'API Identity Insights s'appuie sur des données de réseau mobile en direct pour détecter les échanges de cartes SIM. Activation du Registre du réseau dans votre Applications Vonage permet d'accéder à cette source de données. En production, cela nécessite l'approbation de l'opérateur, ce qui peut prendre du temps, mais le mode Playground vous permet de commencer les tests immédiatement.
Pour ce faire, créez une application Vonage dans le tableau de bord Vonage avec :
Activez la fonction Registre du réseau et sélectionnez "Terrain de jeu".
Générer une clé.privéevous devrez la déplacer à la racine de votre répertoire dans la section suivante
Configurer l'application Go
Dans votre terminal, exécutez les commandes suivantes pour créer un répertoire de projet et les fichiers nécessaires :
mkdir go_sim_swap_checker
cd go_sim_swap_checker
touch main.go .env>> Vous pouvez maintenant déplacer votre fichier clé.privée dans le fichier go_sim_swap_checker dans le répertoire de go_sim_swap_checker
Installer les dépendances
Dans le répertoire de votre projet, initialisez le module Go et installez les paquets nécessaires :
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/uuidgolang-jwt: Gère la génération de jetons JWT pour l'authentification de l'API
godotenv: Charge les variables d'environnement à partir d'un fichier .env
uuid: Génère des identifiants uniques pour chaque JWT, garantissant que chaque jeton peut être distingué en toute sécurité.
Configurez votre.env Fichier
Ouvrez le fichier .env dans votre éditeur de texte et ajoutez ce qui suit :
VONAGE_APPLICATION_ID=your_application_id
VONAGE_PRIVATE_KEY_PATH=./private.key
PHONE_NUMBER=+990123455
DEFAULT_HOURS=240Ajoutez votre ID d'application Vonage, un numéro de téléphone par défaut et la période de temps en heures pour la vérification de la permutation SIM.
L'opérateur virtuel Opérateur virtuel Vonage fournit 9 numéros de téléphone valides que vous pouvez utiliser pour effectuer des tests, ainsi qu'un numéro qui donne une réponse "inconnue".
Vous pouvez voir dans la Référence de l'API Identity Insights que l'aperçu de Sim swap repose sur un seul paramètre appelé périodeNous l'appellerons heure et nous fixerons la valeur par défaut à 240. Pour l'opérateur virtuel, les valeurs inférieures à 500 renverront une réponse indiquant que la carte SIM n'a pas été échangée. Les valeurs supérieures à 500 entraînent une réponse positive de l'API Sim Swap.
Écriture du script Go pour vérifier la permutation de la carte SIM
Étape 1 : Mise en place des importations et de l'environnement
Avant de pouvoir effectuer des requêtes API, nous devons intégrer des packages Go pour les requêtes HTTP, la gestion JSON et la gestion des variables d'environnement. Nous chargerons également nos informations d'identification à partir d'un fichier .env afin de ne pas coder en dur des informations sensibles dans le script.
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")
}
}
Étape 2 : Authentification avec JWT
L'API Identity Insights utilise JWT (JSON Web Token) l'authentification. Un JWT prouve à Vonage que votre application a la permission d'effectuer la demande.
Nous définirons un fichier Références qui contiendra l'identifiant de l'application Vonage et la clé privée, puis nous ajouterons un élément NewCredentials pour les charger, puis utiliser une méthode à usage unique GenerateJWT(ttl) pour créer et signer le jeton. Ainsi, les entrées/sorties de fichiers, la validation et la création de jetons sont clairement séparées et faciles à tester.
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
}
Étape 3 : Définir les structures d'échange de simulations
Pour gérer proprement la réponse JSON de l'API dans Go, nous allons définir un ensemble de structures qui reflètent la structure des données SIM Swap de l'API Identity Insights.
Ces structures nous permettront d'analyser la réponse de l'API directement en objets Go typés, ce qui facilitera l'utilisation des données :
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"`
}
Étape 4 : Définir la fonction Core Sim Swap
L'authentification étant réglée, connectons-nous à l'API. La fonction checkSimSwap rassemble tout : elle accepte un numéro de téléphone, une fenêtre temporelle (en heures), l'URL de l'API et le jeton JWT que vous avez généré plus tôt.
Voici ce qui se passe :
Préparer la demande : construire un corps JSON qui comprend le numéro de téléphone, l'objectif de prévention de la fraude et la période d'échange de la carte SIM.
Envoyez-le de manière sécurisée : utilisez http.NewRequest pour créer une requête POST, attachez le JWT dans le champ autorisation et définir le type de contenu.
Analyser la réponse : décoder le JSON dans notre SimSwapResponse afin de pouvoir travailler avec des champs typés plutôt qu'avec du JSON brut.
Interpréter le résultat : sur la base du code d'état (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)
}
}
Étape 5 : Enveloppe CLI pour l'interactivité
Pour rendre le script pratique, nous l'envelopperons dans une fonction main() afin que vous puissiez l'exécuter directement. Le wrapper CLI demande à l'utilisateur d'indiquer un numéro de téléphone et une période de temps personnalisée, ou de revenir à la valeur par défaut. Il envoie ensuite la demande à l'API Identity Insights par le biais de la fonction checkSimSwap et imprime un résultat clair sur votre terminal.
De cette manière, vous pouvez tester différents nombres et fenêtres temporelles de manière interactive sans avoir à modifier le code à chaque fois. Plus tard, la même logique pourra être intégrée dans un service web ou un système dorsal.
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)
}
Test du script
Pour exécuter le script, utilisez la commande suivante dans votre terminal :
go run main.go Conclusion
Avec seulement quelques lignes de Go et l'API Identity Insights de Vonage, vous pouvez détecter les activités d'échange de cartes SIM avant qu'elles ne se transforment en une prise de contrôle de compte à grande échelle. Cette approche est parfaite pour les tests et peut être adaptée à la production une fois que votre application est enregistrée auprès du registre du réseau.
Vous avez une question ou souhaitez partager ce que vous construisez ?
Rejoignez la conversation sur le Communauté Vonage Slack
S'abonner à la Bulletin d'information du développeur
Suivez-nous sur X (anciennement Twitter) pour les mises à jour
Regardez les tutoriels sur notre chaîne YouTube
Connectez-vous avec nous sur la page Vonage Developer sur LinkedIn
Restez connecté et tenez-vous au courant des dernières nouvelles, astuces et événements concernant les développeurs.
Partager:
Benjamin Aronov est un défenseur des développeurs chez Vonage. C'est un bâtisseur de communauté qui a fait ses preuves, avec une formation en Ruby on Rails. Benjamin apprécie les plages de Tel Aviv, où il vit. Sa base à Tel Aviv lui permet de rencontrer et d'apprendre de certains des meilleurs fondateurs de startups du monde. En dehors de la technologie, Benjamin aime voyager à travers le monde à la recherche du parfait pain au chocolat.
