# Apache 虚拟主机最终安全整改方案（保证项目正常运行版）

生成时间：2026-06-20  
适用文件：`C:\xampp\apache\conf\extra\httpd-vhosts.conf`  
目标：**在不破坏 shayukeji 项目现有访问路径、API 反代、WebSocket、APK 下载的前提下，加强 Apache 边界安全，避免敏感文件泄露。**

---

## 一、核心原则

本方案不是简单粗暴地封目录，而是采用：

> **业务入口精准放行，敏感路径精准封禁。**

也就是说：

### 必须保证正常运行的路径

#### 管理后台

```text
https://buyrdbcdgdst.cv/
https://buyrdbcdgdst.cv/api/
https://buyrdbcdgdst.cv/uploads/
```

对应：

```text
管理后台前端 dist:
C:/xampp/htdocs/shayukeji/shark-control-admin/frontend/dist

管理后台后端:
http://127.0.0.1:3001/api

管理后台上传文件:
http://127.0.0.1:3001/uploads
```

---

#### 控制端

```text
https://yybfok.store/
https://yybfok.store/api/auth/
https://yybfok.store/api/client/
https://yybfok.store/api/public/
https://yybfok.store/api/distribute/
https://yybfok.store/api/
https://yybfok.store/uploads/
https://yybfok.store/downloads/**/*.apk
```

对应：

```text
控制端前端 dist:
C:/xampp/htdocs/shayukeji/shark-control/dist

认证、客户、公共、下发 API:
http://127.0.0.1:3001/api/...

控制端自己的 API:
http://127.0.0.1:3002/api

控制端上传文件:
http://127.0.0.1:3002/uploads

APK 下载目录:
C:/xampp/htdocs/shayukeji/shark-control/downloads
```

---

#### WebSocket

```text
wss://sunwukongzhubajjie.lat/api/ws/
wss://sunwukongzhubajjie.lat/ws
wss://sunwukongzhubajjie.lat/ws/
```

对应：

```text
ws://127.0.0.1:8080
```

---

### 必须禁止 Web 访问的敏感内容

```text
.env
.env.*
*.sql
*.log
*.bak
*.backup
*.old
*.jks
*.pem
*.key
*.zip
*.rar
*.7z
private/
backend/
src/
node_modules/
vendor/
prisma/
db-backups*/
keystores/
.git/
.svn/
.idea/
.vscode/
```

---

## 二、当前配置中最需要修复的问题

### 1. `localhost` 暴露整个 `C:/xampp/htdocs`

当前配置中有：

```apache
<VirtualHost *:80>
  ServerName localhost
  DocumentRoot "C:/xampp/htdocs"

  <Directory "C:/xampp/htdocs">
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
  </Directory>
</VirtualHost>
```

这是最危险的点。

原因：`C:/xampp/htdocs` 下存在：

```text
private/
.env
数据库备份
日志
APK
JKS
Excel 数据
node_modules
backend 源码
src 源码
```

如果默认虚拟主机、Host 头、IP 访问或 HTTP 访问落到这里，就可能造成敏感文件泄露。

最终方案：

```apache
localhost 不再指向 C:/xampp/htdocs
localhost 只指向 C:/xampp/apache/empty
并且只允许本机访问
```

---

### 2. 公网 HTTP 没有统一跳 HTTPS

需要补充：

```text
http://buyrdbcdgdst.cv       -> https://buyrdbcdgdst.cv
http://yybfok.store          -> https://yybfok.store
http://sunwukongzhubajjie.lat -> https://sunwukongzhubajjie.lat
```

这样可以避免 HTTP 请求落入错误虚拟主机。

---

### 3. 部分目录开启 `Indexes`

`Options Indexes` 可能导致目录列表暴露。

应统一改为：

```apache
Options -Indexes +FollowSymLinks
```

---

### 4. `/downloads` 应保留，但只允许 APK

控制端需要下载 APK，所以不能完全封死 `/downloads`。

最终策略：

```text
/downloads/**/*.apk 允许下载
/downloads/         禁止列目录
/downloads/非apk    禁止访问
```

---

## 三、修改前准备

### 1. 备份原配置

PowerShell 执行：

```powershell
Copy-Item "C:\xampp\apache\conf\extra\httpd-vhosts.conf" "C:\xampp\apache\conf\extra\httpd-vhosts.conf.bak-20260620"
```

---

### 2. 创建空目录

