Lesson 24-Deno Encryption and Security

Digital security is a cornerstone of modern application development. Deno, with its modern security model and rich cryptographic libraries, provides developers with a powerful toolkit for building secure applications. This tutorial delves into Deno’s encryption techniques and security practices, from fundamental algorithms to advanced security architectures, demonstrating how to protect sensitive data and mitigate common attacks through code examples.

Deno Security Model Basics

Deno’s Security Sandbox

Core Security Principles
Deno enforces a strict security sandbox by default, requiring explicit permission declarations for all system-level operations:

// Default behavior without permissions
Deno.readFile("secret.txt"); // Throws error: Requires --allow-read permission

// Explicitly grant permissions
deno run --allow-read secret_reader.ts

Permission Categories

Permission TypeScopeExample Flag
File SystemRead/write files/directories--allow-read --allow-write
NetworkNetwork access--allow-net --allow-conn
Environment VariablesRead/write environment variables--allow-env
SubprocessExecute external commands--allow-run
PluginsLoad native plugins--allow-plugin

Security Best Practices

Applying the Principle of Least Privilege

# Unsafe: Overly permissive
deno run --allow-all sensitive_app.ts

# Safe: Precise permissions
deno run --allow-read=/etc/config.json --allow-net=api.trusted.com app.ts

Protecting Sensitive Operations

// Secure password input example (avoid console echo)
import { Input } from "https://deno.land/x/cliffy@v0.25.7/prompt/input.ts";

const password = await Input.prompt({
  message: "Enter password:",
  hidden: true // Hide input content
});

Encryption Algorithm Implementations

Hashing Algorithms

Password Hashing

// bcrypt password hashing example
import { hash, compare } from "https://deno.land/x/bcrypt@v0.4.1/mod.ts";

// Generate secure hash (auto-salted)
const password = "securePassword123";
const hashed = await hash(password, 12); // Cost factor 12

console.log("Hashed password:", hashed);

// Verify password
const isMatch = await compare(password, hashed);
console.log("Password match:", isMatch);

Data Integrity Verification

// SHA-256 hash verification
import { createHash } from "https://deno.land/std@0.224.0/crypto/mod.ts";

const fileData = await Deno.readFile("important.pdf");
const hash = createHash("sha256").update(fileData).digest();

console.log("File hash:", new TextEncoder().encode(hash).toString());

Symmetric Encryption

AES Encryption Implementation

// AES-GCM encryption example
import { crypto } from "https://deno.land/std@0.224.0/crypto/mod.ts";

// Generate random key (256-bit)
const key = await crypto.subtle.generateKey(
  { name: "AES-GCM", length: 256 },
  true,
  ["encrypt", "decrypt"]
);

// Encrypt data
const plaintext = new TextEncoder().encode("Sensitive data");
const nonce = crypto.getRandomValues(new Uint8Array(12));
const ciphertext = await crypto.subtle.encrypt(
  { name: "AES-GCM", iv: nonce },
  key,
  plaintext
);

// Decrypt data
const decrypted = await crypto.subtle.decrypt(
  { name: "AES-GCM", iv: nonce },
  key,
  ciphertext
);
console.log("Decrypted:", new TextDecoder().decode(decrypted));

Asymmetric Encryption

RSA Key Pair Management

// RSA key generation and encryption
import { crypto } from "https://deno.land/std@0.224.0/crypto/mod.ts";

// Generate 2048-bit RSA key pair
const { publicKey, privateKey } = await crypto.subtle.generateKey(
  {
    name: "RSA-OAEP",
    modulusLength: 2048,
    publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    hash: "SHA-256",
  },
  true,
  ["encrypt", "decrypt"]
);

// Encrypt with public key
const message = new TextEncoder().encode("Confidential message");
const encrypted = await crypto.subtle.encrypt(
  { name: "RSA-OAEP" },
  publicKey,
  message
);

// Decrypt with private key
const decrypted = await crypto.subtle.decrypt(
  { name: "RSA-OAEP" },
  privateKey,
  encrypted
);
console.log("Decrypted:", new TextDecoder().decode(decrypted));

Advanced Security Protocols

TLS/SSL Configuration

Secure HTTP Server

// HTTPS server configuration
import { serveTls } from "https://deno.land/std@0.224.0/http/server.ts";

const server = serveTls({
  port: 443,
  cert: await Deno.readTextFile("./fullchain.pem"), // Certificate chain file
  key: await Deno.readTextFile("./privkey.pem"),    // Private key file
});

console.log("Secure server running on https://localhost:443");

for await (const req of server) {
  await req.respond({
    status: 200,
    body: "Secure connection established\n",
  });
}

// Generate self-signed certificate (for development)
// openssl req -x509 -newkey rsa:4096 -nodes \
//   -keyout privkey.pem -out fullchain.pem -days 365

Secure Tokens

JWT Implementation

