Categories We Write About

Build a secure link shortener

Building a secure link shortener involves a few key steps to ensure that the system is safe, reliable, and efficient. Here’s an outline of the process:

1. Set Up the Backend

Start by choosing your tech stack. Common choices include:

  • Backend Frameworks: Node.js (Express), Django (Python), or Flask (Python).

  • Database: A relational database like MySQL, PostgreSQL, or a NoSQL database like MongoDB.

  • Hosting/Server: A cloud provider like AWS, DigitalOcean, or Heroku.

For this example, let’s assume you’re using Node.js and MongoDB.

2. Design the URL Shortener Database Schema

You need to store the original URLs and their shortened versions. A simple schema might look like this:

  • id: A unique identifier (the shortened part of the URL).

  • original_url: The full URL the user wants to shorten.

  • created_at: Timestamp when the URL was shortened.

  • expires_at: An optional expiration date for links.

  • clicks: A counter for how many times the link has been clicked.

javascript
const mongoose = require('mongoose'); const linkSchema = new mongoose.Schema({ id: { type: String, required: true, unique: true }, original_url: { type: String, required: true }, created_at: { type: Date, default: Date.now }, expires_at: { type: Date }, clicks: { type: Number, default: 0 } }); const Link = mongoose.model('Link', linkSchema);

3. Generate Shortened Links

Use a method to generate unique, short identifiers. You could use a combination of random characters, base62 encoding, or hashing algorithms.

javascript
const crypto = require('crypto'); function generateShortLink() { return crypto.randomBytes(6).toString('base64').slice(0, 8); // Generates a random 8-character string. }

Alternatively, use Base62 encoding for a URL-safe shortened ID.

4. Create the API Endpoints

You’ll need at least two endpoints:

  1. Create Short Link: To shorten the URL.

  2. Redirect to Original URL: To handle redirections when a user accesses a shortened link.

Endpoint: Create Short Link

javascript
const express = require('express'); const app = express(); const bodyParser = require('body-parser'); app.use(bodyParser.json()); app.post('/shorten', async (req, res) => { const { original_url } = req.body; // Validate URL const urlRegex = /^(https?|ftp)://[^s/$.?#].[^s]*$/i; if (!urlRegex.test(original_url)) { return res.status(400).json({ error: 'Invalid URL' }); } const shortId = generateShortLink(); const expiresAt = new Date(); expiresAt.setDate(expiresAt.getDate() + 30); // Link expires after 30 days (optional) const newLink = new Link({ id: shortId, original_url: original_url, expires_at: expiresAt }); try { await newLink.save(); res.status(201).json({ short_url: `http://yourdomain.com/${shortId}` }); } catch (err) { res.status(500).json({ error: 'Internal Server Error' }); } });

Endpoint: Redirect to Original URL

javascript
app.get('/:shortId', async (req, res) => { const { shortId } = req.params; try { const link = await Link.findOne({ id: shortId }); if (!link) { return res.status(404).json({ error: 'Link not found' }); } // Check if link has expired if (link.expires_at && new Date() > link.expires_at) { return res.status(410).json({ error: 'Link has expired' }); } // Update click count link.clicks++; await link.save(); // Redirect to original URL res.redirect(link.original_url); } catch (err) { res.status(500).json({ error: 'Internal Server Error' }); } });

5. Security Considerations

  • Rate Limiting: Protect against abuse by limiting the number of links a user can shorten in a given time period.

    • You can use libraries like express-rate-limit to limit requests.

javascript
const rateLimit = require('express-rate-limit'); const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // Limit each IP to 100 requests per windowMs message: 'Too many requests, please try again later' }); app.use(limiter);
  • Validating URLs: Ensure that the URLs submitted are valid and do not point to potentially harmful or malicious websites.

    • Use libraries like valid-url to validate the structure of URLs.

javascript
const validUrl = require('valid-url'); if (!validUrl.isUri(original_url)) { return res.status(400).json({ error: 'Invalid URL' }); }
  • Blacklist URLs: You can implement a blacklist for known malicious websites.

javascript
const blacklist = ['http://maliciouswebsite.com', 'http://phishing.com']; if (blacklist.includes(original_url)) { return res.status(400).json({ error: 'URL is blacklisted' }); }
  • HTTPS: Make sure to serve the API and the short links over HTTPS to ensure that data is encrypted in transit.

6. Analytics and Tracking (Optional)

You can add tracking features like counting how many times the link was clicked, tracking the geographical location of users, or seeing which browsers are being used. This can be useful for users to track the performance of their shortened links.

javascript
app.get('/analytics/:shortId', async (req, res) => { const { shortId } = req.params; try { const link = await Link.findOne({ id: shortId }); if (!link) { return res.status(404).json({ error: 'Link not found' }); } res.json({ original_url: link.original_url, clicks: link.clicks, created_at: link.created_at, expires_at: link.expires_at }); } catch (err) { res.status(500).json({ error: 'Internal Server Error' }); } });

7. Frontend (Optional)

For the frontend, you can create a simple HTML form where users can input their long URL, and the application will return the shortened URL.

html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>URL Shortener</title> </head> <body> <form id="shortenForm"> <input type="text" id="url" placeholder="Enter URL to shorten" required /> <button type="submit">Shorten</button> </form> <p id="shortUrl"></p> <script> document.getElementById('shortenForm').addEventListener('submit', async (event) => { event.preventDefault(); const url = document.getElementById('url').value; const response = await fetch('http://yourdomain.com/shorten', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ original_url: url }) }); const data = await response.json(); if (response.ok) { document.getElementById('shortUrl').innerHTML = `Shortened URL: <a href="${data.short_url}">${data.short_url}</a>`; } else { document.getElementById('shortUrl').textContent = `Error: ${data.error}`; } }); </script> </body> </html>

8. Deploy the Application

After you’ve implemented the above steps, deploy your application using services like Heroku, DigitalOcean, or AWS. Make sure to set up proper environment variables for sensitive information like your database credentials and any API keys.


This is a basic implementation of a secure link shortener. There are many ways you can extend this project, such as adding user authentication, setting custom aliases for short URLs, or even implementing machine learning models to detect malicious URLs.

Share This Page:

Enter your email below to join The Palos Publishing Company Email List

We respect your email privacy

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Categories We Write About