You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Python HTTPServer仅响应指定设备?附退出机制疑问

家用光伏数据HTTP服务器安全加固与问题解答

一、实现特定MAC地址访问限制

HTTP协议无法直接获取客户端MAC地址,需通过ARP协议关联客户端IP与MAC地址来实现限制。具体操作如下:

  1. 提取请求的客户端IP地址
  2. 执行ARP命令查询该IP对应的MAC地址
  3. 对比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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 01:20:22