Deno与Secure TypeScript:安全的后端开发

Deno 是一个现代的后端 JavaScript/TypeScript 运行时,由 Node.js 的创始人 Ryan Dahl 创建。Deno 提供了许多内置的安全特性,使得后端开发更加安全可靠。

Deno 简介

特点

  • 安全性:默认情况下禁用文件系统访问、网络访问等权限,必须显式授予。
  • 模块化:支持 ES 模块语法,无需额外的模块加载器。
  • 内置工具:提供了许多内置工具,如 HTTP 服务器、WebSocket 服务器等。
  • 跨平台:支持 Windows、macOS 和 Linux。

TypeScript 简介

  • 类型安全:提供强类型检查,避免运行时错误。
  • 静态类型检查:在编译阶段发现类型错误,提高代码质量。
  • 工具支持:丰富的 IDE 和编辑器支持,提高开发效率。

安全性基础

权限管理

  • Deno 默认禁用所有权限,必须显式授予。
  • 权限包括文件系统访问、网络访问、环境变量访问等。

代码隔离

  • 每个模块都在沙箱环境中运行,防止恶意代码影响全局。

Deno 安装与基本使用

安装 Deno

bash 复制代码
curl -fsSL https://deno.land/x/install/install.sh | sh
deno --version

创建项目

bash 复制代码
mkdir my-deno-app
cd my-deno-app

编写基本代码

typescript 复制代码
// main.ts
console.log("Hello, Deno!");

运行代码

bash 复制代码
deno run main.ts

权限管理

默认权限

默认情况下,Deno 不允许任何权限。

bash 复制代码
deno run --allow-read main.ts

显式授予权限

授予读权限。

bash 复制代码
deno run --allow-read main.ts

权限组合

授予读和写权限。

bash 复制代码
deno run --allow-read --allow-write main.ts

HTTP 服务器

创建 HTTP 服务器

typescript 复制代码
// server.ts
import { serve } from "https://deno.land/std@0.188.0/http/server.ts";

const handler = (req: Request) => {
  if (req.method === "GET") {
    return new Response("Hello, World!");
  }
  return new Response("Method not allowed", { status: 405 });
};

serve(handler);

运行 HTTP 服务器

bash 复制代码
deno run --allow-net server.ts

访问服务器

bash 复制代码
curl http://localhost:8000

安全的 HTTP 请求

发送 HTTP 请求

typescript 复制代码
// request.ts
import { serve } from "https://deno.land/std@0.188.0/http/server.ts";
import { fetch } from "https://deno.land/std@0.188.0/fetch/mod.ts";

const handler = async (req: Request) => {
  const response = await fetch("https://api.example.com/data");
  const data = await response.json();
  return new Response(JSON.stringify(data), { headers: { "Content-Type": "application/json" } });
};

serve(handler);

运行请求处理程序

bash 复制代码
deno run --allow-net request.ts

访问请求处理程序

bash 复制代码
curl http://localhost:8000

数据验证与类型安全

数据验证

typescript 复制代码
// validator.ts
import { serve } from "https://deno.land/std@0.188.0/http/server.ts";
import { z } from "https://deno.land/x/zod@v3.21.4/mod.ts";

interface User {
  id: number;
  name: string;
  email: string;
}

const userSchema = z.object({
  id: z.number(),
  name: z.string().min(1),
  email: z.string().email(),
});

const handler = async (req: Request) => {
  const url = new URL(req.url);
  const params = Object.fromEntries(url.searchParams.entries());
  const result = userSchema.safeParse(params);

  if (!result.success) {
    return new Response(result.error.message, { status: 400 });
  }

  const user: User = result.data;
  return new Response(JSON.stringify(user), { headers: { "Content-Type": "application/json" } });
};

serve(handler);

运行验证处理程序

bash 复制代码
deno run --allow-net validator.ts

访问验证处理程序

bash 复制代码
curl "http://localhost:8000?id=1&name=John&email=john@example.com"