本方案使用 `C:/xampp/apache/empty` 作为空站点目录。

如果不存在，执行：

```powershell
New-Item -ItemType Directory -Force "C:\xampp\apache\empty"
```

该目录应保持为空。

---

### 3. 确认 Apache 模块启用

检查：

```text
C:\xampp\apache\conf\httpd.conf
```

确认以下模块没有被注释：

```apache
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule headers_module modules/mod_headers.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
```

否则可能出现：

```text
Header 指令不可用
SSLEngine 指令不可用
RewriteRule 不生效
WebSocket 反代失败
```

---

## 四、最终推荐版 `httpd-vhosts.conf`

> 建议在备份后，将现有 `C:\xampp\apache\conf\extra\httpd-vhosts.conf` 按以下结构调整。

```apache
# Virtual Hosts
# Required modules:
# mod_log_config, mod_proxy, mod_proxy_http, mod_proxy_wstunnel,
# mod_rewrite, mod_ssl, mod_headers

# Apache 2.4 不再需要 NameVirtualHost
# NameVirtualHost *:80

# ============================================================
# Global basic hardening
# ============================================================

ServerTokens Prod
ServerSignature Off

# 默认不允许整个 htdocs 被当作站点根目录直接访问。
# 注意：后面每个真正业务目录会单独 Require all granted。
<Directory "C:/xampp/htdocs">
  Options -Indexes +FollowSymLinks
  AllowOverride None
  Require all denied
</Directory>

# 全局禁止直接访问常见敏感文件。
# 不影响 /api 反代，也不影响已单独放行的 dist 和 APK 下载。
<FilesMatch "(?i)^(\.env|\.env\..*|.*\.sql|.*\.log|.*\.bak|.*\.backup|.*\.old|.*\.jks|.*\.pem|.*\.key)$">
  Require all denied
</FilesMatch>

# ============================================================
# Public HTTP -> HTTPS
# ============================================================

<VirtualHost *:80>
  ServerName buyrdbcdgdst.cv
  RewriteEngine On
  RewriteRule ^ https://buyrdbcdgdst.cv%{REQUEST_URI} [R=301,L]

  ErrorLog "logs/buyrdbcdgdst-admin-http-error.log"
  CustomLog "logs/buyrdbcdgdst-admin-http-access.log" common
</VirtualHost>

<VirtualHost *:80>
  ServerName yybfok.store
  RewriteEngine On
  RewriteRule ^ https://yybfok.store%{REQUEST_URI} [R=301,L]

  ErrorLog "logs/yybfok-control-http-error.log"
  CustomLog "logs/yybfok-control-http-access.log" common
</VirtualHost>

<VirtualHost *:80>
  ServerName sunwukongzhubajjie.lat
  RewriteEngine On
  RewriteRule ^ https://sunwukongzhubajjie.lat%{REQUEST_URI} [R=301,L]

  ErrorLog "logs/ws-http-error.log"
  CustomLog "logs/ws-http-access.log" common
</VirtualHost>

# ============================================================
# 管理后台本地域名：shark-admin.local
# 仅本机调试使用，不对外开放。
# ============================================================

<VirtualHost *:80>
  ServerName shark-admin.local
  DocumentRoot "C:/xampp/htdocs/shayukeji/shark-control-admin/frontend/dist"

  <Directory "C:/xampp/htdocs/shayukeji/shark-control-admin/frontend/dist">
    Options -Indexes +FollowSymLinks
    AllowOverride All
    Require local

    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
  </Directory>

  <IfModule proxy_module>
    ProxyRequests Off
    ProxyPreserveHost On

    ProxyPass        /api/     http://127.0.0.1:3001/api/
    ProxyPassReverse /api/     http://127.0.0.1:3001/api/

    ProxyPass        /uploads/ http://127.0.0.1:3001/uploads/
    ProxyPassReverse /uploads/ http://127.0.0.1:3001/uploads/
  </IfModule>

  ErrorLog "logs/shark-admin-error.log"
  CustomLog "logs/shark-admin-access.log" common
</VirtualHost>

# ============================================================
# 管理后台 HTTPS 公网域名
# https://buyrdbcdgdst.cv
# ============================================================

<VirtualHost *:443>
  ServerName buyrdbcdgdst.cv
  DocumentRoot "C:/xampp/htdocs/shayukeji/shark-control-admin/frontend/dist"

  SSLEngine on
  SSLCertificateFile    "C:/xampp/apache/conf/ssl/buyrdbcdgdst.cv-chain.pem"
  SSLCertificateKeyFile "C:/xampp/apache/conf/ssl/buyrdbcdgdst.cv-key.pem"

  # 安全响应头，不影响正常业务
  Header always set X-Content-Type-Options "nosniff"
  Header always set X-Frame-Options "DENY"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

  <Directory "C:/xampp/htdocs/shayukeji/shark-control-admin/frontend/dist">
    Options -Indexes +FollowSymLinks
    AllowOverride All
    Require all granted

    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
  </Directory>

  # 仅封管理后台域名下不该出现的敏感路径。
  # 不影响 /api 和 /uploads 反代。
  <LocationMatch "(?i)^/(private|backend|src|node_modules|vendor|prisma|db-backups[^/]*|keystores|\.git|\.svn|\.idea|\.vscode)(/|$)">
    Require all denied
  </LocationMatch>

  <LocationMatch "(?i)\.(env|sql|log|bak|backup|old|jks|pem|key|zip|rar|7z)$">
    Require all denied
  </LocationMatch>

  <IfModule proxy_module>
    ProxyRequests Off
    ProxyPreserveHost On

    ProxyPass        /api/     http://127.0.0.1:3001/api/
    ProxyPassReverse /api/     http://127.0.0.1:3001/api/

    ProxyPass        /uploads/ http://127.0.0.1:3001/uploads/
    ProxyPassReverse /uploads/ http://127.0.0.1:3001/uploads/
  </IfModule>

  ErrorLog "logs/buyrdbcdgdst-admin-ssl-error.log"
  CustomLog "logs/buyrdbcdgdst-admin-ssl-access.log" common
</VirtualHost>

# ============================================================
# 控制端本地域名：shark-control.local
# 仅本机调试使用，不对外开放。
# ============================================================

<VirtualHost *:80>
  ServerName shark-control.local
  DocumentRoot "C:/xampp/htdocs/shayukeji/shark-control/dist"

  <Directory "C:/xampp/htdocs/shayukeji/shark-control/dist">
    Options -Indexes +FollowSymLinks
    AllowOverride All
    Require local

    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^/downloads/
    RewriteRule . /index.html [L]
  </Directory>

  # 本地 APK 下载目录，仅本机可访问
  Alias /downloads "C:/xampp/htdocs/shayukeji/shark-control/downloads"

  <Directory "C:/xampp/htdocs/shayukeji/shark-control/downloads">
    Options -Indexes +FollowSymLinks
    AllowOverride None
    Require local

    RewriteEngine On

    # 禁止访问目录本身
    RewriteRule ^$ - [F]

    # 只允许 APK 文件，其它文件一律 403
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteCond %{REQUEST_URI} !\.apk$ [NC]
    RewriteRule ^ - [F]

    <FilesMatch "\.apk$">
      ForceType application/vnd.android.package-archive
      Header set Content-Disposition "attachment"
      Header set X-Content-Type-Options "nosniff"
      Require local
    </FilesMatch>
  </Directory>

  <IfModule proxy_module>
    ProxyRequests Off
    ProxyPreserveHost On

    ProxyPass /downloads !

    ProxyPass        /api/auth/       http://127.0.0.1:3001/api/auth/
    ProxyPassReverse /api/auth/       http://127.0.0.1:3001/api/auth/

    ProxyPass        /api/client/     http://127.0.0.1:3001/api/client/
    ProxyPassReverse /api/client/     http://127.0.0.1:3001/api/client/

    ProxyPass        /api/public/     http://127.0.0.1:3001/api/public/
    ProxyPassReverse /api/public/     http://127.0.0.1:3001/api/public/

    ProxyPass        /api/distribute/ http://127.0.0.1:3001/api/distribute/
    ProxyPassReverse /api/distribute/ http://127.0.0.1:3001/api/distribute/

    ProxyPass        /api/            http://127.0.0.1:3002/api/
    ProxyPassReverse /api/            http://127.0.0.1:3002/api/

    ProxyPass        /uploads/        http://127.0.0.1:3002/uploads/
    ProxyPassReverse /uploads/        http://127.0.0.1:3002/uploads/
  </IfModule>

  ErrorLog "logs/shark-control-error.log"
  CustomLog "logs/shark-control-access.log" common
</VirtualHost>

# ============================================================
# 控制端 HTTPS 公网域名
# https://yybfok.store
# ============================================================

<VirtualHost *:443>
  ServerName yybfok.store
  DocumentRoot "C:/xampp/htdocs/shayukeji/shark-control/dist"

  SSLEngine on
  SSLCertificateFile    "C:/xampp/apache/conf/ssl/yybfok.store-chain.pem"
  SSLCertificateKeyFile "C:/xampp/apache/conf/ssl/yybfok.store-key.pem"

  # 安全响应头，不影响正常业务
  Header always set X-Content-Type-Options "nosniff"
  Header always set X-Frame-Options "DENY"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

  <Directory "C:/xampp/htdocs/shayukeji/shark-control/dist">
    Options -Indexes +FollowSymLinks
    AllowOverride All
    Require all granted

    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^/downloads/
    RewriteRule . /index.html [L]
  </Directory>

  # APK 下载目录
  Alias /downloads "C:/xampp/htdocs/shayukeji/shark-control/downloads"

  <Directory "C:/xampp/htdocs/shayukeji/shark-control/downloads">
    Options -Indexes +FollowSymLinks
    AllowOverride None
    Require all granted

    RewriteEngine On

    # 禁止访问目录本身
    RewriteRule ^$ - [F]

    # 只允许 APK 文件，其它文件一律 403
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteCond %{REQUEST_URI} !\.apk$ [NC]
    RewriteRule ^ - [F]

    <FilesMatch "\.apk$">
      ForceType application/vnd.android.package-archive
      Header set Content-Disposition "attachment"
      Header set X-Content-Type-Options "nosniff"
      Require all granted
    </FilesMatch>
  </Directory>

  # 仅封控制端域名下不该出现的敏感路径。
  # 不影响 /api、/uploads、/downloads/*.apk。
  <LocationMatch "(?i)^/(private|backend|src|node_modules|vendor|prisma|db-backups[^/]*|keystores|\.git|\.svn|\.idea|\.vscode)(/|$)">
    Require all denied
  </LocationMatch>

  <LocationMatch "(?i)\.(env|sql|log|bak|backup|old|jks|pem|key|zip|rar|7z)$">
    Require all denied
  </LocationMatch>

  <IfModule proxy_module>
    ProxyRequests Off
    ProxyPreserveHost On

    # 不代理 /downloads，让 Apache 直接提供 APK
    ProxyPass /downloads !

    # 认证相关 API 走管理后台后端
    ProxyPass        /api/auth/       http://127.0.0.1:3001/api/auth/
    ProxyPassReverse /api/auth/       http://127.0.0.1:3001/api/auth/

    # 控制端调用管理后台的 API
    ProxyPass        /api/client/     http://127.0.0.1:3001/api/client/
    ProxyPassReverse /api/client/     http://127.0.0.1:3001/api/client/

    ProxyPass        /api/public/     http://127.0.0.1:3001/api/public/
    ProxyPassReverse /api/public/     http://127.0.0.1:3001/api/public/

    ProxyPass        /api/distribute/ http://127.0.0.1:3001/api/distribute/
    ProxyPassReverse /api/distribute/ http://127.0.0.1:3001/api/distribute/

    # 其余控制端 API 走 3002
    ProxyPass        /api/            http://127.0.0.1:3002/api/
    ProxyPassReverse /api/            http://127.0.0.1:3002/api/

    # 控制端上传文件
    ProxyPass        /uploads/        http://127.0.0.1:3002/uploads/
    ProxyPassReverse /uploads/        http://127.0.0.1:3002/uploads/
  </IfModule>

  ErrorLog "logs/yybfok-control-ssl-error.log"
  CustomLog "logs/yybfok-control-ssl-access.log" common
</VirtualHost>

# ============================================================
# localhost 仅用于本机占位，不暴露整个 htdocs
# ============================================================

<VirtualHost *:80>
  ServerName localhost
  DocumentRoot "C:/xampp/apache/empty"

  <Directory "C:/xampp/apache/empty">
    Options None
    AllowOverride None
    Require local
  </Directory>

  ErrorLog "logs/localhost-error.log"
  CustomLog "logs/localhost-access.log" common
</VirtualHost>

# ============================================================
# WebSocket 专用 HTTPS 虚拟主机
# wss://sunwukongzhubajjie.lat/api/ws/
# wss://sunwukongzhubajjie.lat/ws
# ============================================================

<VirtualHost *:443>
  ServerName sunwukongzhubajjie.lat

  DocumentRoot "C:/xampp/apache/empty"

  SSLEngine on
  SSLCertificateFile    "C:/xampp/apache/conf/ssl/sunwukongzhubajjie.lat-chain.pem"
  SSLCertificateKeyFile "C:/xampp/apache/conf/ssl/sunwukongzhubajjie.lat-key.pem"

  Header always set X-Content-Type-Options "nosniff"
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

  <Directory "C:/xampp/apache/empty">
    Options None
    AllowOverride None
    Require all denied
  </Directory>

  ProxyRequests Off
  ProxyPreserveHost On
  ProxyTimeout 300

  # APK 内置连接路径
  ProxyPass        /api/ws/  ws://127.0.0.1:8080/
  ProxyPassReverse /api/ws/  ws://127.0.0.1:8080/

  # 前端连接路径，兼容 /ws 和 /ws/
  ProxyPass        /ws/      ws://127.0.0.1:8080/
  ProxyPassReverse /ws/      ws://127.0.0.1:8080/

  ProxyPass        /ws       ws://127.0.0.1:8080/
  ProxyPassReverse /ws       ws://127.0.0.1:8080/

  ErrorLog  "logs/ws-ssl-error.log"
  CustomLog "logs/ws-ssl-access.log" common
</VirtualHost>
```

