Skip to content

MohamedMouloudj/LL-Rate-Limiter

Repository files navigation

HTTP Server with Authentication and Rate Limiting

A secure HTTP server implementation using libmicrohttpd, SQLite3, and libsodium that provides robust user authentication with session management and configurable rate limiting to prevent abuse.

Docker Support: A Dockerfile is provided for easy cross-platform deployment. If you don't have the required libraries installed or use a different OS, you can run this application using Docker. See the Docker Deployment section below.

Quick Start

Option 1: Docker (Recommended for All Platforms)

# Clone the repository
git clone https://github.com/MohamedMouloudj/LL-Rate-Limiter
cd LL-Rate-Limiter

# Start with docker-compose
docker-compose up -d

# Access the server
open http://localhost:8080

Option 2: Build from Source (Linux)

Requires: libmicrohttpd, libsqlite3, libsodium, build-essential

make
./server

Required Libraries

Before building, ensure the following libraries are installed:

On Ubuntu/Debian:

sudo apt-get update
sudo apt-get install libmicrohttpd-dev libsqlite3-dev libsodium-dev build-essential

Library Details:

  • libmicrohttpd - Lightweight HTTP server library (required)
  • libsqlite3 - Embedded SQL database engine (required)
  • libsodium - Modern cryptographic library for password hashing with Argon2id (required)
  • build-essential - GCC compiler and build tools (required)

On Other Systems:

Ensure you have equivalent packages:

  • GCC compiler
  • libmicrohttpd (HTTP server library)
  • SQLite3 (database)
  • libsodium (cryptographic functions - Argon2id password hashing)

Architecture Overview

The system is organized into modular components with clear separation of concerns:

┌─────────────────────────────────────────────────────────────┐
│                        HTTP Server                          │
│                  (libmicrohttpd - Port 8080)                │
└────────────────┬────────────────────────────────────────────┘
                 │
                 ├──► Rate Limiter ──► Database (rate_limit table)
                 │      - Checks IP-based request limits (form submissions only)
                 │      - Enforces temporary blocks
                 │
                 ├──► Session Manager ──► Database (sessions table)
                 │      - Creates secure random session IDs
                 │      - Validates sessions with IP binding
                 │      - Handles session expiration
                 │
                 ├──► Authentication Module
                 │      - Argon2id password hashing (libsodium)
                 │      - Input validation
                 │      │
                 │      └──► Database (users table)
                 │
                 └──► HTML Page Generator
                        - Register, Login, Dashboard, Error pages

Component Interaction

  1. HTTP Server (http_server.c): Core request handler using libmicrohttpd with thread-per-connection model

    • Routes incoming requests to appropriate handlers
    • Extracts client IP addresses for rate limiting
    • Manages POST data processing
    • Handles session state (simplified via URL parameters)
  2. Rate Limiter (rate_limiter.c): IP-based request tracking with configurable algorithms

    • Checks request count against configured limits for form submissions only
    • Blocks IPs that exceed thresholds
    • Supports both sliding and fixed window algorithms
  3. Session Manager (session.c): Secure session lifecycle management

    • Cryptographically secure random session ID generation (32 bytes → 64 hex chars)
    • IP address binding to prevent session hijacking
    • Automatic session expiration (30-minute inactivity, 24-hour absolute limit)
    • Periodic cleanup of expired sessions
  4. Authentication (auth.c): Secure user registration and login

    • Argon2id password hashing via libsodium with automatic salt generation
    • Input validation (username format, password length)
    • Credential verification with constant-time comparison
  5. Database (database.c): SQLite3 persistence layer

    • User account storage with Argon2id hashed passwords
    • Session storage with expiration tracking
    • Rate limit tracking per IP address
    • Automatic cleanup of expired entries
  6. Pages (pages.c): Dynamic HTML generation

    • Consistent styling across all pages
    • Error message display
    • Form handling for registration/login

Rate Limiter Configuration

The rate limiter can be easily configured through constants in include/rate_limiter.h:

Adjusting Request Limits

