https://a.storyblok.com/f/270183/1368x665/72fccf48d3/26mar_dev-blog_sim-swap-burner.jpg

Prevent Account Takeover Fraud with the Vonage SIM Swap Insight

Time to read: 6 minutes

Introduction

We all have business and personal accounts registered on several online websites and applications. Account takeover occurs when attackers hijack accounts using stolen credentials, SIM swaps, or phishing. In this blog post, I will demonstrate how to use Vonage SIM Swap Insight to verify phone numbers during login. Even if the hijacker has the correct combination of user and password credentials, we’ll have an additional SIM Swap check in place.

Prerequisites

Source Code

Note: Check that your Communication Service Provider and Country are supported in this available list.

What is SIM Swap Fraud?

You may use, or know someone who uses, their phone to authenticate their identity across various accounts, like a bank or social media. 

SIM swap fraud occurs when a malicious actor impersonates a victim and convinces a Mobile Network Operator to link the victim’s phone number to a new SIM card. Bad actors often persuade telecom operators through social engineering, using personal information obtained via phishing or data breaches. The attacker then intercepts the delivery of the new SIM card or activates the eSIM, gaining control of the victim’s number.

Consider what this bad actor can do: intercept SMS messages, reset passwords, make and receive phone calls, access accounts protected by two-factor authentication, and much more.

Create a Vonage Application

Now that we understand what SIM Swap is, let’s create the Vonage application to make use of the Vonage SIM Swap Insight and our demonstration web app solution.

  • To create an application, go to the Create an Application page on the Vonage Dashboard, and define a Name for your Application.

  • If you intend to use an API that uses Webhooks, you will need a private key. Click “Generate public and private key”, your download should start automatically. Store it securely; this key cannot be re-downloaded if lost. It will follow the naming convention private_<your app id>.key. This key can now be used to authenticate API calls. Note: Your key will not work until your application is saved.

  • Choose the capabilities you need (e.g., Voice, Messages, RTC, etc.) and provide the required webhooks (e.g., event URLs, answer URLs, or inbound message URLs). These will be described in the tutorial.

  • To save and deploy, click "Generate new application" to finalize the setup. Your application is now ready to use with Vonage APIs.

Select the Network Registry Capability

When working with the Network-powered features in Identity Insights APIs, there are two different environments:

  • The Production environment returns live data from the supported Operators in some countries. Access to the production environment requires approval from the Mobile Operators. You can learn how to request access.

  • The Playground is a safe, controlled testing environment in which API calls return live data only to a small set of allowlisted phone numbers. It does not require approval from the Network Operators. Additionally, the Playground provides access to the Virtual Operator, a simulated Operator that generates fake but deterministic responses. 

On the application creation step, toggle ‘Network Registry’ capability, select ‘Playground’, and click to create the application in the bottom right of the page.

Network Registry capability on the dashboard, you can choose two access types: playground or production.Network Registry Capability

Update the Environment Variables File

Copy it from the .env.example file, create a new .env file for your project, and add the environment variables in the code snippet below.

# .env

VONAGE_APPLICATION_ID=your_application_id
VONAGE_PRIVATE_KEY=Paste the private key file you just downloaded into your project directory, then provide the path to it in this field (e.g., ./private_your-app-id-here.key)
PERIOD=300

Note: Refer to Michael's blog post for an explanation of using environment variables in Node.js.

Install the Dependencies

In the project's package.json file, you will find the following dependencies: Vonage Identity Insights SDK for Node.js, Vonage Auth SDK for Node.js, Vonage Server SDK for Node.js, dotenv, express, and nodemon. All can be installed with one command from the command line.

npm install 

The Server.js File

The server.js file handles user registration and login, and adds the SIM Swap Insight from the Vonage Identity Insights API to detect SIM Swap fraud. The server runs on port 3000.

We require the dependencies you've installed, as described in the "Install the Dependencies" section of this blog post.

require("dotenv").config();
const path = require("path");
const express = require("express");
const { IdentityInsights } = require("@vonage/identity-insights");
const fs = require("fs");

We initialize Express and configure it to serve static files from the public folder.

const app = express();
app.use(express.json());
app.use(express.static("public"));

We create a user variable initialized to an empty value that will be populated once the user registers on the webpage. This user data is not persisted, so every time you stop the server, the information is cleared.

const users = {};

Initialization and Configuration

We load three environment variables: VONAGE_APPLICATION_ID, VONAGE_PRIVATE_KEY, and PERIOD (which specifies the number of hours to check for SIM swap events). We then perform a bootstrap step to verify that the application ID and private key are configured; if not, the server exits. Otherwise, it reads the private key from the file path or environment variable and initializes the identityClient with both values.

if (!APPLICATION_ID || !PRIVATE_KEY) {
 console.error('VONAGE_APPLICATION_ID or VONAGE_PRIVATE_KEY not set');
 process.exit(1);
}

const keyContent = fs.existsSync(PRIVATE_KEY)
 ? fs.readFileSync(PRIVATE_KEY, 'utf8')
 : PRIVATE_KEY;

if (!keyContent) {
 console.error('INVALID private key. Check if the file exists or the environment variable is correctly set');
 process.exit(1);
}

const identityClient = new IdentityInsights({
 applicationId: APPLICATION_ID,
 privateKey: keyContent,
});

SIM Swap Detection Function