---

## 五、为什么这个方案不会导致项目无法运行

### 1. 管理后台业务路径完整保留

保留：

```text
/
index.html
前端静态资源
/api/
/uploads/
```

所以管理后台页面、登录、接口、上传资源都不受影响。

---

### 2. 控制端业务路径完整保留

保留：

```text
/
index.html
前端静态资源
/api/auth/
/api/client/
/api/public/
/api/distribute/
/api/
/uploads/
/downloads/*.apk
```

所以控制端登录、刷新、设备管理、应用构建、APK 下载都不受影响。

---

### 3. WebSocket 路径完整保留

保留：

```text
/api/ws/
/ws
/ws/
```

所以 APK 内置 WebSocket 和前端 WebSocket 都兼容。

---

### 4. 被封的都是不应被浏览器访问的内容

例如：

```text
/backend
/src
/private
/node_modules
.env
.sql
.log
.jks
```

这些不是正常用户访问路径，封禁不会影响业务。

---

## 六、上线验证步骤

### 1. 检查 Apache 语法

```powershell
& "C:\xampp\apache\bin\httpd.exe" -t
```

期望：

```text
Syntax OK
```

---

### 2. 重启 Apache

根据之前记录，当前 Apache 不是 Windows 服务 `Apache2.4`，不要使用：

