关于python -m http.server的一些安全问题
在测试环境中使用 python -m http.server 8080 可以快速启动一个web服务,测试一些简单的网页,
但是如果要在公网发布页面还是存在一些安全问题的。
1. python -m http.server 的作用与安全风险
python -m http.server 8080 是 Python 内置的一个简单 HTTP 服务器,用于快速共享文件或调试。它的主要安全风险如下:
(1)默认暴露当前目录所有文件
- 启动后,任何人(包括外网)都能访问你当前工作目录及子目录的所有文件,存在信息泄露风险。
- 例如:cd /etc && python3 -m http.server 8080会导致
/etc目录下的敏感配置文件被公开访问。
(2)无身份验证与加密
- 传输为明文 HTTP,没有 HTTPS 加密,数据可能被中间人窃取或篡改。
- 没有密码保护,任何人都可访问服务器。
(3)潜在的执行风险
- 如果目录中存在可执行文件(如
.py、.sh),虽然默认不会执行,但攻击者可能通过其他方式诱导执行。 - 例如:上传恶意文件到可访问目录,再结合其他漏洞执行。
(4)性能与稳定性
- 该服务器为单线程,不适合高并发,易被 DDoS 攻击拖垮。
2. http.server 库的安全漏洞情况
官方维护状态:
http.server是 Python 标准库的一部分,安全漏洞会在新版本中修复。- 建议使用最新版本的 Python(如 3.12+)以获取安全补丁。
已知漏洞(历史):
- CVE-2019-9740:目录遍历漏洞(已修复)。
- CVE-2021-23336:请求解析缺陷(已修复)。
- CVE-2023-40217:HTTP 请求走私漏洞(已修复)。
结论:
- 最新版本的
http.server没有已知高危漏洞,但它的设计目标是开发调试,不适合生产环境。
3. 安全使用建议
(1)限制访问范围
- 绑定到本地回环地址:python3 -m http.server 8080 --bind 127.0.0.1仅允许本机访问。
- 或使用防火墙限制端口:sudo ufw allow from 192.168.1.0/24 to any port 8080
(2)使用临时目录
- 在空目录中启动服务器,避免暴露敏感文件:mkdir /tmp/web && cd /tmp/web && python3 -m http.server 8080
(3)启用身份验证
- 自定义
SimpleHTTPRequestHandler添加 Basic Auth:from http.server import SimpleHTTPRequestHandler import base64 class AuthHandler(SimpleHTTPRequestHandler): def do_AUTHHEAD(self): self.send_response(401) self.send_header('WWW-Authenticate', 'Basic realm=\"Test\"') self.send_header('Content-type', 'text/html') self.end_headers() def do_GET(self): if self.headers.get('Authorization') is None: self.do_AUTHHEAD() self.wfile.write(b'No auth header received') else: auth = self.headers.get('Authorization').split()[1] username, password = base64.b64decode(auth).decode().split(':') if username == 'admin' and password == 'password': SimpleHTTPRequestHandler.do_GET(self) else: self.do_AUTHHEAD() self.wfile.write(b'Invalid credentials') if __name__ == '__main__': from http.server import HTTPServer server = HTTPServer(('0.0.0.0', 8080), AuthHandler) server.serve_forever()
(4)使用 HTTPS
- 通过
ssl模块包装:openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out cert.pem python3 -m http.server 8080 --bind 0.0.0.0 --ssl-cert cert.pem --ssl-key key.pem
(5)生产环境替换方案
- Nginx:高性能、安全的静态文件服务器。
- Apache:支持复杂配置和访问控制。
- Flask/Django:带路由和权限管理的应用服务器。
4. 总结
- 漏洞情况:最新版本的
http.server无已知高危漏洞,但它不是为生产环境设计的。 - 安全风险:默认配置会暴露文件、无加密、无认证。
- 建议:
- 限制访问范围(
--bind 127.0.0.1)。 - 在空目录中运行。
- 添加身份验证和 HTTPS。
- 生产环境使用专业服务器。
- 限制访问范围(
如果临时使用,为了快速搭建一个应急用的服务器,这里有一个安全加固版的 Python HTTP 服务器脚本,它会包含以下安全特性:
安全特性
- 目录白名单:只允许访问指定目录,防止越权访问。
- 身份验证:支持 HTTP Basic Auth。
- HTTPS 加密:通过 SSL/TLS 加密传输。
- 访问日志:记录访问请求(方便审计)。
- 禁用目录列表:防止直接列出目录内容。
安全加固版 Python HTTP 服务器脚本
import os import ssl import base64 import logging from http.server import HTTPServer, SimpleHTTPRequestHandler # ===== 配置 ===== HOST = '0.0.0.0' # 监听地址,0.0.0.0 表示允许外网访问 PORT = 8080 # 监听端口 WHITELIST_DIR = '/tmp/web' # 允许访问的目录 USERNAME = 'admin' # 用户名 PASSWORD = 'securepass' # 密码 CERT_FILE = 'cert.pem' # SSL证书 KEY_FILE = 'key.pem' # SSL私钥 # 初始化日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('access.log'), logging.StreamHandler() ] ) class SecureHTTPRequestHandler(SimpleHTTPRequestHandler): def __init__(self, *args, **kwargs): # 切换到白名单目录 os.chdir(WHITELIST_DIR) super().__init__(*args, **kwargs) def do_AUTHHEAD(self): self.send_response(401) self.send_header('WWW-Authenticate', 'Basic realm=\"Secure File Server\"') self.send_header('Content-type', 'text/html') self.end_headers() def do_GET(self): # 1. 检查认证 auth_header = self.headers.get('Authorization') if not auth_header or not auth_header.startswith('Basic '): self.do_AUTHHEAD() self.wfile.write(b'401 Unauthorized: Authentication required.') logging.warning(f"Unauthorized access attempt from {self.client_address[0]}") return # 2. 验证用户名和密码 try: auth_decoded = base64.b64decode(auth_header.split(' ')[1]).decode('utf-8') username, password = auth_decoded.split(':') except Exception: self.do_AUTHHEAD() self.wfile.write(b'401 Unauthorized: Invalid credentials.') logging.warning(f"Invalid credentials from {self.client_address[0]}") return if username != USERNAME or password != PASSWORD: self.do_AUTHHEAD() self.wfile.write(b'401 Unauthorized: Invalid username or password.') logging.warning(f"Failed login from {self.client_address[0]}") return # 3. 检查路径是否在白名单目录内 path = self.translate_path(self.path) if not path.startswith(os.path.abspath(WHITELIST_DIR)): self.send_response(403) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(b'403 Forbidden: Access denied.') logging.warning(f"Directory traversal attempt from {self.client_address[0]}: {self.path}") return # 4. 禁用目录列表 if os.path.isdir(path): self.send_response(404) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(b'404 Not Found: Directory listing disabled.') logging.info(f"Directory listing attempt from {self.client_address[0]}: {self.path}") return # 5. 正常响应 logging.info(f"Access from {self.client_address[0]}: {self.path}") super().do_GET() def log_message(self, format, *args): # 自定义日志格式 logging.info(f"{self.client_address[0]} - {format % args}") def run_server(): # 创建服务器 server_address = (HOST, PORT) httpd = HTTPServer(server_address, SecureHTTPRequestHandler) # 启用HTTPS context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE) httpd.socket = context.wrap_socket(httpd.socket, server_side=True) print(f"Secure HTTP server running on https://{HOST}:{PORT}") print(f"Whitelisted directory: {WHITELIST_DIR}") try: httpd.serve_forever() except KeyboardInterrupt: print("\nServer stopped.") httpd.server_close() if __name__ == '__main__': # 检查目录是否存在 if not os.path.isdir(WHITELIST_DIR): os.makedirs(WHITELIST_DIR) print(f"Created whitelist directory: {WHITELIST_DIR}") # 检查证书和密钥 if not (os.path.isfile(CERT_FILE) and os.path.isfile(KEY_FILE)): print("Generating self-signed SSL certificate...") os.system(f"openssl req -newkey rsa:2048 -nodes -keyout {KEY_FILE} -x509 -days 365 -out {CERT_FILE} -subj '/CN=localhost'") run_server()
使用步骤
1. 保存脚本
将上面的代码保存为 secure_server.py。
2. 安装依赖
脚本使用 Python 标准库,无需额外安装依赖。
3. 生成 SSL 证书
首次运行会自动生成自签名证书:
python3 secure_server.py
4. 启动服务器
python3 secure_server.py
5. 访问测试
浏览器访问:
https://your-ip:8080
会提示输入用户名(admin)和密码(securepass)。
安全建议
- 密码:生产环境中建议使用强密码,并通过环境变量或配置文件读取,而不是硬编码。
- 证书:生产环境中建议使用可信 CA 签发的证书,而不是自签名证书。
- 防火墙:配合防火墙限制访问 IP 范围。
- 日志:定期查看
access.log以检测异常访问。
完。