// JWT generation and verification
import { create, getNumericDate, verify } from "https://deno.land/x/djwt@v3.0.2/mod.ts";
import { crypto } from "https://deno.land/std@0.224.0/crypto/mod.ts";

// Key configuration (use a more secure key in production)
const key = await crypto.subtle.generateKey(
  { name: "HMAC", hash: "SHA-256" },
  true,
  ["sign", "verify"]
);

// Generate token
const payload = {
  iss: "your-app",
  exp: getNumericDate(60), // Expires in 60 seconds
  sub: "user123",
  role: "admin",
};

const token = await create({ alg: "HS256", typ: "JWT" }, payload, key);
console.log("Generated JWT:", token);

// Verify token
try {
  const decoded = await verify(token, key);
  console.log("Token valid:", decoded);
} catch (err) {
  console.error("Token invalid:", err.message);
}

Key Management

Secure Key Storage

// Manage keys using environment variables (use dedicated key management service in production)
const encryptionKey = Deno.env.get("ENCRYPTION_KEY");
if (!encryptionKey || encryptionKey.length !== 32) {
  throw new Error("Invalid encryption key configuration");
}

// Use key for encryption operations
const key = await crypto.subtle.importKey(
  "raw",
  new TextEncoder().encode(encryptionKey),
  { name: "AES-GCM" },
  false,
  ["encrypt", "decrypt"]
);

Key Rotation Strategy

// Key version management example
interface KeyVersion {
  id: string;
  key: CryptoKey;
  expiry: Date;
}

class KeyManager {
  private keys: KeyVersion[] = [];

  async rotateKey() {
    const newKey = await crypto.subtle.generateKey(
      { name: "AES-GCM", length: 256 },
      true,
      ["encrypt", "decrypt"]
    );
    const expiry = new Date();
    expiry.setHours(expiry.getHours() + 24); // Expires in 24 hours

    this.keys.push({
      id: crypto.randomUUID(),
      key: newKey,
      expiry,
    });

    // Remove expired keys
    this.keys = this.keys.filter(k => k.expiry > new Date());
  }

  getCurrentKey(): CryptoKey {
    const validKey = this.keys.find(k => k.expiry > new Date());
    if (!validKey) throw new Error("No valid encryption key available");
    return validKey.key;
  }
}

Defending Against Common Attacks

Injection Attack Protection

SQL Injection Protection

// Use parameterized queries (example with PostgreSQL)
import { Client } from "https://deno.land/x/postgres@v0.17.0/mod.ts";

const client = new Client({
  user: "app_user",
  password: "secure_password",
  database: "app_db",
  hostname: "localhost",
  port: 5432,
});

await client.connect();

// Safe query (parameterized)
const userId = "user_input"; // User-controlled input
const result = await client.queryObject({
  text: "SELECT * FROM users WHERE id = $1",
  args: [userId], // Automatically escaped
});

// Dangerous example (DO NOT DO THIS!)
// const dangerousQuery = `SELECT * FROM users WHERE id = '${userId}'`;
// await client.query(dangerousQuery);

XSS Protection