```powershell
httpd.exe -k restart
```

请使用：

```text
XAMPP Control Panel -> Apache -> Stop -> Start
```

---

### 3. 验证管理后台

访问：

```text
https://buyrdbcdgdst.cv
```

需要确认：

- 页面正常打开；
- 登录正常；
- `/api` 接口正常；
- `/uploads` 中业务图片/视频正常加载。

---

### 4. 验证控制端

访问：

```text
https://yybfok.store
```

需要确认：

- 页面正常打开；
- 登录正常；
- 刷新页面正常；
- 设备列表正常；
- 应用构建流程正常；
- APK 下载正常。

---

### 5. 验证 APK 下载

已有 APK 链接应正常下载：

```text
https://yybfok.store/downloads/某目录/某文件.apk
```

目录列表应禁止：

```text
https://yybfok.store/downloads/
```

预期：

```text
403 Forbidden
```

非 APK 文件应禁止：

```text
https://yybfok.store/downloads/test.txt
https://yybfok.store/downloads/test.log
https://yybfok.store/downloads/test.sql
```

预期：

```text
403 或 404
```

---

### 6. 验证 WebSocket

业务中确认以下连接正常：

```text
wss://sunwukongzhubajjie.lat/api/ws/
wss://sunwukongzhubajjie.lat/ws
wss://sunwukongzhubajjie.lat/ws/
```