#define RATE_LIMIT_MAX_REQUESTS 10      // Maximum login/registration attempts
#define RATE_LIMIT_WINDOW_SECONDS 300   // Time window in seconds (5 minutes)

Note: Rate limiting only applies to form submissions (POST to /login and /register), not to page views.

Example configurations:

  • Strict: MAX_REQUESTS=5, WINDOW=600 (5 attempts per 10 minutes)
  • Moderate: MAX_REQUESTS=10, WINDOW=300 (10 attempts per 5 minutes - current)
  • Lenient: MAX_REQUESTS=20, WINDOW=300 (20 attempts per 5 minutes)

Switching Between Algorithms

#define USE_SLIDING_WINDOW 1  // 1 = Sliding Window, 0 = Fixed Window

Sliding Window Algorithm:

  • Continuously tracks requests within a rolling time window
  • More precise but slightly more complex
  • Request count resets gradually as old requests fall outside the window

Fixed Window Algorithm:

  • Resets counter at fixed intervals
  • Simpler implementation
  • Potential for burst traffic at window boundaries

After modifying these values, rebuild the project:

make rebuild

Available Routes

Route Method Description Authentication Required
/ GET Redirects to login page No
/register GET Display registration form No
/register POST Process new user registration No
/login GET Display login form No
/login POST Authenticate user credentials No
/dashboard GET Protected dashboard with user info Yes (session cookie)
/logout GET End session and clear cookie Yes (session cookie)
/too-many-requests GET Rate limit violation page No

Authentication Flow

  1. Registration: User submits username and password (minimum 8 characters)

    • Password is hashed with Argon2id (via libsodium) with automatic salt generation
    • Stored securely in database (128 bytes)
    • Redirected to login on success
  2. Login: User submits credentials

    • Password is verified using constant-time comparison against stored Argon2id hash
    • On success: secure session created with cryptographically random 64-character session ID
    • Session stored as HTTP-only cookie (not in URL)
    • Cookie attributes: HttpOnly; Path=/; Max-Age=86400; SameSite=Strict
    • Session bound to user's IP address to prevent hijacking
    • Redirected to clean URL: /dashboard (no session in URL)
    • On failure: error message displayed
  3. Dashboard Access: Requires valid session cookie

    • Browser automatically sends session cookie with each request
    • Session validated: checks expiration (30-min inactivity / 24-hour absolute) and IP match
    • Without valid session: redirected to login
    • Shows personalized welcome message and demo content
    • Session automatically renewed on each request (updates last_activity timestamp)
  4. Logout: User can explicitly end session

    • Access /logout to destroy session
    • Session removed from database
    • Cookie cleared with Max-Age=0
    • Redirected to login page

Rate Limiting Behavior

All requests are checked against rate limits:

  • If limit not exceeded: request proceeds normally
  • If limit exceeded:
    • IP is temporarily blocked for RATE_LIMIT_WINDOW_SECONDS
    • Error message displayed on the form
    • Block persists until window expires

Important: Rate limiting only applies to form submissions (POST requests to /login and /register). Page views (GET requests) are not rate limited, allowing users to browse freely.

Docker Deployment

Quick Start with Docker Compose

The easiest way to run the application across all platforms:

# Start the server
docker-compose up -d

# View logs
docker-compose logs -f

# Stop the server
docker-compose down

# Stop and remove data
docker-compose down -v

The server will be available at http://localhost:8080

Manual Docker Build

# Build the image
docker build -t rate-limiter .

# Run the container
docker run -d \
  --name rate-limiter \
  -p 8080:8080 \
  -v ./data:/app/data \
  rate-limiter

# View logs
docker logs -f rate-limiter

# Stop and remove
docker stop rate-limiter && docker rm rate-limiter

Configuration via Environment Variables

Customize rate limiting and server settings using environment variables:

docker run -d \
  --name rate-limiter \
  -p 8080:8080 \
  -e RATE_LIMIT_MAX_REQUESTS=20 \
  -e RATE_LIMIT_WINDOW_SECONDS=600 \
  -e RATE_LIMIT_ALGORITHM=sliding \
  -e HTTP_PORT=8080 \
  -e DB_PATH=/app/data/ratelimiter.db \
  -v ./data:/app/data \
  rate-limiter

