183 lines
4.9 KiB
Markdown
183 lines
4.9 KiB
Markdown
# 部署脚本安全指南
|
||
|
||
## ⚠️ 安全风险说明
|
||
|
||
如果将这些脚本开源,需要注意以下安全风险:
|
||
|
||
### 1. 密码泄露风险
|
||
|
||
**风险等级:高**
|
||
|
||
- **问题**:脚本从 `.env` 文件读取密码,如果 `.env` 文件被意外提交到 Git,密码会泄露
|
||
- **缓解措施**:
|
||
- ✅ `.env` 已在 `.gitignore` 中(已确认)
|
||
- ✅ 脚本中不包含硬编码的密码
|
||
- ⚠️ 建议添加 `.env.example` 文件作为模板(不包含真实密码)
|
||
|
||
### 2. 密码在进程列表中可见
|
||
|
||
**风险等级:中**
|
||
|
||
- **问题**:使用 `sshpass -p "password"` 时,密码会出现在进程列表中(`ps aux`)
|
||
- **缓解措施**:
|
||
- ✅ 优先使用 SSH 密钥认证(推荐)
|
||
- ⚠️ 如果必须使用密码,考虑使用环境变量或 `sshpass -e`(从环境变量读取)
|
||
|
||
### 3. Sudo 密码传递方式不安全
|
||
|
||
**风险等级:中**
|
||
|
||
- **问题**:使用 `echo 'password' | sudo -S` 时,密码可能出现在命令历史或进程列表中
|
||
- **缓解措施**:
|
||
- ⚠️ 建议配置免密 sudo(更安全)
|
||
- ⚠️ 或者使用 `expect` 脚本(但增加了复杂性)
|
||
|
||
### 4. 命令注入风险
|
||
|
||
**风险等级:中**
|
||
|
||
- **问题**:如果配置值包含特殊字符(如 `;`、`|`、`&`),可能导致命令注入
|
||
- **当前保护**:
|
||
- ✅ 使用双引号包裹变量
|
||
- ✅ 密码转义单引号
|
||
- ⚠️ 但路径变量(如 `tempPath`)未完全转义
|
||
|
||
### 5. SSH 安全选项
|
||
|
||
**风险等级:低**
|
||
|
||
- **问题**:`StrictHostKeyChecking=no` 禁用了主机密钥验证
|
||
- **说明**:这是为了自动化部署的便利性,但降低了安全性
|
||
- **建议**:在生产环境首次连接后,应该使用已知主机文件
|
||
|
||
## 🔒 安全建议
|
||
|
||
### 1. 使用 SSH 密钥认证(强烈推荐)
|
||
|
||
```bash
|
||
# 生成 SSH 密钥对
|
||
ssh-keygen -t ed25519 -C "deploy@aitu"
|
||
|
||
# 将公钥添加到服务器
|
||
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
|
||
|
||
# 在 .env 中配置
|
||
DEPLOY_SSH_KEY=~/.ssh/id_ed25519
|
||
```
|
||
|
||
### 2. 配置免密 Sudo(推荐)
|
||
|
||
在服务器上配置:
|
||
|
||
```bash
|
||
# 编辑 sudoers 文件
|
||
sudo visudo
|
||
|
||
# 添加以下行(将 username 替换为实际用户名)
|
||
username ALL=(ALL) NOPASSWD: /bin/cp, /bin/rm, /usr/sbin/nginx, /bin/systemctl, /usr/sbin/service
|
||
```
|
||
|
||
### 3. 使用环境变量传递密码(如果必须)
|
||
|
||
修改脚本使用环境变量:
|
||
|
||
```bash
|
||
# 在 .env 中不存储密码,而是使用环境变量
|
||
export DEPLOY_SSH_PASSWORD="your-password"
|
||
export DEPLOY_SUDO_PASSWORD="your-sudo-password"
|
||
|
||
# 使用 sshpass -e(从环境变量读取)
|
||
sshpass -e ssh ...
|
||
```
|
||
|
||
### 4. 限制 SSH 密钥权限
|
||
|
||
```bash
|
||
# 使用受限的 SSH 密钥(只能执行特定命令)
|
||
# 在服务器的 ~/.ssh/authorized_keys 中添加:
|
||
command="/usr/bin/sudo /bin/cp /tmp/*.conf /etc/nginx/sites-enabled/",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAAC3...
|
||
```
|
||
|
||
### 5. 使用专用部署用户
|
||
|
||
- 创建专门的部署用户(如 `deploy`)
|
||
- 限制该用户的权限
|
||
- 只允许执行必要的命令
|
||
|
||
### 6. 添加 `.env.example` 文件
|
||
|
||
创建示例配置文件,不包含真实密码:
|
||
|
||
```bash
|
||
# .env.example
|
||
DEPLOY_HOST=your-server.com
|
||
DEPLOY_USER=username
|
||
DEPLOY_PORT=22
|
||
DEPLOY_SSH_KEY=~/.ssh/id_rsa
|
||
# DEPLOY_SSH_PASSWORD= # 不推荐,使用 SSH 密钥
|
||
# DEPLOY_SUDO_PASSWORD= # 建议配置免密 sudo
|
||
```
|
||
|
||
## 📋 开源前检查清单
|
||
|
||
- [ ] 确认 `.env` 在 `.gitignore` 中
|
||
- [ ] 创建 `.env.example` 文件(不包含真实密码)
|
||
- [ ] 检查脚本中是否有硬编码的服务器地址、密码等
|
||
- [ ] 添加安全警告注释到脚本顶部
|
||
- [ ] 在 README 中添加安全使用说明
|
||
- [ ] 考虑添加命令注入防护(更严格的输入验证)
|
||
|
||
## 🛡️ 改进建议
|
||
|
||
### 1. 增强命令注入防护
|
||
|
||
```javascript
|
||
// 转义 shell 特殊字符
|
||
function escapeShellArg(str) {
|
||
return "'" + str.replace(/'/g, "'\\''") + "'";
|
||
}
|
||
|
||
// 使用转义函数
|
||
const safePath = escapeShellArg(tempPath);
|
||
const safeRemotePath = escapeShellArg(remotePath);
|
||
```
|
||
|
||
### 2. 使用更安全的密码传递方式
|
||
|
||
```javascript
|
||
// 使用环境变量而不是命令行参数
|
||
if (config.DEPLOY_SSH_PASSWORD) {
|
||
process.env.SSHPASS = config.DEPLOY_SSH_PASSWORD;
|
||
scpCommand = 'sshpass -e scp';
|
||
}
|
||
```
|
||
|
||
### 3. 添加输入验证
|
||
|
||
```javascript
|
||
// 验证服务器地址格式
|
||
function validateHost(host) {
|
||
const hostPattern = /^[a-zA-Z0-9.-]+$/;
|
||
if (!hostPattern.test(host)) {
|
||
throw new Error('Invalid host format');
|
||
}
|
||
}
|
||
```
|
||
|
||
## 📝 总结
|
||
|
||
**当前安全状态**:
|
||
- ✅ 基本安全措施已到位(`.env` 在 `.gitignore` 中)
|
||
- ⚠️ 密码传递方式可以改进
|
||
- ⚠️ 建议优先使用 SSH 密钥和免密 sudo
|
||
|
||
**开源风险评估**:
|
||
- **低风险**:如果用户遵循最佳实践(使用 SSH 密钥、免密 sudo)
|
||
- **中风险**:如果用户使用密码认证,密码可能泄露
|
||
|
||
**建议**:
|
||
1. 在脚本顶部添加安全警告
|
||
2. 在 README 中强调使用 SSH 密钥认证
|
||
3. 提供 `.env.example` 文件
|
||
4. 考虑添加更严格的输入验证
|