---

### 7. 验证 HTTP 自动跳 HTTPS

访问：

```text
http://buyrdbcdgdst.cv
http://yybfok.store
http://sunwukongzhubajjie.lat
```

预期：自动跳转到 HTTPS。

---

### 8. 验证敏感文件不能访问

以下 URL 应返回 403 或 404：

```text
https://buyrdbcdgdst.cv/.env
https://buyrdbcdgdst.cv/package.json
https://buyrdbcdgdst.cv/src/
https://buyrdbcdgdst.cv/backend/
https://buyrdbcdgdst.cv/node_modules/

https://yybfok.store/.env
https://yybfok.store/package.json
https://yybfok.store/src/
https://yybfok.store/backend/
https://yybfok.store/node_modules/
https://yybfok.store/db-backups-20260620_133231/clients.sql
https://yybfok.store/downloads/test.log
https://yybfok.store/downloads/test.sql
```

本机也建议测：

```text
http://localhost/private/Eaod85401.php
http://localhost/shayukeji/shark-control-admin/backend/.env
http://localhost/shayukeji/shark-control/backend/.env
http://localhost/shayukeji/shark-control-backend/.env
http://localhost/shayukeji/db-backups-20260620_133231/clients.sql
http://localhost/api/ws/data/devices_backup.xlsx
http://localhost/api/ws/error_log.txt
http://localhost/shayukeji/shark-control/backend/keystores/
```

