惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
I
InfoQ
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
P
Privacy International News Feed
T
Threatpost
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
Vulnerabilities – Threatpost
NISL@THU
NISL@THU
aimingoo的专栏
aimingoo的专栏
S
Schneier on Security
C
Cisco Blogs
T
The Blog of Author Tim Ferriss
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Jina AI
Jina AI
雷峰网
雷峰网
Know Your Adversary
Know Your Adversary
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
I
Intezer
博客园 - Franky
博客园 - 【当耐特】
Hugging Face - Blog
Hugging Face - Blog
The Hacker News
The Hacker News
K
Kaspersky official blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tailwind CSS Blog
Project Zero
Project Zero
T
Tor Project blog
B
Blog RSS Feed
Recorded Future
Recorded Future
Scott Helme
Scott Helme
美团技术团队
V
V2EX
V
Visual Studio Blog
L
Lohrmann on Cybersecurity
P
Proofpoint News Feed
D
DataBreaches.Net
The Register - Security
The Register - Security
M
MIT News - Artificial intelligence
L
LangChain Blog
Cisco Talos Blog
Cisco Talos Blog
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
Cyber Attacks, Cyber Crime and Cyber Security
博客园_首页
P
Privacy & Cybersecurity Law Blog

WishMeLz - Vue

van-nav-bar 页面宽度改动 placeholder占位元素未自动更新 - WishMeLz Vant UI van-search 键盘没有显示「搜索」按钮的解决方案 - WishMeLz Lodop、C-Lodop使用笔记 - WishMeLz el-upload beforeUpload 使用async无法拦截 ANSI 字体在前端展示 Jenkins日志 - WishMeLz 获取视频某一秒的截图 - WishMeLz elementui 动态生成的 el-form-item rules校验失效 vue中v-html - WishMeLz SSE(Server-Sent Events) - WishMeLz
Electron 主进程起一个可用的 HTTPS 静态服务器 - WishMeLz
Wish · 2026-01-20 · via WishMeLz - Vue

1. 启动 HTTPS 服务

在 Electron 的主进程中,我们可以直接利用 Node.js 原生的 httphttps 模块来创建服务。区别在于 HTTPS 需要配置 key (私钥) 和 cert (证书)。

代码实现

import { createServer as createHttpServer } from "http";
import { createServer as createHttpsServer } from "https";
import { generateSiteCert } from "./cert-service"; // 下文会提到的证书服务

const startServer = async (config: ServerConfig) => {
  const requestHandler = (req, res) => {
    // 处理静态文件或 API 代理逻辑
    res.end("Hello Secure World!");
  };

  let server;
  
  if (config.https.enabled) {
    // 关键点:动态生成或读取站点证书
    // 返回的 key/cert 是 PEM 格式的字符串
    const { key, cert } = generateSiteCert(config.https.domain);
    
    server = createHttpsServer({ 
      key, 
      cert 
    }, requestHandler);
  } else {
    server = createHttpServer(requestHandler);
  }

  server.listen(config.port, () => {
    console.log(`Server running at ${config.https.enabled ? 'https' : 'http'}://localhost:${config.port}`);
  });
};

2. SSL 证书的自动化生成与认证

我们使用 node-forge 库来完成这些操作,它是一个纯 JavaScript 实现的加密库。

2.1 生成根证书 (Root CA)

CA 证书的有效期通常设置得很长(如 10 年),并且需要标记为 cA: true

import * as forge from "node-forge";

export const generateCA = () => {
  const keys = forge.pki.rsa.generateKeyPair(2048);
  const cert = forge.pki.createCertificate();
  cert.publicKey = keys.publicKey;
  cert.serialNumber = "01";
  
  // 设置有效期 10 年
  cert.validity.notBefore = new Date();
  cert.validity.notAfter = new Date();
  cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10);

  const attrs = [
    { name: "commonName", value: `My Local Dev CA - ${Date.now()}` }, // 加上时间戳避免重名冲突
    { name: "organizationName", value: "Local Dev" }
  ];
  cert.setSubject(attrs);
  cert.setIssuer(attrs); // 自签名:颁发者等于使用者

  cert.setExtensions([
    { name: "basicConstraints", cA: true }, // 关键:标识为 CA
    { name: "keyUsage", keyCertSign: true, digitalSignature: true },
    { name: "subjectKeyIdentifier" } 
  ]);

  // 使用私钥签名
  cert.sign(keys.privateKey, forge.md.sha256.create());

  return {
    key: forge.pki.privateKeyToPem(keys.privateKey),
    cert: forge.pki.certificateToPem(cert)
  };
};

2.2 签发站点证书 (Site Certificate)

