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.tsPermission Categories
| Permission Type | Scope | Example Flag |
|---|---|---|
| File System | Read/write files/directories | --allow-read --allow-write |
| Network | Network access | --allow-net --allow-conn |
| Environment Variables | Read/write environment variables | --allow-env |
| Subprocess | Execute external commands | --allow-run |
| Plugins | Load 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.tsProtecting 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 365Secure 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 --denoSecurity 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.tsSecure 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");