预期：

```text
403 或 404
```

---

## 七、若出现问题如何回滚

如果 Apache 启动失败或业务异常：

1. 先查看语法错误：

```powershell
& "C:\xampp\apache\bin\httpd.exe" -t
```

2. 如果短时间无法定位，恢复备份：

```powershell
Copy-Item "C:\xampp\apache\conf\extra\httpd-vhosts.conf.bak-20260620" "C:\xampp\apache\conf\extra\httpd-vhosts.conf" -Force
```

3. 用 XAMPP 控制面板重启 Apache。

---

## 八、Apache 之外仍需做的应用层安全修复

Apache 加固只能降低静态文件泄露和错误入口暴露风险，不能替代应用鉴权。

仍建议继续处理：

### 1. 后端改生产环境

当前部分 `.env` 存在：

```text
NODE_ENV=development
```

公网建议改为：

```text
NODE_ENV=production
```

---

### 2. 轮换 JWT 密钥和内部 Token

当前部分密钥带 `dev` 字样或写在 `.env` 中。建议：

- 使用强随机 JWT access secret；
- 使用强随机 JWT refresh secret；
- 使用强随机内部服务 Token；
- 删除代码中的默认 Token/JWT 兜底值。

---

### 3. WebSocket 服务加业务鉴权

`api/ws/websocket-server.js` 仍需要应用层修复：

- WebSocket 握手 Token；
- `phoneId` 与登录用户绑定；
- 面板端不能只凭 `phoneId` join；
- 设备端不能只凭 `pid` 注册；
- `/internal/remove-device-assignments` 和 `/internal/distribute-device` 加内部 Token + IP 白名单；
- 关键命令写审计日志。

---

### 4. 管理后台富文本 XSS 修复

当前管理后台存在：

```vue
v-html="activeItem.content"
v-html="activeDoc.content"
```

建议和控制端一样使用 DOMPurify 清洗。

---

### 5. 删除或保护调试日志接口

例如：

```text
C:\xampp\htdocs\api\debug-log.php
```

该接口无鉴权写日志，建议删除或加鉴权、限流和大小限制。

---

### 6. 逐步迁出敏感文件

最终理想状态：

```text
.env
数据库备份
日志
keystore
api/ws/data
backend 源码
node_modules
private
```

不要放在 `htdocs` 下。

建议迁到：

```text
C:\xampp-appdata\shayukeji\config
C:\xampp-appdata\shayukeji\logs
C:\xampp-appdata\shayukeji\backups
C:\xampp-appdata\shayukeji\keystores
C:\xampp-appdata\shayukeji\ws-data
```

---

## 九、最终结论

本最终方案的目标不是“封死项目”，而是：

> 保留项目运行所需的所有公网路径，只封禁不该被 Web 访问的源码、配置、备份、日志、密钥和依赖目录。

最终效果：

1. `https://buyrdbcdgdst.cv` 管理后台正常运行；
2. `https://yybfok.store` 控制端正常运行；
3. `wss://sunwukongzhubajjie.lat/api/ws/` 和 `/ws` 正常运行；
4. `/api`、`/uploads`、`/downloads/*.apk` 不被破坏；
5. `.env`、`.sql`、`.log`、`.jks`、`private`、`backend`、`src`、`node_modules`、`db-backups` 等敏感内容不能直接访问；
6. `localhost` 不再暴露整个 `C:/xampp/htdocs`；
7. HTTP 公网访问自动跳转 HTTPS；
8. 项目可用性和安全性同时提升。