站点证书必须包含 SAN (Subject Alternative Name)Server Auth (扩展密钥用法),否则现代浏览器(Chrome 58+)会拦截。

export const generateSiteCert = (domain: string, caKeyPem: string, caCertPem: string) => {
  const caKey = forge.pki.privateKeyFromPem(caKeyPem);
  const caCert = forge.pki.certificateFromPem(caCertPem);

  const keys = forge.pki.rsa.generateKeyPair(2048);
  const cert = forge.pki.createCertificate();
  cert.publicKey = keys.publicKey;
  cert.serialNumber = Date.now().toString(); // 唯一的序列号
  
  // 有效期 1 年
  cert.validity.notBefore = new Date();
  cert.validity.notAfter = new Date();
  cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);

  cert.setSubject([{ name: "commonName", value: domain }]);
  cert.setIssuer(caCert.subject.attributes); // 颁发者是我们的 CA

  cert.setExtensions([
    { name: "basicConstraints", cA: false },
    { 
      name: "keyUsage", 
      digitalSignature: true, 
      keyEncipherment: true 
    },
    {
      name: "extKeyUsage", // 关键:必须包含服务器验证
      serverAuth: true,
      clientAuth: true
    },
    {
      name: "subjectAltName", // 关键:SAN 字段
      altNames: [
        { type: 2, value: domain }, // DNS: mysite.local
        { type: 7, ip: "127.0.0.1" } // IP: 127.0.0.1
      ]
    },
    {
       name: "authorityKeyIdentifier", // 建立信任链的关键
       keyIdentifier: caCert.generateSubjectKeyIdentifier().data
    }
  ]);

  // 使用 CA 的私钥进行签名
  cert.sign(caKey, forge.md.sha256.create());

  return {
    key: forge.pki.privateKeyToPem(keys.privateKey),
    cert: forge.pki.certificateToPem(cert)
  };
};

2.3 信任根证书 (Windows)

生成的证书默认是不受系统信任的。我们需要调用 Windows 的 certutil 工具将我们的 CA 导入到“受信任的根证书颁发机构”存储区。

这需要管理员权限,我们可以通过 PowerShell 的 Start-Process -Verb RunAs 来触发 UAC 提权弹窗。

import { exec } from "child_process";

export const installCertTrust = (caCertPath: string) => {
  // certutil -addstore -user Root "path/to/rootCA.pem"
  const psCmd = `Start-Process certutil -ArgumentList '-addstore','-user','Root','"${caCertPath}"' -Verb RunAs -Wait`;
  
  return new Promise((resolve, reject) => {
    exec(`powershell "${psCmd}"`, (err) => {
      if (err) reject(err);
      else resolve();
    });
  });
};

3. 修改系统 Hosts 文件

为了支持 mysite.local 这样的自定义域名指向本地,我们需要修改系统的 Hosts 文件。

Windows 的 Hosts 文件位于 C:\Windows\System32\drivers\etc\hosts。直接写入通常会因为权限不足而失败(即使是管理员权限的 Node 进程有时也会受限)。

稳健的解决方案

  1. 读取原 Hosts 内容。
  2. 在内存中修改(添加 127.0.0.1 mysite.local)。
  3. 写入到一个临时文件。
  4. 使用提权 PowerShell 将临时文件强制复制覆盖系统 Hosts 文件。
import * as fs from "fs";
import * as path from "path";
import { app } from "electron"; // 获取临时目录路径

const HOSTS_PATH = "C:\\Windows\\System32\\drivers\\etc\\hosts";

export const updateHosts = (domain: string) => {
  // 1. 读取并修改内容
  let content = fs.readFileSync(HOSTS_PATH, "utf8");
  // ... (省略具体的字符串处理逻辑,如去重、追加) ...
  const newContent = content + `\r\n127.0.0.1 ${domain}`;

  // 2. 写入临时文件
  const tempPath = path.join(app.getPath("userData"), `hosts_temp_${Date.now()}`);
  fs.writeFileSync(tempPath, newContent);

  // 3. 提权覆盖
  // Copy-Item "temp" "hosts" -Force
  const psCmd = `Start-Process powershell -ArgumentList '-Command "Copy-Item ''${tempPath}'' ''${HOSTS_PATH}'' -Force"' -Verb RunAs -Wait`;

  return new Promise((resolve, reject) => {
    exec(`powershell "${psCmd}"`, (err) => {
      // 清理临时文件
      fs.unlinkSync(tempPath);
      
      if (err) reject(err);
      else resolve();
    });
  });
};

4. 总结

  1. Node-Forge 负责构建合规的证书链,骗过浏览器的安全检查。
  2. Certutil + PowerShell 负责打通操作系统的证书信任。
  3. Hosts Hack 负责实现自定义域名的本地回环解析。