影刀RPA 流程合规检查清单:上线前的安全检查项
作者:林焱
什么情况用
写完一个流程,迫不及待想上线跑——但你真的确认它安全吗?
我见过太多这样的场景:流程在开发机上跑得好好的,上线第二天就出事了——不小心把生产数据库的订单表删了、批量发邮件时抄送了不该抄送的人、流程卡在一个弹窗上等了6小时直到超时。
流程上线和代码上线一样,需要走一遍安全检查清单。
核心场景:流程开发完成,准备上线运行前,逐一检查安全性、稳定性和合规性。
怎么做
第一步:安全检查清单
按这个顺序逐项打勾,别跳:
□ 1. 凭证明文检查
□ 2. 文件路径检查
□ 3. 网络请求检查
□ 4. 异常处理检查
□ 5. 数据安全与隐私检查
□ 6. 资源消耗检查
□ 7. 流程中止条件检查
□ 8. 日志与监控检查
□ 9. 版本与备份检查
□ 10. 灰度测试确认
第二步:逐项详解
1. 凭证明文检查
# ❌ 上线前必须清理的代码
API_KEY = "sk-abc123xyz456"
DB_PASSWORD = "MyP@ssw0rd!"
email_password = "app_pass_123"
# ✅ 正确做法
[video(video-8mL3e7it-1784481802357)(type-csdn)(url-https://live.csdn.net/v/embed/526818)(image-https://v-blog.csdnimg.cn/asset/582d14c3bd0451c5399cd990b56e2a0d/cover/Cover0.jpg)(title-拼多多店群自动化报活动上架!)]
import os
API_KEY = os.environ.get("RPA_API_KEY")
# 或从凭证管理器获取
检查方法:在代码里搜索 password、secret、token、key、api,确认没有硬编码的凭证。
2. 文件路径检查
# ❌ 绝对路径(换机器就跑不了)
file_path = "C:/Users/Administrator/Desktop/data.csv"
# ✅ 使用相对路径或配置化路径
file_path = os.path.join(RPA_DATA_DIR, "data.csv")
# ❌ 硬编码的系统临时目录
temp_dir = "C:/Windows/Temp"
# ✅ 用系统API获取
import tempfile
temp_dir = tempfile.gettempdir()
关键检查点:
- 输入文件路径是否正确(测试数据可能和生产数据不在同一位置)
- 输出文件路径是否会在生产环境产生权限问题
- 文件名是否包含时间戳(防止覆盖历史结果)
3. 网络请求检查
# ❌ 没有超时的请求
resp = requests.get("https://api.example.com/data")
# ✅ 必须设置超时
resp = requests.get("https://api.example.com/data", timeout=30)
# ❌ 没有重试机制
# ✅ 至少要处理网络异常
try:

resp = requests.post(url, json=data, timeout=30)
resp.raise_for_status()
except requests.exceptions.Timeout:
print(f"请求超时:{url}")
# 记录到失败队列
except requests.exceptions.RequestException as e:
print(f"请求失败:{e}")
检查清单:
- 所有网络请求设置了timeout
- 关键请求有重试逻辑
- 处理了可能的网络异常
- 频率限制(QPS)不会超过服务端限制
4. 异常处理检查
# ❌ 裸奔的代码——出错了流程直接挂
data = get_data_from_web()
process_data(data)
save_to_database(data)
# ✅ 必须要有异常处理
try:
data = get_data_from_web()
if not data:
raise ValueError("获取数据为空")
try:
result = process_data(data)
except Exception as e:
# 处理逻辑出错时,原始数据别丢
backup_raw_data(data, f"failed_{timestamp}.json")
raise
save_to_database(result)
except Exception as e:
# 至少通知运维
send_alert(f"流程异常:{e}")
# 记录详细日志
log_error(e, traceback.format_exc())
5. 数据安全与隐私检查
□ 导出的CSV/Excel中是否包含未经脱敏的个人信息
□ 日志文件是否会打印完整手机号/身份证号
□ 截图是否可能包含敏感信息
□ 邮件收件人列表是否正确(别把测试列表带到生产)
□ 数据库操作是否有限制条件(别忘记WHERE子句)
特别注意DELETE和UPDATE操作:
# ❌ 极其危险——没有WHERE条件
cursor.execute("DELETE FROM orders")
# ✅ 必须有限制条件,且限制条件来自明确的变量
cursor.execute("DELETE FROM orders WHERE status='cancelled' AND created_at < ?",
(threshold_date,))
# ✅ 危险操作前先SELECT确认影响范围
cursor.execute("SELECT COUNT(*) FROM orders WHERE status='cancelled'")
count = cursor.fetchone()[0]
print(f"将删除 {count} 条记录,确认后执行")
6. 资源消耗检查
□ 内存使用:大文件是否分块处理而不是一次性加载
□ 磁盘空间:输出文件是否会无限增长
□ CPU占用:是否有死循环
□ 数据库连接:是否用完就关闭(不是等垃圾回收)
□ 临时文件:是否及时清理
# ❌ 一次性加载大文件到内存
df = pd.read_csv("huge_file.csv") # 2GB的CSV直接爆内存
# ✅ 分块处理
chunk_size = 10000
for chunk in pd.read_csv("huge_file.csv", chunksize=chunk_size):
process(chunk) # 每次只处理10000行
7. 流程中止条件检查
□ 是否有可能无限循环?(while True必须有明确的退出条件)
□ 是否有超时机制?(整个流程最长跑多久)
□ 是否有手动中止的退出点?

□ 是否有条件分支处理了「数据为空」的情况?
8. 日志与监控检查
□ 运行是否记录了日志(时间、输入、输出、错误)
□ 失败时是否有人收到通知(企微/钉钉/邮件)
□ 是否方便事后排查问题(日志里有足够的上下文)
□ 日志文件是否会无限增长(是否设置了轮转或定期清理)
9. 版本与备份检查
□ 是否保存了上一个能正常运行的版本
□ 本次修改是否有变更记录(改了哪里、为什么改)
□ 能否一键回滚到上一个版本
□ 输入数据是否有备份(处理失败能重新来)
10. 灰度测试确认
在上全量之前,先小规模验证:
# 灰度测试模式
TEST_MODE = True # 上线前改为False
TEST_LIMIT = 10 # 只处理前10条
def process_items(items):
if TEST_MODE:
items = items[:TEST_LIMIT]
print(f"灰度模式:只处理前{TEST_LIMIT}条")

for item in items:
process(item)
if TEST_MODE:
print("灰度测试完成,确认结果无误后再关闭TEST_MODE")
第三步:快速自查脚本
写一个脚本自动扫描代码:
import os
import re
class SecurityScanner:
"""流程安全检查扫描器"""
# 危险模式
DANGER_PATTERNS = [
(r'(password|passwd|pwd|secret|token|api_key)\s*=\s*["\'][^"\']+["\']',
"硬编码凭证"),
(r'DELETE\s+FROM\s+\w+\s*$',
"危险的DELETE语句(缺少WHERE条件)"),
(r'UPDATE\s+\w+\s+SET\s+.*\s*$',
"危险的UPDATE语句(可能缺少WHERE条件)"),
(r'requests\.(get|post|put|delete)\([^)]*\)(?!.*timeout)',
"网络请求缺少timeout参数"),
(r'while\s+True',
"无限循环(检查是否有退出条件)"),
]
@classmethod
def scan_file(cls, filepath):
"""扫描单个文件"""
if not filepath.endswith(('.py', '.txt', '.md')):
return []
issues = []
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
for pattern, description in cls.DANGER_PATTERNS:
matches = re.finditer(pattern, content, re.IGNORECASE)
for m in matches:
# 计算行号
line_num = content[:m.start()].count('\n') + 1
issues.append({
"file": filepath,
"line": line_num,
"issue": description,
"snippet": m.group()[:80]
})
return issues
@classmethod
def scan_folder(cls, folder_path):
"""扫描整个文件夹"""
all_issues = []
for root, dirs, files in os.walk(folder_path):
for f in files:
filepath = os.path.join(root, f)
issues = cls.scan_file(filepath)
all_issues.extend(issues)
# 生成报告
print(f"\n===== 安全检查报告 =====")
print(f"扫描文件数:扫描完成")
print(f"发现问题:{len(all_issues)} 个\n")
for issue in all_issues:
print(f"[{issue['issue']}]")
print(f" 位置:{issue['file']}:{issue['line']}")
print(f" 代码:{issue['snippet']}")
print()
return all_issues
# 使用
# SecurityScanner.scan_folder("./my_rpa_scripts")
有什么坑
[video(video-OmvMMhHH-1784481809073)(type-csdn)(url-live.csdn.net/v/embed/526…)]
坑1:自以为简单的流程不需要检查
「就是个数据导出工具,哪会出问题?」——然后导出了生产数据库的全部客户信息,发到了一个外网邮箱。
原则:所有上线流程都要走一遍清单,哪怕是「只读不写」的流程也有隐私风险。
坑2:测试环境和生产环境混用
测试时连接的是测试数据库,上线时忘记改配置——流程连上了生产库,用测试逻辑去处理生产数据。
解决方法:环境配置独立管理,测试和生产用不同的配置文件、不同的凭证、不同的输出目录。
坑3:安全检查只在首次上线时做
流程迭代改了几个地方,觉得改动小不用再检查——然后一个新增的API调用没加timeout,半夜超时把整个流程卡死了。
解决方法:每次修改流程后,至少检查修改涉及的部分。重大版本更新走完整清单。
坑4:忽视操作系统的权限问题
在管理员权限下开发流程,流程可以随便读写文件。上线后用普通用户跑,结果 Permission denied。
解决方法:在和生产环境相同权限的账号下做最终测试。
坑5:流程回滚的代价被低估
没有保留上一个版本,新版本出问题只能临时修——修的过程中业务就断了。
解决方法:流程文件用Git管理,每个版本打tag。出问题 git checkout v1.2.3 就能切回去。
总结:上线前的安全检查不是形式主义,是无数踩坑经验的总结。走完这个清单能挡住90%的生产事故。剩下的10%,靠日志和监控及时发现问题。