安全的数据库操作

连接数据库

typescript 复制代码
// database.ts
import { serve } from "https://deno.land/std@0.188.0/http/server.ts";
import { sql } from "https://deno.land/x/sqlite@v3.4.2/mod.ts";

const db = sql.open(":memory:");

const createTable = `
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT NOT NULL UNIQUE
  );
`;

db.query(createTable);

const insertUser = `
  INSERT INTO users (name, email) VALUES (?, ?);
`;

const selectUsers = `
  SELECT * FROM users;
`;

const handler = async (req: Request) => {
  const url = new URL(req.url);
  const name = url.searchParams.get("name");
  const email = url.searchParams.get("email");

  if (!name || !email) {
    return new Response("Missing parameters", { status: 400 });
  }

  try {
    db.query(insertUser, [name, email]);
    const users = db.query(selectUsers).fetchAll();
    return new Response(JSON.stringify(users), { headers: { "Content-Type": "application/json" } });
  } catch (error) {
    return new Response(error.message, { status: 500 });
  }
};

serve(handler);

运行数据库处理程序

bash 复制代码
deno run --allow-net --allow-read --allow-write database.ts

访问数据库处理程序

bash 复制代码
curl "http://localhost:8000?name=John&email=john@example.com"

日志与错误处理

日志记录

typescript 复制代码
// logger.ts
import { serve } from "https://deno.land/std@0.188.0/http/server.ts";
import { format } from "https://deno.land/std@0.188.0/datetime/mod.ts";

const handler = async (req: Request) => {
  const now = format(new Date(), "yyyy-MM-dd HH:mm:ss");
  console.log(`${now} - ${req.method} - ${req.url}`);

  return new Response("OK");
};

serve(handler);

错误处理

typescript 复制代码
// error-handler.ts
import { serve } from "https://deno.land/std@0.188.0/http/server.ts";

const handler = async (req: Request) => {
  try {
    // Perform some operation
    return new Response("OK");
  } catch (error) {
    console.error(error);
    return new Response(error.message, { status: 500 });
  }
};

serve(handler);

安全的最佳实践

最小权限原则

只授予必要的权限。

bash 复制代码
deno run --allow-net --allow-read main.ts

输入验证

对所有外部输入进行严格验证。

typescript 复制代码
const userSchema = z.object({
  id: z.number(),
  name: z.string().min(1),
  email: z.string().email(),
});

加密敏感数据

对敏感数据进行加密处理。

typescript 复制代码
import { crypto } from "https://deno.land/std@0.188.0/crypto/mod.ts";

const secret = crypto.randomUUID();
const encryptedData = crypto.encrypt(secret, sensitiveData);

安全的数据库操作

使用参数化查询防止 SQL 注入。

typescript 复制代码
const insertUser = `
  INSERT INTO users (name, email) VALUES (?, ?);
`;

db.query(insertUser, [name, email]);

安全的会话管理

使用安全的会话管理机制。

typescript 复制代码
import { serve, Cookie } from "https://deno.land/std@0.188.0/http/server.ts";

const handler = async (req: Request) => {
  const sessionCookie = req.headers.get("Cookie");
  let sessionId = null;

  if (sessionCookie) {
    const cookie = new Cookie(sessionCookie);
    sessionId = cookie.get("session_id")?.value;
  }

  if (!sessionId) {
    sessionId = crypto.randomUUID();
    const cookie = new Cookie({
      name: "session_id",
      value: sessionId,
      httpOnly: true,
      secure: true,
      sameSite: "strict",
    });

    return new Response("Session created", {
      headers: { "Set-Cookie": cookie.toString() },
    });
  }

  // Perform session-related operations
  return new Response("OK");
};

serve(handler);

使用 HTTPS

确保所有通信都使用 HTTPS。

typescript 复制代码
const server = serve({ port: 443, hostname: "example.com", secure: true });

CORS 策略

配置适当的 CORS 策略。

