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重构,代码更简洁健壮
  • 安全建议:明文传输风险、文件并发写入问题及解决方案

这套方案特别适合内网批量服务器密码轮换场景。如果需要在公网使用,务必增加加密传输和身份验证。


—— 本着方便的原则设计的密码管理系统,欢迎根据实际需求修改优化。

posted @ 2017-10-31 13:56  一起走过的路  阅读(452)  评论(0)    收藏  举报