fix(security): 移除硬编码凭据与内网信息,改为环境变量注入

这个提交包含在:
2026-09-07 09:20:28 +08:00
父节点 20aec2bf26
当前提交 2383cd6e21
共修改 7 个文件,包含 113 行新增和 19 行删除
+13
查看文件
@@ -0,0 +1,13 @@
# 复制本文件为 .env 并按实际环境填写(.env 已被 .gitignore 忽略,切勿提交真实凭据)
# 服务器列表(JSON 数组),多个服务器用逗号分隔
SERVERS_JSON=[{"name":"web1","ip":"192.168.1.10","username":"root","password":"change-me"}]
# 是否开启 Flask 调试模式(生产环境务必保持 0)
FLASK_DEBUG=0
# 以下变量仅供 test.py 使用
# SSH_HOST=192.168.1.10
# SSH_PORT=22
# SSH_USER=root
# SSH_PASSWORD=change-me
+7
查看文件
@@ -164,3 +164,10 @@ cython_debug/
/.idea/ /.idea/
/.vscode/ /.vscode/
# 项目本地数据:运行日志与截图(可能含内网信息,禁止提交)
logs/
*.png
# 历史清理临时文件
replacements.txt
+17 -7
查看文件
@@ -1,4 +1,6 @@
from flask import Flask, render_template, request, redirect, url_for,jsonify from flask import Flask, render_template, request, redirect, url_for,jsonify
import json
import os
import threading import threading
import time import time
import logging import logging
@@ -46,12 +48,18 @@ def setup_logging():
setup_logging() setup_logging()
# 模拟的服务器信息,可以根据实际需求进行动态配置 # 服务器列表通过环境变量 SERVERS_JSON 注入(JSON 数组),避免在代码中硬编码 IP / 账号 / 密码
servers = [ # 格式: [{"name": "web1", "ip": "192.168.1.10", "username": "root", "password": "xxx"}]
{"name": "现场端侧070", "ip": "***REMOVED***", "username": "root", "password": "***REMOVED***"}, # 配置方式参考 .env.example
{"name": "测试服务器", "ip": "***REMOVED***", "username": "root", "password": "***REMOVED***"}, _servers_env = os.environ.get("SERVERS_JSON", "").strip()
{"name": "Server2", "ip": "192.168.1.2", "username": "user2", "password": "password2"}, if _servers_env:
] try:
servers = json.loads(_servers_env)
except json.JSONDecodeError as e:
raise SystemExit(f"SERVERS_JSON 环境变量不是合法 JSON: {e}")
else:
servers = []
logging.warning("未设置 SERVERS_JSON 环境变量,服务器列表为空,请参考 .env.example 进行配置")
# 全局变量存储服务器状态 # 全局变量存储服务器状态
server_status = {} server_status = {}
@@ -249,4 +257,6 @@ def control():
if __name__ == '__main__': if __name__ == '__main__':
# 启动定时任务 # 启动定时任务
start_scheduler() start_scheduler()
app.run(host='0.0.0.0',port=8090,debug=True) # debug 模式默认关闭:开启后 Werkzeug 调试器会暴露在网络上,存在远程代码执行风险
debug = os.environ.get("FLASK_DEBUG", "0").lower() in ("1", "true", "yes")
app.run(host='0.0.0.0', port=8090, debug=debug)
+4
查看文件
@@ -4,6 +4,10 @@ services:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
container_name: linux_controller container_name: linux_controller
environment:
# 服务器列表从环境变量注入(写入项目根目录 .env 文件即可,compose 会自动读取)
- SERVERS_JSON=${SERVERS_JSON:-}
- FLASK_DEBUG=${FLASK_DEBUG:-0}
ports: ports:
- "8090:8090" - "8090:8090"
volumes: volumes:
+51 -5
查看文件
@@ -1,7 +1,53 @@
linux服务器控制 # linux_controller
PC端: 基于 Flask + Paramiko 的 Linux 服务器批量监控与开关机控制面板(PC / 移动端自适应)。
http://***REMOVED***:8090/m
移动端:
http://***REMOVED***:8090/m
## 功能
- 定时(60 秒)通过 SSH 采集各服务器 `top` 指标:CPU / 内存 / 负载 / 任务状态等
- Web 页面展示服务器状态,支持远程关机 / 重启(带二次确认弹窗)
## 快速开始
### 1. 配置服务器列表
复制 `.env.example` 为 `.env`,填写 `SERVERS_JSON`(JSON 数组,包含 name / ip / username / password)。
`.env` 已被 `.gitignore` 忽略,**切勿提交真实凭据**。
### 2. 本地运行
```bash
pip install -r requirements.txt
```
Linux / macOS:
```bash
export SERVERS_JSON='[{"name":"demo","ip":"192.168.1.10","username":"root","password":"your-password"}]'
python app.py
```
Windows PowerShell:
```powershell
$env:SERVERS_JSON='[{"name":"demo","ip":"192.168.1.10","username":"root","password":"your-password"}]'
python app.py
```
### 3. Docker 运行
在项目根目录 `.env` 文件中配置 `SERVERS_JSON` 后:
```bash
docker compose up -d --build
```
访问 `http://<主机IP>:8090/`(PC 端)、`http://<主机IP>:8090/m`(移动端)。
## 安全建议(部署前必读)
- **切勿将服务直接暴露在公网**:本应用未内置登录认证与 CSRF 防护,任何能访问到它的人都可以远程关机 / 重启受控服务器。请仅部署在内网,并通过防火墙、VPN 或反向代理(BasicAuth 等)做访问控制。
- 服务器凭据一律通过环境变量注入,不要写回代码或提交到仓库。
- 代码中 `AutoAddPolicy()` 会自动接受未知主机指纹,存在中间人风险;对安全要求较高的环境请改为 `RejectPolicy` 并预置 known_hosts。
- 建议 SSH 使用密钥认证代替密码认证。
- 生产环境保持 `FLASK_DEBUG` 关闭(默认已关闭)。
+7 -1
查看文件
@@ -1 +1,7 @@
scp -r ./* root@***REMOVED***:/data/linux_controller/ #!/bin/bash
# 用法: ./send.sh <user@host> [目标目录]
# 示例: ./send.sh root@192.168.1.100
TARGET="${1:?用法: ./send.sh <user@host> [目标目录]}"
DEST_DIR="${2:-/data/linux_controller}"
scp -r ./* "$TARGET:$DEST_DIR/"
+13 -5
查看文件
@@ -1,13 +1,21 @@
import os
import sys
import paramiko import paramiko
# 配置连接参数 # 连接参数从环境变量读取,避免在代码中硬编码任何真实凭据
hostname = "***REMOVED***" # 远程服务器的 IP 地址 # 可参考 .env.example 配置;生产环境建议改用 SSH 密钥认证
port = 22 # SSH 端口,通常是 22 hostname = os.environ.get("SSH_HOST", "")
username = "root" # SSH 用户名 port = int(os.environ.get("SSH_PORT", "22"))
password = "***REMOVED***" # SSH 密码,或使用密钥认证 username = os.environ.get("SSH_USER", "")
password = os.environ.get("SSH_PASSWORD", "")
# SSH 连接并执行关机命令 # SSH 连接并执行关机命令
def shutdown_server(): def shutdown_server():
if not all([hostname, username, password]):
print("请先通过环境变量配置 SSH_HOST / SSH_USER / SSH_PASSWORD(可参考 .env.example)")
sys.exit(1)
try: try:
# 创建 SSH 客户端对象 # 创建 SSH 客户端对象
client = paramiko.SSHClient() client = paramiko.SSHClient()