The checkSimSwapWithIdentityInsights() function is an async function that queries the Vonage Identity Insights API for SIM swap information. It accepts a phone number and a period (in hours), then sends a request with multiple insights enabled: format, originalCarrier, currentCarrier, and simSwap.

For the purpose of this blog post, we're passing all of them as empty objects and only using the SIM Swap Insight. The period value is converted to an integer before being sent to the API.

If the SIM swap check returns true (meaning a SIM swap occurred within the specified period), the login is blocked. If an API call fails, the API logs a warning but allows the application to continue.

async function checkSimSwapWithIdentityInsights(phoneNumber, period) {
 try {
   const resp = await identityClient.getIdentityInsights({
     phoneNumber: phoneNumber,
     purpose: 'FraudPreventionAndDetection',
     insights: {
       format: {},
       originalCarrier: {},
       currentCarrier: {},
       simSwap: {
         period: parseInt(period)
       }
     }
   });

   return resp.insights?.simSwap?.isSwapped === true;
 } catch (error) {
   console.warn('Identity Insights SDK call failed:', error && error.message);
 }
}

Routes and Endpoints

The server has four main routes. The first one serves index.html, where users can log in or register, and the second one serves main.html, the welcome page after successful authentication.

app.get("/", (_req, res) => {
 res.sendFile(path.join(__dirname, "views/index.html"));
});

app.get("/main", (_req, res) => {
 res.sendFile(path.join(__dirname, "views/main.html"));
});

The /register endpoint handles new user registration with validation checks. It ensures the username doesn't already exist and prevents the same phone number from being registered to multiple accounts. If the registration is valid, it is stored in the users object.

app.post("/register", (req, res) => {
 const { username, password, phoneNumber } = req.body;

 if (users[username]) {
   return res
     .status(400)
     .json({ message: "Sorry, this username already exists." });
 }

 const phoneExists = Object.values(users).some(
   (user) => user.phoneNumber === phoneNumber
 );

 if (phoneExists) {
   return res.status(400).json({
     message: "This phone number is associated with another account.",
   });
 }

 users[username] = { username, password, phoneNumber };
 res.json({ message: "Registration success!" });
});

The /login endpoint is async and handles authentication with SIM swap protection. It first verifies that the username exists in the system and validates that the password matches. Only after both checks pass does it call the SIM swap detection function with the configured period.

app.post("/login", async (req, res) => {
 try {
   const { username, password } = req.body;
   const user = users[username];

   if (!user) {
     return res.status(404).json({ message: "Not Found" });
   }

   console.log("Attempting SIM swap check on phone number:", user.phoneNumber);

   if (user.password !== password) {
     return res
       .status(401)
       .json({ message: "This is an invalid username or password" });
   }

   const simSwapped = await checkSimSwapWithIdentityInsights(user.phoneNumber, PERIOD);

   if (simSwapped) {
     return res
       .status(401)
       .json({ message: "SIM Swap: true", simSwapped: true });
   }

   res.json({ message: "Success" });
 } catch (err) {
   console.error("Login error:", err);

   if (err.response && err.response.text) {
     const body = await err.response.text();
     console.error("Vonage SIM Swap API response:", body);
   }

   res.status(500).json({ message: "Internal Server Error" });
 }
});

In this tutorial, we check for potential burner accounts. I also wanted to mention that the SIM Swap Insight provides real-time verification of a SIM card's activation date on the mobile network across EU and US endpoints.

You can also check the Identity Insights (SIM Swap) Insight Reference page, which includes the OpenAPI specification.

The index.html Page

The content page for index.html lets you create a new user and enter a username, password, and phone number. We will add a check to ensure the same phone number is not added to two different accounts as a first step to reduce the risk of creating duplicate accounts with the same phone number. You can then log in with the credentials you’ve created.

The client.js File

The information we added to the HTML page will be passed to the client.js file once the form is submitted. This then sends the data to the server.js endpoints to handle registration, login, and SIM swap checks. If the login is successful, the user will be redirected to /main.html.

See it in Action

Run the server JavaScript file to initialize the web application.

npm run start:dev

Go ahead and test it by creating a new user and logging in. You can use the Virtual Operator; 10 phone numbers are available for testing: +990123400, +990123411, +990123422, +990123433, +990123444, +990123455, +990123466, +990123477, +990123488, and +990123499. 

Each of these test numbers has a “latest_sim_swap_at” value. You can use that number of hours as the value of the period environment variable to test for a true or false SIM swap scenario.

If you have Network Registry approval and a phone number from an accepted CSP, you can select the production option in the dashboard and test it with the real phone number, setting the environment variable period to detect a SIM Swap.

Get Started with Identity Insights

Within the Vonage Dashboard, you can find the Identity Insights Playground, which allows you to experiment with not only the SIM Swap Insight as shown in this blog post but also other insights. Enter a phone number, select the relevant data points, and receive the requested insights.

You can find two test modes: “Demo”, which lets you pick from a set of predefined phone numbers to experiment with the API using simulated examples, in addition to “Live”, in which you can choose your application and test phone numbers to try out real interactions based on supported features.

Conclusion

Congratulations, you've reached the end of this tutorial. We’ve focused on the SIM Swap Insight, but there are many other insights available for you to explore. Check out the Identity Insights Playground and learn how to gather further information.

Share:

https://a.storyblok.com/f/270183/400x400/3f6b0c045f/amanda-cavallaro.png
Amanda CavallaroDeveloper Advocate