如何让Python HTTPServer仅响应指定设备?附退出机制疑问
家用光伏数据HTTP服务器安全加固与问题解答
一、实现特定MAC地址访问限制
HTTP协议无法直接获取客户端MAC地址,需通过ARP协议关联客户端IP与MAC地址来实现限制。具体操作如下:
- 提取请求的客户端IP地址
- 执行ARP命令查询该IP对应的MAC地址
- 对比MAC是否在允许列表内,不匹配则返回403禁止访问
修改后的核心代码示例:
import subprocess import os from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer import threading import signal # 替换成你要允许的设备MAC地址,支持多个 ALLOWED_MACS = {"aa:bb:cc:dd:ee:ff"} def get_mac_from_ip(ip): try: # 适配Linux系统的ARP命令查询 result = subprocess.check_output(["arp", "-n", ip], stderr=subprocess.STDOUT, text=True) for line in result.splitlines(): if ip in line: parts = line.split() if len(parts) >= 3: return parts[2].lower() return None except subprocess.CalledProcessError: return None def load_binary(filename): with open(filename, 'rb') as file_handle: return file_handle.read() class MyRequestHandler(BaseHTTPRequestHandler): def do_GET(self): # 先做MAC地址验证 client_ip = self.client_address[0] client_mac = get_mac_from_ip(client_ip) if client_mac not in ALLOWED_MACS: self.send_response(403) self.end_headers() self.wfile.write(b"Forbidden") return # 仅处理根路径请求 if self.path == '/': # 替换os.system为更安全的subprocess try: subprocess.run(["python3", "/home/pi/Plot_Generator_0_2.py"], check=True) mimetype='image/png' self.send_response(200) self.send_header('Content-type', mimetype) self.end_headers() self.wfile.write(load_binary('plot_image.png')) except subprocess.CalledProcessError: self.send_response(500) self.end_headers() self.wfile.write(b"Internal Server Error") return else: # 其他路径返回404 self.send_response(404) self.end_headers() self.wfile.write(b"Not Found") def signal_handler(sig, frame): print("Shutting down server...") server.shutdown() server.server_close() currentOS = os.name if currentOS != "nt": # Windows系统标识为"nt" server = ThreadingHTTPServer(('192.168.0.122', 5555), MyRequestHandler) # 捕获Ctrl+C信号,主动关闭服务器 signal.signal(signal.SIGINT, signal_handler) server_thread = threading.Thread(target=server.serve_forever) server_thread.daemon = True server_thread.start() server_thread.join()
二、Ctrl+C退出时的进程残留问题
- 你设置了
server_thread.daemon = True,主线程退出时守护线程会自动终止,但server.serve_forever()可能存在未释放的资源(比如端口)。 - 建议添加信号处理函数(如上代码中的
signal_handler),主动调用server.shutdown()和server.server_close(),确保服务器完全停止,避免残留进程或占用端口的情况。 - 无信号处理的场景下,大部分情况守护线程会随主线程退出,但主动处理能更稳妥地释放资源。
三、额外安全加固建议
- 替换
os.system为subprocess:os.system会创建shell进程,存在命令注入风险,subprocess.run更可控,能捕获执行错误,避免安全隐患。 - 添加HTTP基础认证:作为MAC过滤的第二层防护,在请求处理器中检查
Authorization头,只有携带正确账号密码的请求才能访问。 - 定时生成图表:不要在每次GET请求时执行绘图脚本,改为定时运行脚本生成最新图表,请求时直接返回静态文件,提升性能同时减少风险。
- 限制请求范围:除了根路径,其他所有路径直接返回404,避免暴露无关资源。
- 隐藏错误细节:错误响应中不要返回服务器内部信息(比如脚本路径、错误栈),仅返回通用提示。
内容的提问来源于stack exchange,提问作者Kenglaze
相关产品推荐
相关产品推荐

