python2批量改密码
批量服务器密码管理:Python实现的密码自动修改与上报系统
📌 系统背景
运维工作中经常需要批量修改服务器root密码。传统方式需要手动登录每台机器执行命令,效率低且容易出错。本文分享一套客户端/服务端架构的密码管理系统:客户端自动生成随机密码并修改本地root密码,然后将新密码上报给服务端统一记录。服务端支持多线程并发接收,并持久化保存到文件。
🏗️ 一、系统架构
整体流程:
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │ 客户端1 │─────▶│ │─────▶│ │ ├─────────────┤ │ 服务端 │ │ passwd.txt │ │ 客户端2 │─────▶│ (10.1.2.221 │─────▶│ (密码记录) │ ├─────────────┤ │ 端口9999) │ │ │ │ 客户端N │─────▶│ │─────▶│ │ └─────────────┘ └──────────────┘ └─────────────┘
| 组件 | 功能 | 技术要点 |
|---|---|---|
| 客户端 | 生成随机密码 → 修改root密码 → 上报服务端 | 支持本地执行(注释socket部分) |
| 服务端(v1) | 多线程接收客户端上报,保存到文件 | 使用threading实现并发 |
| 服务端(v2) | 使用socketserver重构,更健壮 | 内置线程池,自动处理连接 |
🖥️ 二、客户端代码详解
2.1 完整代码
# -*- coding: utf-8 -*- # 作者:GuoYabin # 功能:生成随机密码、修改root密码、上报服务端 # 如果注释最后三行socket发送,可只在本机修改密码(不发送数据到服务端) import random import string import os from socket import * # 服务端配置 serverip = '10.1.2.221' port = 9999 buffersize = 1024 addr = (serverip, port) # 连接服务端 client = socket(AF_INET, SOCK_STREAM) client.connect(addr) def Psswd(length): """生成指定长度的随机密码(字母+数字)""" chars = string.ascii_letters + string.digits return ''.join([random.choice(chars) for i in range(length)]) def get_wanip_info(): """获取本机内网IP(匹配10.1网段)""" get_ip_cmd = "ip add |awk '/10.1/ {print $2}'|grep -oP '(\d+.){3}\d+'" ethip = os.popen(get_ip_cmd).readline().strip() return ethip # 生成18位随机密码 passwd = Psswd(18) username = 'root' try: # 修改root密码(CentOS/RedHat系使用--stdin) os.system('echo %s | /usr/bin/passwd --stdin %s' % (passwd, username)) print(get_wanip_info(), '=>', passwd) print("root passwd change success!!!!") except: print("root passwd change error!!!!") # 上报密码到服务端 data = str(get_wanip_info() + '=>' + passwd) client.send('%s\r\n' % data) client.close()
2.2 关键函数解析
| 函数 | 实现原理 | 注意事项 |
|---|---|---|
Psswd(length) |
使用random.choice从字母+数字中随机选取 |
random模块的随机性足够密码使用,如需更高安全性可用secrets模块 |
get_wanip_info() |
执行shell命令ip add,用awk和grep提取10.1网段的IP |
依赖Linux的ip命令,不适用于Windows;正则匹配内网IP段 |
os.system('echo ...') |
使用passwd --stdin从标准输入读取密码 |
--stdin选项在部分Linux发行版中可能不可用,可用chpasswd替代 |
📡 三、服务端代码(v1版:多线程socket)
3.1 完整代码
# -*- coding: utf-8 -*- # 作者:GuoYabin # 功能:多线程接收客户端上报的密码,保存到文件 # 版本:v1 - 使用threading import socket import threading import time # 创建socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('10.1.2.221', 9999)) server.listen(10) print('Waiting for connection...') def tcplink(sock, addr): """处理单个客户端连接""" while True: try: data = sock.recv(1024) time.sleep(1) # 防止接收过快 # 断开条件 if not data or data.decode('utf-8') == 'exit': break # 安全验证:必须包含"=>"才认为是有效数据 if '=>' not in data.decode('utf-8'): print(f"非法数据 from {addr}: {data}") break # 打印并保存 print(data.decode('utf-8')) savepasswd(data) except Exception as e: print(f"处理连接出错: {e}") break sock.close() print(f"连接关闭: {addr}") def savepasswd(passwd): """将密码追加保存到文件""" now = time.strftime("%Y-%m-%d %H:%M:%S") with open('passwd.txt', 'a', encoding='utf-8') as f: f.write(f"{now} {passwd.decode('utf-8')}\n") # 主循环:接收连接并创建线程 while True: sock, addr = server.accept() print(f"新连接: {addr}") # 创建新线程处理每个连接 t = threading.Thread(target=tcplink, args=(sock, addr)) t.start()
🚀 四、服务端改良版(v2:socketserver实现)
v1版虽然能工作,但需要手动管理线程。Python标准库提供了socketserver模块,封装了多线程处理逻辑,代码更简洁、更健壮。
4.1 完整代码
# -*- coding:utf-8 -*- # 作者:GuoYabin # 功能:socketserver实现的密码接收服务端 # 版本:v2 - 使用socketserver.ThreadingTCPServer import socketserver import time class RecvPasswdHandler(socketserver.BaseRequestHandler): """自定义请求处理器""" def handle(self): """处理客户端连接(自动在线程中执行)""" conn = self.request # 客户端socket对象 client_addr = self.client_address print(f"新连接: {client_addr}") while True: try: data = conn.recv(1024).decode('utf-8').strip() # 断开条件 if data == 'exit': break if len(data) == 0: # 空数据表示连接关闭 break # 安全验证:必须包含"=>" if '=>' not in data: print(f"非法数据 from {client_addr}: {data}") break # 打印并保存 print(f"{client_addr}: {data}") self.savepasswd(data) except Exception as e: print(f"处理出错: {e}") break conn.close() print(f"连接关闭: {client_addr}") def savepasswd(self, passwd): """线程安全的文件写入""" now = time.strftime("%Y-%m-%d %H:%M:%S") # 使用with语句保证文件正确关闭 with open('passwd.txt', 'a', encoding='utf-8') as f: f.write(f"{now} {passwd}\n") if __name__ == '__main__': # 创建多线程TCP服务器 server = socketserver.ThreadingTCPServer(('0.0.0.0', 9999), RecvPasswdHandler) print("服务端启动成功,监听 0.0.0.0:9999") print("密码将保存到 passwd.txt") try: server.serve_forever() # 永久运行 except KeyboardInterrupt: print("\n服务端已停止") server.shutdown()
4.2 v1 vs v2 对比
| 对比项 | v1 (threading) | v2 (socketserver) |
|---|---|---|
| 代码行数 | 约50行 | 约40行(更简洁) |
| 线程管理 | 手动创建和管理线程 | 内置线程池,自动管理 |
| 错误处理 | 需要自行处理异常 | 框架层有更好的容错 |
| 扩展性 | 修改逻辑需要改动多处 | 继承Handler即可扩展 |
⚠️ 五、安全与优化建议
🔴 1. 密码传输安全
当前方案使用明文TCP传输密码,存在被窃听的风险。建议:
- 在局域网内使用(如公司内网)
- 或使用TLS/SSL加密传输(Python支持
ssl.wrap_socket) - 或对密码进行简单加密后再传输
🔴 2. 客户端安全
客户端代码中包含了服务端IP,如果被恶意获取,可能被用来发送假数据。建议:
- 客户端脚本设置适当的权限(700)
- 服务端增加简单的身份验证(如预共享密钥)
🔴 3. 密码强度
当前使用18位字母+数字组合,强度足够。如需更强密码,可以:
# 增加特殊字符 chars = string.ascii_letters + string.digits + "!@#$%^&*()" # 确保至少包含每种字符类型(可选)
🔴 4. 文件写入并发
多个线程同时写入同一个文件可能导致数据错乱。v2版虽然使用了with语句,但在高并发下仍有风险。建议:
- 使用队列+单线程写入
- 或使用数据库存储
- 或每个客户端写入独立文件
📝 六、使用说明
6.1 服务端部署
# 将服务端代码保存为 server.py python3 server.py # 后台运行(使用nohup或screen) nohup python3 server.py > server.log 2>&1 &
6.2 客户端部署
# 将客户端代码保存为 client.py,修改serverip为实际服务端IP python3 client.py # 批量执行(配合pssh或ansible) for ip in $(cat server_list.txt); do scp client.py root@$ip:/tmp/ ssh root@$ip "python3 /tmp/client.py" done
6.3 查看收集的密码
cat passwd.txt # 输出示例: 2026-03-11 15:30:22 10.1.2.100=>aB3dE7fGhJkL9mNpQrS 2026-03-11 15:30:25 10.1.2.101=>xYz2w4V6u8T0pR1sN3M
📊 七、总结
本文实现了一套完整的密码批量修改与上报系统:
- ✅ 客户端:自动生成随机密码、修改root密码、上报服务端
- ✅ 服务端v1:多线程socket实现,手动管理连接
- ✅ 服务端v2:socketserver重构,代码更简洁健壮
- ✅ 安全建议:明文传输风险、文件并发写入问题及解决方案
这套方案特别适合内网批量服务器密码轮换场景。如果需要在公网使用,务必增加加密传输和身份验证。
—— 本着方便的原则设计的密码管理系统,欢迎根据实际需求修改优化。

浙公网安备 33010602011771号