Technical‐Architecture - capstone-hermes/hermes-fullstack GitHub Wiki

Technical Architecture

System Overview

The Weak Website follows a modern three-tier architecture with intentional security vulnerabilities for educational purposes. The system is containerized using Docker for easy deployment and isolation.

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   React Client  │◄──►│  NestJS Server  │◄──►│  MySQL Database │
│   (Port 8081)   │    │   (Port 8080)   │    │   (Port 3306)   │
└─────────────────┘    └─────────────────┘    └─────────────────┘
         │                       │                       │
         └───────────────────────┼───────────────────────┘
                                 │
                        ┌─────────────────┐
                        │ Docker Compose  │
                        │   Orchestration │
                        └─────────────────┘

Technology Stack

Frontend (Client)

  • Framework: React 18.3.1
  • Language: TypeScript 5.5.3
  • Build Tool: Vite 5.4.1
  • UI Library: ShadCN UI with Radix UI primitives
  • Styling: TailwindCSS 3.4.11
  • State Management: TanStack Query 5.56.2
  • Routing: React Router DOM 6.30.0
  • Form Handling: React Hook Form 7.53.0 + Zod validation

Backend (Server)

  • Framework: NestJS 10.0.0
  • Language: TypeScript 5.1.3
  • Database ORM: TypeORM 0.3.20
  • Authentication: JSON Web Tokens (jsonwebtoken 9.0.2)
  • Validation: class-validator 0.14.1
  • API Documentation: Swagger/OpenAPI (@nestjs/swagger 8.1.0)
  • Testing: Jest 29.5.0 + Supertest 7.0.0

Database

  • Engine: MySQL 8.0+
  • Connection: TypeORM with connection pooling
  • Schema Management: Auto-synchronization (development)
  • Data Persistence: Docker volumes

Infrastructure

  • Containerization: Docker + Docker Compose
  • Development: Hot-reload for both client and server
  • Production: Multi-stage Dockerfiles for optimization
  • Networking: Internal Docker network isolation

Project Structure

Repository Layout

hermes-fullstack/
├── weak-website/
│   ├── client/                 # React frontend application
│   ├── server/                 # NestJS backend application
│   ├── docker-compose.dev.yml  # Development configuration
│   └── README.md              # Project documentation
├── gui/                       # Scanner GUI application
├── web-scanner/              # Python vulnerability scanner
└── docker-compose.yml        # Multi-service orchestration

Client Architecture

client/
├── src/
│   ├── components/            # Reusable UI components
│   │   ├── ui/               # ShadCN UI component library
│   │   ├── Layout.tsx        # Main application layout
│   │   ├── PostForm.tsx      # Post creation form
│   │   ├── PostList.tsx      # Feed display component
│   │   └── ProtectedRoute.tsx # Authentication guard
│   ├── pages/                # Route-based page components
│   │   ├── Index.tsx         # Landing page
│   │   ├── Login.tsx         # Authentication page
│   │   ├── Signup.tsx        # User registration
│   │   ├── Dashboard.tsx     # User dashboard
│   │   ├── Feed.tsx          # Social feed
│   │   ├── FileUpload.tsx    # File upload interface
│   │   └── SecurityInfo.tsx  # Vulnerability documentation
│   ├── services/             # API communication layer
│   │   └── api.ts           # HTTP client and endpoints
│   ├── types/                # TypeScript type definitions
│   │   ├── auth.ts          # Authentication types
│   │   └── post.ts          # Post-related types
│   ├── utils/                # Utility functions
│   │   └── auth.ts          # Authentication helpers
│   ├── routes/               # Routing configuration
│   │   └── routes.tsx       # React Router setup
│   └── hooks/                # Custom React hooks
└── public/                   # Static assets

Server Architecture

server/
├── src/
│   ├── modules/              # Feature-based modules
│   │   ├── auth/            # Authentication & authorization
│   │   │   ├── auth.controller.ts
│   │   │   ├── auth.service.ts
│   │   │   ├── auth.module.ts
│   │   │   ├── jwt-auth.guard.ts
│   │   │   ├── password.helper.ts
│   │   │   └── dtos/
│   │   ├── user/            # User management
│   │   │   ├── user.controller.ts
│   │   │   ├── user.service.ts
│   │   │   ├── user.entity.ts
│   │   │   ├── user.module.ts
│   │   │   └── dtos/
│   │   ├── file/            # File upload/download
│   │   │   ├── file.controller.ts
│   │   │   └── file.module.ts
│   │   ├── input/           # Input validation demos
│   │   ├── redirect/        # URL redirection
│   │   └── validation/      # Validation examples
│   ├── post/                # Social posting feature
│   │   ├── post.controller.ts
│   │   ├── post.service.ts
│   │   ├── post.entity.ts
│   │   ├── post.module.ts
│   │   └── dtos/
│   ├── vulnerable-exception.filter.ts  # Error handling flaws
│   ├── vulnerable-params.middleware.ts # Parameter pollution
│   ├── app.module.ts        # Main application module
│   └── main.ts              # Application entry point
├── certs/                   # SSL certificates
├── test/                    # E2E and unit tests
└── dist/                    # Compiled JavaScript output