Or update docker-compose.yml:

environment:
  - RATE_LIMIT_MAX_REQUESTS=20
  - RATE_LIMIT_WINDOW_SECONDS=600
  - RATE_LIMIT_ALGORITHM=fixed  # or "sliding"
  - HTTP_PORT=8080
  - DB_PATH=/app/data/ratelimiter.db

Available Environment Variables

Variable Default Description
RATE_LIMIT_MAX_REQUESTS 10 Maximum login/registration attempts
RATE_LIMIT_WINDOW_SECONDS 300 Time window in seconds (5 minutes)
RATE_LIMIT_ALGORITHM sliding Algorithm type: sliding or fixed
HTTP_PORT 8080 HTTP server port
DB_PATH /app/data/ratelimiter.db SQLite database file path

Data Persistence

The SQLite database is stored in a Docker volume to persist across container restarts:

  • docker-compose: Named volume ll-rate-limiter-data automatically created
  • Manual run: Use -v ./data:/app/data to mount local directory

Docker Image Details

  • Base Image: Alpine Linux 3.19 (minimal size)
  • Final Size: ~20-25 MB
  • Security: Runs as non-root user (UID 1000)
  • Architecture: Multi-stage build for optimization

Build Instructions (Native)

If you prefer to build and run natively without Docker:

Prerequisites

Install required libraries on Ubuntu/Debian:

sudo apt-get update
sudo apt-get install libmicrohttpd-dev libsqlite3-dev libsodium-dev build-essential

On other systems, ensure you have:

  • GCC compiler
  • libmicrohttpd (HTTP server library)
  • SQLite3 (database)
  • libsodium (cryptographic library for Argon2id password hashing)

Compilation

Build the project:

make

Other Makefile targets:

make clean      # Remove build artifacts and database
make rebuild    # Clean and rebuild from scratch
make run        # Build and start the server
make help       # Show all available targets

Running the Server

Start the server:

./server

Or use the Makefile:

make run

The server will:

  1. Initialize the SQLite database (server.db)
  2. Create necessary tables if they don't exist
  3. Start listening on port 8080
  4. Display configuration information

Access the server at: http://localhost:8080

Stop the server with Ctrl+C for graceful shutdown.

Database Schema

Users Table

Stores registered user accounts:

CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT UNIQUE NOT NULL,
    password_hash TEXT NOT NULL,
    created_at INTEGER DEFAULT (strftime('%s', 'now'))
);

Fields:

  • id: Unique user identifier (auto-incremented)
  • username: Unique username (alphanumeric, underscore, hyphen allowed)
  • password_hash: Argon2id hash of password (128 bytes with embedded salt)
  • created_at: Unix timestamp of account creation

Sessions Table

Stores active user sessions with security validation:

CREATE TABLE sessions (
    session_id TEXT PRIMARY KEY,
    username TEXT NOT NULL,
    ip_address TEXT NOT NULL,
    created_at INTEGER NOT NULL,
    last_activity INTEGER NOT NULL,
    expires_at INTEGER NOT NULL,
    FOREIGN KEY (username) REFERENCES users(username) ON DELETE CASCADE
);

CREATE INDEX idx_username ON sessions(username);
CREATE INDEX idx_expires_at ON sessions(expires_at);

Fields:

  • session_id: Cryptographically secure random 64-character hex string (primary key)
  • username: Associated user account
  • ip_address: Client IP bound to this session (prevents hijacking)
  • created_at: Unix timestamp when session was created
  • last_activity: Unix timestamp of last request (updated on each access)
  • expires_at: Unix timestamp when session expires (24 hours from creation)

Indexes:

  • idx_username: Fast lookup of all sessions for a user
  • idx_expires_at: Optimizes expired session cleanup

Session Lifecycle:

  • Created on successful login with 32 random bytes (→ 64 hex chars)
  • Validated on each dashboard access (checks expiration + IP match)
  • Expires after 30 minutes of inactivity OR 24 hours absolute
  • Destroyed on logout or automatic cleanup

