Skip to content

Security: learnfrombasic/tinyurl-rs-service

Security

docs/security.md

Security Considerations

Input Validation and Sanitization

URL Validation

TinyURL-RS implements comprehensive URL validation to prevent malicious input:

URL Format Validation

// RFC-compliant URL parsing
match Url::parse(&self.url) {
    Ok(_) => {},
    Err(_) => return Err(AppError::InvalidUrl("Invalid URL format".to_string())),
}

Scheme Restrictions

  • Allowed: http://, https://
  • Blocked: javascript:, data:, file:, ftp://
  • Validation: Automatic scheme checking during URL parsing

Domain Validation

// Future enhancement: Domain blacklist checking
const BLOCKED_DOMAINS: &[&str] = &[
    "localhost",
    "127.0.0.1",
    "0.0.0.0",
    // Add malicious domains
];

Custom Code Validation

Character Restrictions

// Only allow alphanumeric characters and hyphens
if !code.chars().all(|c| c.is_alphanumeric() || c == '-') {
    return Err(AppError::Validation(
        "Custom code can only contain alphanumeric characters and hyphens".to_string()
    ));
}

Length Constraints

  • Minimum: 1 character
  • Maximum: 20 characters
  • Prevents: Buffer overflow and database constraints

SQL Injection Prevention

Parameterized Queries

All database operations use parameterized queries:

// Safe: Uses parameter binding
sqlx::query_as::<_, TinyUrl>(
    "SELECT * FROM tinyurls WHERE short_code = $1"
)
.bind(short_code)
.fetch_optional(&*self.pool)
.await

Query Construction

What NOT to do:

// VULNERABLE: String concatenation
let query = format!("SELECT * FROM tinyurls WHERE short_code = '{}'", user_input);

Safe approach:

// SAFE: Parameter binding
sqlx::query_as::<_, TinyUrl>(query_string)
    .bind(parameter)
    .fetch_optional(&pool)
    .await

Authentication and Authorization

Current State

  • No authentication required for basic operations
  • Suitable for: Internal networks, development, low-risk environments

Future Authentication Strategies

API Key Authentication

// Header-based API key validation
#[derive(Debug)]
pub struct ApiKeyAuth {
    key: String,
}

impl ApiKeyAuth {
    pub fn validate(&self, request_key: &str) -> bool {
        // Constant-time comparison to prevent timing attacks
        use subtle::ConstantTimeEq;
        self.key.as_bytes().ct_eq(request_key.as_bytes()).into()
    }
}

Rate Limiting

// Future: Implement rate limiting per API key/IP
pub struct RateLimiter {
    // Redis-based rate limiting
    // Window-based or token bucket algorithm
}

Data Protection

Database Security

Connection Security

# Use SSL/TLS for database connections
DATABASE_URL=postgresql://user:pass@host:5432/db?sslmode=require

Least Privilege Access

-- Create dedicated application user
CREATE USER tinyurl_app WITH PASSWORD 'secure_random_password';

-- Grant minimal required permissions
GRANT SELECT, INSERT, UPDATE, DELETE ON tinyurls TO tinyurl_app;
GRANT USAGE, SELECT ON SEQUENCE tinyurls_id_seq TO tinyurl_app;

-- Revoke unnecessary permissions
REVOKE ALL ON SCHEMA public FROM PUBLIC;

Redis Security

Authentication

# Use Redis AUTH
REDIS_URL=redis://username:password@redis-host:6379/0

Network Security

# Bind Redis to specific interface
bind 127.0.0.1 ::1

# Disable dangerous commands
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command KEYS ""

Network Security

TLS/SSL Configuration

Reverse Proxy Setup