Data Flow Architecture

Request Processing Pipeline

1. Client Request
   │
   ├── React Component
   │   └── TanStack Query
   │       └── API Service Layer
   │
2. Network Layer
   │
   ├── HTTP Request (Axios)
   │   └── JSON Payload
   │
3. Server Processing
   │
   ├── NestJS Controller
   │   ├── Vulnerable Middleware (Parameter Pollution)
   │   ├── Route Handler
   │   └── DTO Validation (Minimal)
   │
4. Business Logic
   │
   ├── Service Layer
   │   ├── Raw SQL Queries (Vulnerable)
   │   └── Business Logic
   │
5. Data Persistence
   │
   ├── TypeORM Repository
   │   └── MySQL Database
   │
6. Response Generation
   │
   ├── Unfiltered Data
   │   └── Error Information Exposure
   │
7. Client Response
   │
   └── React State Update
       └── UI Re-render

Authentication Flow

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Client    │     │   Server    │     │  Database   │
└─────────────┘     └─────────────┘     └─────────────┘
        │                   │                   │
        │ POST /auth/login  │                   │
        ├──────────────────►│                   │
        │ {email, password} │                   │
        │                   │ Raw SQL Query     │
        │                   ├──────────────────►│
        │                   │ (SQL Injection)   │
        │                   │                   │
        │                   │ User Data         │
        │                   │◄──────────────────┤
        │                   │                   │
        │                   │ JWT Generation    │
        │                   │ (Hardcoded Secret)│
        │                   │                   │
        │ JWT Token         │                   │
        │◄──────────────────┤                   │
        │                   │                   │
        │ Subsequent        │                   │
        │ Requests with     │                   │
        │ Bearer Token      │                   │
        ├──────────────────►│                   │

Database Schema

Entity Relationship Diagram

┌─────────────────┐    ┌─────────────────┐
│      User       │    │      Post       │
├─────────────────┤    ├─────────────────┤
│ id (PK)         │◄───┤ id (PK)         │
│ email           │    │ content         │
│ password        │    │ userId (FK)     │
│ role            │    │ createdAt       │
│ createdAt       │    └─────────────────┘
└─────────────────┘

User Entity

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column()
  password: string; // Stored in plain text (vulnerability)

  @Column({ default: 'user' })
  role: string;

  @CreateDateColumn()
  createdAt: Date;

  @OneToMany(() => Post, post => post.user)
  posts: Post[];
}

Post Entity

@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @Column('text')
  content: string; // No sanitization (vulnerability)

  @Column()
  userId: number;

  @CreateDateColumn()
  createdAt: Date;

  @ManyToOne(() => User, user => user.posts)
  user: User;
}

Security Architecture (Intentionally Vulnerable)

Authentication Vulnerabilities

// auth.service.ts:24-26
async login(email: string, password: string) {
  // SQL Injection vulnerability
  const user = await this.userRepository.query(
    `SELECT * FROM user WHERE email = '${email}' AND password = '${password}'`
  );
  
  // Hardcoded JWT secret
  const token = jwt.sign({ userId: user[0].id }, 'hardcoded-secret');
  
  return { token };
}

Parameter Pollution Middleware

// vulnerable-params.middleware.ts
@Injectable()
export class VulnerableParamsMiddleware implements NestMiddleware {
  use(req: any, res: any, next: () => void) {
    // Last parameter wins - enables parameter pollution
    if (req.body && typeof req.body === 'object') {
      Object.keys(req.body).forEach(key => {
        if (Array.isArray(req.body[key])) {
          req.body[key] = req.body[key][req.body[key].length - 1];
        }
      });
    }
    next();
  }
}

File Upload Vulnerabilities

// file.controller.ts:38-52
@UseInterceptors(
  FileInterceptor('file', {
    storage: diskStorage({
      destination: './uploads',
      filename: (req, file, cb) => {
        // Use user-submitted filename directly (vulnerability)
        const filename = file.originalname;
        cb(null, filename);
      },
    }),
    // No file size limit (vulnerability)
    limits: {
      fileSize: 1024 * 1024 * 1000, // 1GB
    },
  }),
)

API Architecture

RESTful Endpoint Structure

/auth
├── POST /login              # User authentication
├── POST /signup             # User registration
└── POST /change-password    # Password modification