typescript 复制代码
const handler = async (req: Request) => {
  const origin = req.headers.get("Origin");

  if (origin === "https://example.com") {
    return new Response("OK", {
      headers: { "Access-Control-Allow-Origin": origin },
    });
  }

  return new Response("Not allowed", { status: 403 });
};

serve(handler);

安全的文件上传

对上传文件进行严格的验证和限制。

typescript 复制代码
import { serve } from "https://deno.land/std@0.188.0/http/server.ts";
import { parseMultipartFormData } from "https://deno.land/std@0.188.0/mime/multipart/form_data/parser.ts";

const handler = async (req: Request) => {
  const formData = await parseMultipartFormData(req, { maxFileSize: 1024 * 1024 * 5 }); // 5MB limit

  if (!formData.has("file")) {
    return new Response("File missing", { status: 400 });
  }

  const file = formData.get("file");

  if (!file) {
    return new Response("Invalid file", { status: 400 });
  }

  const fileName = file.name;
  const fileSize = file.size;
  const fileType = file.type;

  if (fileType !== "image/jpeg" && fileType !== "image/png") {
    return new Response("Unsupported file type", { status: 400 });
  }

  // Save the file securely
  const filePath = `./uploads/${fileName}`;
  const fileStream = Deno.openSync(filePath, { write: true, create: true });
  await fileStream.write(file.data);
  fileStream.close();

  return new Response("File uploaded successfully");
};

serve(handler);

安全的环境变量管理

使用环境变量存储敏感信息。

typescript 复制代码
const apiKey = Deno.env.get("API_KEY");
const apiSecret = Deno.env.get("API_SECRET");

定期审计与更新

定期进行安全审计,并及时更新依赖库。

bash 复制代码
deno upgrade

安全的认证与授权

JWT认证

使用 JWT 进行用户认证。

typescript 复制代码
import { serve } from "https://deno.land/std@0.188.0/http/server.ts";
import { jwt } from "https://deno.land/x/djwt@v2.2/mod.ts";

const secret = Deno.env.get("JWT_SECRET");

const handler = async (req: Request) => {
  const authHeader = req.headers.get("Authorization");

  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    return new Response("Unauthorized", { status: 401 });
  }

  const token = authHeader.slice(7); // Remove "Bearer " prefix

  try {
    const decodedToken = await jwt.decode(token, { secret });
    return new Response("Authenticated");
  } catch (error) {
    return new Response("Invalid token", { status: 401 });
  }
};

serve(handler);

角色与权限

使用角色和权限进行细粒度控制。

typescript 复制代码
const userRoles = {
  admin: ["read", "write", "delete"],
  user: ["read"],
};

const handler = async (req: Request) => {
  const authHeader = req.headers.get("Authorization");
  const token = authHeader.slice(7); // Remove "Bearer " prefix
  const decodedToken = await jwt.decode(token, { secret });

  const role = decodedToken.role;
  const permissions = userRoles[role];

  if (!permissions.includes("write")) {
    return new Response("Permission denied", { status: 403 });
  }

  // Perform write operation
  return new Response("Write successful");
};

serve(handler);
相关推荐
baiduopenmap11 分钟前
百度世界2024精选公开课:基于地图智能体的导航出行AI应用创新实践
前端·人工智能·百度地图
loooseFish18 分钟前
小程序webview我爱死你了 小程序webview和H5通讯
前端
请叫我欧皇i31 分钟前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
533_33 分钟前
[vue] 深拷贝 lodash cloneDeep
前端·javascript·vue.js
guokanglun39 分钟前
空间数据存储格式GeoJSON
前端
zhang-zan1 小时前
nodejs操作selenium-webdriver
前端·javascript·selenium
猫爪笔记1 小时前
前端:HTML (学习笔记)【2】
前端·笔记·学习·html
brief of gali1 小时前
记录一个奇怪的前端布局现象
前端
Json_181790144802 小时前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
风尚云网3 小时前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网