// HTML escaping function
function escapeHtml(unsafe: string): string {
  return unsafe
    .replace(/&/g, "&")
    .replace(/</g, "<")
    .replace(/>/g, ">")
    .replace(/"/g, """)
    .replace(/'/g, "'");
}

// Usage example
const userInput = '<script>alert("XSS")</script>';
const safeOutput = escapeHtml(userInput);
console.log(safeOutput); // <script>alert("XSS")</script>

Transport Security

Secure Cookie Configuration

// Secure HTTP response headers
import { serve } from "https://deno.land/std@0.224.0/http/server.ts";

await serve(async (_req) => {
  const cookie = [
    "sessionId=abc123",
    "Secure",       // HTTPS only
    "HttpOnly",     // Prohibit JavaScript access
    "SameSite=Strict", // Strict same-site policy
    "Max-Age=3600", // 1-hour validity
  ].join("; ");

  return new Response("Secure session established", {
    headers: {
      "Set-Cookie": cookie,
      "Content-Security-Policy": "default-src 'self'",
    },
  });
});

Rate Limiting

API Access Control

// IP-based rate limiting
class RateLimiter {
  private requests: Map<string, number[]> = new Map();
  private windowMs = 60 * 1000; // 1-minute window
  private maxRequests = 100;    // Maximum requests

  async check(ip: string): Promise<boolean> {
    const now = Date.now();
    let timestamps = this.requests.get(ip) || [];

    // Remove expired requests
    timestamps = timestamps.filter(t => t > now - this.windowMs);

    if (timestamps.length >= this.maxRequests) {
      return false; // Exceeds limit
    }

    timestamps.push(now);
    this.requests.set(ip, timestamps);
    return true;
  }
}

// Usage example
const limiter = new RateLimiter();

await serve(async (req) => {
  const ip = req.headers.get("X-Forwarded-For") || "unknown";

  if (!await limiter.check(ip)) {
    return new Response("Too many requests", { status: 429 });
  }

  // Handle normal request
  return new Response("Request processed");
});

Security Auditing and Compliance

Dependency Security Checks

Vulnerability Scanning Tools

# Use deno audit to check dependency vulnerabilities (requires deno_audit tool)
deno audit

# Or use third-party services
# snyk test --deno

Security Headers Configuration Checklist

// Comprehensive security HTTP headers example
const securityHeaders = {
  "Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline'",
  "X-Frame-Options": "DENY",
  "X-Content-Type-Options": "nosniff",
  "Referrer-Policy": "strict-origin-when-cross-origin",
  "Strict-Transport-Security": "max-age=63072000; includeSubDomains; preload",
};

Audit Logging

Security Event Logging

// Security audit logging implementation
class SecurityLogger {
  private logFile = await Deno.open("security.log", { 
    create: true, 
    append: true,
    write: true 
  });

  async logEvent(event: string, metadata: Record<string, unknown>) {
    const timestamp = new Date().toISOString();
    const logEntry = JSON.stringify({ timestamp, event, ...metadata }) + "\n";

    await Deno.writeAll(this.logFile, new TextEncoder().encode(logEntry))
      .catch(err => console.error("Failed to write audit log:", err));
  }

  close() {
    this.logFile.close();
  }
}

// Usage example
const logger = new SecurityLogger();
await logger.logEvent("FAILED_LOGIN", {
  userId: "user123",
  ip: "192.168.1.100",
  timestamp: new Date().toISOString()
});
logger.close();

Practical Case Studies

Secure File Storage Service

// secure_file_storage.ts
import { crypto } from "https://deno.land/std@0.224.0/crypto/mod.ts";

// Initialize encryption key (load from secure storage in production)
const key = await crypto.subtle.generateKey(
  { name: "AES-GCM", length: 256 },
  true,
  ["encrypt", "decrypt"]
);

// File upload handling
async function handleUpload(fileData: Uint8Array, userId: string) {
  // Generate unique file ID
  const fileId = crypto.randomUUID();

  // Encrypt file content
  const nonce = crypto.getRandomValues(new Uint8Array(12));
  const ciphertext = await crypto.subtle.encrypt(
    { name: "AES-GCM", iv: nonce },
    key,
    fileData
  );

  // Store encrypted data (example uses in-memory storage)
  const storage: Record<string, { ciphertext: ArrayBuffer; nonce: Uint8Array }> = {};
  storage[fileId] = { ciphertext, nonce };

  // Record access permissions
  const accessLog: Record<string, string[]> = {};
  accessLog[fileId] = [userId];

  return { fileId };
}

// File download handling
async function handleDownload(fileId: string, userId: string) {
  // Verify access permissions
  const accessLog: Record<string, string[]> = {}; // Should be loaded from storage
  if (!accessLog[fileId]?.includes(userId)) {
    throw new Error("Access denied");
  }

  // Retrieve encrypted data
  const storage: Record<string, { ciphertext: ArrayBuffer; nonce: Uint8Array }> = {}; // Should be loaded from storage
  const { ciphertext, nonce } = storage[fileId];

  // Decrypt file
  const decrypted = await crypto.subtle.decrypt(
    { name: "AES-GCM", iv: nonce },
    key,
    ciphertext
  );

  return new Uint8Array(decrypted);
}

// Run: deno run --allow-read --allow-write secure_file_storage.ts

Secure API Gateway

// secure_api_gateway.ts
import { serve } from "https://deno.land/std@0.224.0/http/server.ts";
import { verify } from "https://deno.land/x/djwt@v3.0.2/mod.ts";
import { crypto } from "https://deno.land/std@0.224.0/crypto/mod.ts";

// JWT verification middleware
async function authMiddleware(req: Request): Promise<Request | Response> {
  const authHeader = req.headers.get("Authorization");
  if (!authHeader?.startsWith("Bearer ")) {
    return new Response("Unauthorized", { status: 401 });
  }

  const token = authHeader.substring(7);
  const key = await crypto.subtle.generateKey(
    { name: "HMAC", hash: "SHA-256" },
    true,
    ["sign", "verify"]
  );
  try {
    const payload = await verify(token, key);
    // Attach user info to request
    (req as any).user = payload;
    return req;
  } catch (err) {
    return new Response("Invalid token", { status: 401 });
  }
}

// Protected route handler
async function protectedHandler(req: Request) {
  const user = (req as any).user;
  return new Response(`Welcome ${user.sub}`, { status: 200 });
}

// Create secure server
await serve(async (req) => {
  // Apply authentication middleware
  const processedReq = await authMiddleware(req);
  if (processedReq instanceof Response) {
    return processedReq;
  }

  // Route handling
  if (new URL(req.url).pathname.endsWith("/protected")) {
    return protectedHandler(processedReq);
  }

  return new Response("Public endpoint", { status: 200 });
}, { port: 8000 });

console.log("Secure API gateway running on http://localhost:8000");
Share your love