/users
├── GET /profile            # User profile information
└── POST /create            # User creation (admin)

/posts
├── GET /all               # Retrieve all posts
├── POST /create           # Create new post
└── DELETE /:id            # Delete post

/file
├── POST /upload           # File upload
├── GET /download/:filename # File download
├── GET /retrieve          # Path traversal endpoint
├── GET /remote            # Remote file inclusion
├── POST /execute          # Command injection
└── GET /backup/:filename  # Backup file access

/validation
├── GET /input             # Input validation demos
├── POST /reflect          # Reflection vulnerabilities
└── GET /header            # Header injection

/redirect
└── GET /to                # Open redirect vulnerability

Request/Response Flow

Client Request → Middleware → Controller → Service → Repository → Database
                     ↓
              Parameter Pollution
                     ↓
              Business Logic (Vulnerable)
                     ↓
              Raw SQL Execution
                     ↓
              Unfiltered Response ← Error Disclosure ← Exception Filter

Deployment Architecture

Docker Compose Configuration

services:
  db:
    image: mysql:latest
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
      - MYSQL_DATABASE=${DB_DATABASE}
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql

  server:
    build: ./server
    ports:
      - "8080:8080"
    depends_on:
      - db
    environment:
      - DB_HOST=db
      - JWT_SECRET=${JWT_SECRET}

  client:
    build: ./client
    ports:
      - "8081:8081"
    depends_on:
      - server
    environment:
      - VITE_SERVER_URL=http://localhost:8080

Network Architecture

Host Network
├── Client Container (8081)
├── Server Container (8080)
└── Database Container (3306)
     │
     └── Internal Docker Network
         ├── app-network (bridge)
         └── Volume: mysql-data

Environment Configuration

# Development
DB_HOST=db
DB_PORT=3306
DB_USER=user
DB_PASSWORD=password
DB_DATABASE=hermes-weak-website-db
JWT_SECRET=hardcoded-secret
SERVER_PORT=8080
CLIENT_PORT=8081

Performance Characteristics

Database Performance

  • Connection Pooling: TypeORM default pool (10 connections)
  • Query Optimization: None (intentionally inefficient)
  • Indexing: Minimal (only primary keys)
  • Transactions: Limited support

Server Performance

  • Concurrent Requests: Limited by security overhead
  • Memory Usage: Unoptimized for demonstration
  • Response Times: Degraded by vulnerable operations
  • Throughput: Reduced by extensive logging

Client Performance

  • Bundle Size: ~2MB (modern React stack)
  • Initial Load: ~3 seconds (unoptimized)
  • Runtime Performance: Good (React 18 features)
  • Caching: Browser cache only

Development Workflow

Local Development

# Client development
cd client
npm install
npm run dev  # http://localhost:8081

# Server development  
cd server
npm install
npm run start:dev  # http://localhost:8080

# Database
docker run -d \
  -e MYSQL_ROOT_PASSWORD=password \
  -e MYSQL_DATABASE=hermes-weak-website-db \
  -p 3306:3306 \
  mysql:latest

Build Process

# Production builds
cd client && npm run build
cd server && npm run build

# Docker builds
docker-compose up --build

Testing Strategy

  • Unit Tests: Jest for service layer logic
  • Integration Tests: Supertest for API endpoints
  • E2E Tests: Manual security testing
  • Vulnerability Testing: Intentional security flaw verification

Security Considerations

Intentional Vulnerabilities

The application deliberately implements these security flaws:

  • SQL injection in authentication
  • XSS in post content
  • Path traversal in file operations
  • Parameter pollution in all endpoints
  • Weak JWT implementation
  • Information disclosure in errors
  • Command injection in file operations

Isolation Requirements

  • Use Docker networks for isolation
  • Never expose to public networks
  • Implement firewall rules for container access
  • Monitor for accidental exposure

Monitoring and Logging

Application Logging

// Excessive logging for education
this.logger.log(`User logged in: ${email}:${password}`);
this.logger.log(`Token generated: ${token}`);
this.logger.log(`File uploaded: ${filename} by ${authorization}`);

Security Event Logging

  • Authentication attempts (including credentials)
  • File operations with full paths
  • SQL queries with user input
  • Error details with stack traces

Extensions and Customization

Adding New Vulnerabilities

  1. Create new module in server/src/modules/
  2. Implement vulnerable endpoint
  3. Add corresponding client interface
  4. Document vulnerability in wiki
  5. Add to OWASP ASVS mapping

Educational Enhancements

  • Add more OWASP Top 10 examples
  • Implement additional ASVS requirements
  • Create guided exploitation tutorials
  • Add vulnerability scanning integration

Next: Continue to Database Schema for detailed data modeling or API Reference for endpoint documentation.