server {
    listen 443 ssl http2;
    server_name yourdomain.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/private.key;
    
    # Modern TLS configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers off;
    
    # Security headers
    add_header Strict-Transport-Security "max-age=63072000" always;
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options DENY;
    add_header X-XSS-Protection "1; mode=block";

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Network Isolation

Docker Network Security

# docker-compose.yml
version: '3.8'
services:
  tinyurl-app:
    networks:
      - app-network
  postgres:
    networks:
      - app-network
    # Don't expose ports externally
  redis:
    networks:
      - app-network

networks:
  app-network:
    driver: bridge
    internal: true  # No external access

Denial of Service (DoS) Protection

Rate Limiting

Application-Level Rate Limiting

// Future implementation with Redis
use std::collections::HashMap;
use std::time::{Duration, Instant};

pub struct RateLimiter {
    requests: HashMap<String, Vec<Instant>>,
    max_requests: usize,
    window: Duration,
}

impl RateLimiter {
    pub fn check_rate_limit(&mut self, client_id: &str) -> bool {
        let now = Instant::now();
        let requests = self.requests.entry(client_id.to_string()).or_default();
        
        // Remove old requests outside the window
        requests.retain(|&time| now.duration_since(time) < self.window);
        
        if requests.len() >= self.max_requests {
            false // Rate limit exceeded
        } else {
            requests.push(now);
            true
        }
    }
}

Reverse Proxy Rate Limiting

# Nginx rate limiting
http {
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    
    server {
        location /shorten {
            limit_req zone=api burst=20 nodelay;
            proxy_pass http://localhost:8080;
        }
    }
}

Resource Limits

Request Size Limits

// In Actix-Web configuration
use actix_web::web;

App::new()
    .app_data(web::JsonConfig::default().limit(1024)) // 1KB limit
    .app_data(web::PayloadConfig::new(1024)) // 1KB payload limit

Connection Limits

// Database connection pooling prevents connection exhaustion
.max_connections(20)
.idle_timeout(Some(Duration::from_secs(600)))

Logging and Monitoring

Security Event Logging

Structured Logging

use serde_json::json;

// Log security events
log::warn!(
    "{}",
    json!({
        "event": "invalid_url_attempt",
        "url": sanitized_url,
        "client_ip": client_ip,
        "timestamp": chrono::Utc::now().to_rfc3339()
    })
);

Audit Trail

// Log all URL creation events
log::info!(
    "URL created: short_code={}, client_ip={}, user_agent={}",
    short_code,
    client_ip,
    user_agent
);

Monitoring Alerts

Security Metrics

  • Failed request rate spikes
  • Unusual traffic patterns
  • Database connection failures
  • Cache service unavailability

Log Analysis

# Monitor for suspicious patterns
tail -f /var/log/tinyurl-rs/app.log | grep -E "(ERROR|WARN|invalid_url)"

# Track request rates
grep "URL created" /var/log/tinyurl-rs/app.log | wc -l

Deployment Security

Container Security

Dockerfile Best Practices

# Use specific version tags
FROM rust:1.75-slim as builder

# Create non-root user
RUN useradd --create-home --shell /bin/bash app

# Install only necessary packages
RUN apt-get update && apt-get install -y --no-install-recommends \
    pkg-config \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

# Copy source and build
WORKDIR /app
COPY --chown=app:app . .
USER app
RUN cargo build --release

# Runtime stage
FROM debian:bookworm-slim
RUN useradd --create-home --shell /bin/bash app

# Install runtime dependencies only
RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY --from=builder --chown=app:app /app/target/release/tinyurl-rs .

USER app
EXPOSE 8080
CMD ["./tinyurl-rs"]

Environment Security

Secrets Management

# Use secrets management instead of environment variables
# AWS Secrets Manager, HashiCorp Vault, Kubernetes secrets

# Example with Kubernetes
kubectl create secret generic tinyurl-secrets \
  --from-literal=db-password=secure_password \
  --from-literal=redis-password=another_password

Environment Variable Security

# Avoid logging sensitive environment variables
export RUST_LOG=info  # Don't use debug in production
unset HISTFILE         # Disable command history for secrets

Incident Response

Security Incident Checklist

  1. Detection

    • Monitor logs for anomalies
    • Set up alerting for security events
    • Regular security scans
  2. Response

    • Isolate affected systems
    • Preserve logs and evidence
    • Assess scope of impact
    • Implement containment measures
  3. Recovery

    • Apply security patches
    • Update configurations
    • Reset compromised credentials
    • Restore from clean backups if needed
  4. Post-Incident

    • Conduct root cause analysis
    • Update security measures
    • Document lessons learned
    • Update incident response procedures

Contact Information

Maintain updated contact information for:

  • Security team
  • Infrastructure team
  • Database administrators
  • Cloud provider support
  • Legal/compliance team

These security measures provide defense-in-depth protection while maintaining the performance and usability of the TinyURL-RS service.

There aren’t any published security advisories