Rate Limit Table

Tracks request counts and blocks per IP address:

CREATE TABLE rate_limit (
    ip_address TEXT PRIMARY KEY,
    request_count INTEGER DEFAULT 0,
    window_start INTEGER,
    blocked_until INTEGER DEFAULT 0,
    last_updated INTEGER
);

CREATE INDEX idx_blocked_until ON rate_limit(blocked_until);

Fields:

  • ip_address: Client IP address (primary key)
  • request_count: Number of requests in current window
  • window_start: Unix timestamp when current window began
  • blocked_until: Unix timestamp when block expires (0 if not blocked)
  • last_updated: Unix timestamp of last request

Index: idx_blocked_until optimizes blocked IP lookups

Database Operations

  • Automatic cleanup: Expired sessions and rate limit entries removed every 60 seconds
  • UPSERT operations: Efficiently handle existing/new records
  • Thread safety: SQLite handles concurrent access
  • Persistent storage: Database survives server restarts

Project Structure

LL-Rate-Limiter/
├── Makefile              # Build configuration
├── README.md             # This file
├── include/              # Header files
│   ├── auth.h           # Authentication function prototypes
│   ├── database.h       # Database operation prototypes
│   ├── http_server.h    # HTTP server prototypes
│   ├── pages.h          # HTML generation prototypes
│   ├── rate_limiter.h   # Rate limiter prototypes and config
│   └── session.h        # Session management prototypes
├── src/                  # Implementation files
│   ├── auth.c           # Authentication logic (Argon2id hashing)
│   ├── database.c       # SQLite operations
│   ├── http_server.c    # HTTP request handling
│   ├── main.c           # Entry point
│   ├── pages.c          # HTML page generation
│   ├── rate_limiter.c   # Rate limiting logic
│   └── session.c        # Session creation/validation
├── obj/                  # Object files (generated)
└── server.db            # SQLite database (generated)

Security Features

  • Password Hashing: Argon2id via libsodium with automatic salt generation and memory-hard key derivation
  • Cookie-Based Sessions: HTTP-only cookies prevent XSS attacks, sessions not exposed in URLs
  • Session Security: Cryptographically secure random session IDs (32 bytes → 64 hex chars)
  • Session Binding: IP address validation prevents session hijacking
  • Session Expiration: 30-minute inactivity timeout, 24-hour absolute expiration
  • CSRF Protection: SameSite=Strict cookie attribute prevents cross-site request forgery
  • Input Validation: Username and password requirements enforced
  • SQL Injection Prevention: Prepared statements for all queries
  • Rate Limiting: Prevents brute force and DoS attacks on login/registration
  • IP-based Blocking: Temporary bans for violators
  • Constant-time Comparison: Password verification resistant to timing attacks

Performance Characteristics

  • Threading Model: Thread-per-connection for good portability
  • Database: SQLite with indexed lookups for fast queries
  • Memory Management: Proper cleanup prevents leaks
  • Scalability: Suitable for moderate traffic loads

Limitations and Future Improvements

Current Limitations:

  • No HTTPS support (plain HTTP only - cookies should use Secure flag with HTTPS)
  • IPv4 only (no IPv6 support)

Troubleshooting

Port already in use:

# Find process using port 8080
sudo lsof -i :8080
# Kill the process
kill -9 <PID>

Missing libraries:

# Check if libraries are installed
pkg-config --libs libmicrohttpd sqlite3 libsodium
# Reinstall if needed
sudo apt-get install --reinstall libmicrohttpd-dev libsqlite3-dev libsodium-dev

Database permission errors:

# Ensure database file is writable
chmod 644 server.db

Compilation errors:

# Verify GCC is installed
gcc --version
# Clean and rebuild
make clean && make

License

This is a demonstration project for educational purposes.

Author

Mohamed Mouloud Created as part of Data Security coursework (Semester 7, 2025) - with my exaggeration :P - .

About

Implementation of web server along with rate limiter in C language. Tested against brute force.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages