Build a Phishing Site Detector with NextJS and VirusTotal
Rashid
Posted on March 1, 2024
When applying for a tech job it is important to have a strong portfolio to impress the company. Especially for beginner developers the first impression of resume and projects are playing crucial role. The most common project types are To-do app, Weather app, Blog and etc. which is boring.
In this new series we will build unique and creative stuff and ship it to production. So, in this episode we’re going to build a simple app that will check phishing risk against provided URL.
We’re going to use a NextJS to build our app fast and ship it to production easily using Vercel. Each time we make a new commit Vercel will update our app so we don’t need to worry about deployment but only focus on building.
Why this project is great?
Because it involves many skills those required to have as a developer:
TypeScript.
Third-party integration.
Use of NextJS itself.
UI/UX skills.
Tailwind CSS (eh)
Deployment
What we are building?
This project is going to be a single page app that will let user to enter a URL. After user enters the URL, it should extract the domain and send it to third-party service which will check the phishing risk of that domain. Then, on the backend we need to evaluate the response from that service and display the result to the user with nice UI/UX interface.
Getting Started
Let’s start by creating a new NextJS project. I will be using latest version of NextJS which is version 14 at time of writing this post.
npx create-next-app@latest
It will prompt few questions to configure the NextJS project. I will select to use TypeScript, initialise the Tailwind CSS and use App router.
✔ What is your project named? … <your_app_name_here>
✔ Would you like to use TypeScript? … No / <u>**Yes**</u>
✔ Would you like to use ESLint? … No / <u>**Yes**</u>
✔ Would you like to use Tailwind CSS? … No / <u>**Yes**</u>
✔ Would you like to use `src/` directory? … <u>**No**</u> / Yes
✔ Would you like to use App Router? (recommended) … No / <u>**Yes**</u>
✔ Would you like to customize the default import alias(@/*)? … No / <u>**Yes**</u>
Now you should have initialised NextJS project ready to use.
Integration with VirusTotal
Virus Total is an online service that analyses suspicious files and URLs to detect types of malware and malicious content using antivirus engines and website scanners.
Create an account on VirusTotal to get an API key for interacting with their service programmatically.
Since we want to check domain safety we had to use Domain Report endpoint to gather deep analyse of the submitted domain.
We can test the endpoint with Postman to see which part of the response we need to calculate the risk of phishing. Here’s the results:
There are lots of useful information on domain analysis based on various needs. But for now, we will continue with selected part which will help us to calculate the risk.
Building Backend
Since we have all information about what we’re going to build, it’s time to put these knowledge into practice. First, create a new API route that will send request to VirusTotal:
app/api/virustotal/route.ts
import{calcRisk}from'@/utils/calcRiskcomponents'importaxiosfrom'axios'import{typeNextRequest}from'next/server'import{getDomain}from'tldts'exportasyncfunctionGET(request:NextRequest){consturlToAnalyze=request.nextUrl.searchParams.get('urlToAnalyze')if (!urlToAnalyze){returnnewResponse("URL must not be empty.",{status:400})}try{constdomain=getDomain(urlToAnalyze)constvirustotalRes=awaitaxios.get(`https://www.virustotal.com/api/v3/domains/${domain}`,{headers:{"x-apikey":process.env.VIRUSTOTAL_API_KEY}})conststats=calcRisk(virustotalRes?.data?.data?.attributes?.last_analysis_stats)returnResponse.json({stats:stats})}catch (err){returnnewResponse("Internal Server Error",{status:500})}}
This route will handle the GET request that will be sent from frontend part of our app. Let’s break down the code:
Validating if required search param named urlToAnalyze is present. This param should be URL that provided by user.
If urlToAnalyze is present then we will extract the domain from that URL using npm module named tldts.
Then, based on VirusTotal docs we’re sending the domain to gather analysis report. Also we’re including the API Key in the headers.
We have a helper util function calcRisk which will evaluate the result of last_analysis_stats part from the response.
So, the calcRisk is a simple helper function that will determine if URL is risky or not. You can change the logic as you want such as assigning weights to the states of analysis. I would mark the domain “High Risk” even if there are only single report from antivirus engines or scanners.
Cool, that’s all for backend. Now, let’s move on to frontend part.
Building Frontend
We’re using app router in our NextJS project, so we should create the pages as <folder-name>/page.tsx which in this case I will create it as check-site/page.tsx. That will be routable on browser as /check-site.
If I would be brutally honest, Tailwind CSS is something that I don’t prefer but it’s useful for small projects like this.
And yes, I generated the tailwind code with ChatGPT.
Result
Now, we have full working, single feature app that will analyse the phishing risk of submitted URL. Here’s how it looks when you run the app:
What’s next?
You need to deploy your NextJS to Vercel to make it publicly accessible for others. Also, remember to explain your solution well in ReadMe file since it shows that you’re documenting your work.