基于xterm.js与Django的终端文本编辑器检测及别名管控问询
解决xterm.js+Django环境下禁止终端别名并检测文本编辑器运行的问题
一、完全禁止用户使用别名的可行方案
要解决别名导致关键词过滤失效的问题,最直接的方案是彻底禁用bash的别名功能,具体可通过以下几个层面实现:
- 启动bash时跳过用户配置文件:使用
--noprofile --norc参数,避免加载~/.bashrc或~/.bash_profile中定义的别名 - 清空所有已存在的别名:执行
unalias -a命令,确保当前会话内无任何别名残留 - 关闭别名扩展功能:通过
set +o expand_aliases彻底禁用bash的别名解析能力
这样用户无法创建或使用任何别名,原有的关键词过滤方案就能准确检测nano/vim等编辑器的直接调用。
二、代码实现示例
1. Django 后端 views.py 代码
from django.http import HttpResponse from django.views.decorators.http import require_http_methods import subprocess import os import threading import time from django.middleware.csrf import get_token # 存储终端进程,用session_id做标识 terminal_processes = {} # 编辑器命令黑名单 EDITOR_BLACKLIST = {'nano', 'vim', 'vi', 'emacs'} @require_http_methods(["GET"]) def terminal_connect(request): session_id = request.GET.get('session_id', '') if not session_id: return HttpResponse("Missing session_id", status=400) # 启动禁用别名的bash会话:跳过配置文件+清空别名+关闭别名扩展 startup_cmd = 'unalias -a; set +o expand_aliases; exec /bin/bash' process = subprocess.Popen( ['/bin/bash', '--noprofile', '--norc', '-c', startup_cmd], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, start_new_session=True, preexec_fn=os.setsid, text=True ) terminal_processes[session_id] = process # 后台线程:记录终端输出+检测编辑器调用 def monitor_and_log(): while process.poll() is None: output = process.stdout.readline() if not output: continue # 写入终端会话日志 with open(f'terminal_session_{session_id}.log', 'a', encoding='utf-8') as f: f.write(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {output}") # 检测编辑器命令并记录 for cmd in EDITOR_BLACKLIST: if cmd in output.lower().strip(): with open('editor_usage.log', 'a', encoding='utf-8') as f: f.write(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Session {session_id} executed editor: {output.strip()}\n") break threading.Thread(target=monitor_and_log, daemon=True).start() return HttpResponse("Terminal session started", status=200) @require_http_methods(["POST"]) def terminal_input(request): session_id = request.POST.get('session_id', '') input_data = request.POST.get('input', '') process = terminal_processes.get(session_id) if not process or process.poll() is not None: return HttpResponse("Terminal session not found or exited", status=404) process.stdin.write(input_data) process.stdin.flush() return HttpResponse("Input sent", status=200) # 前端获取CSRF Token的接口(可选) def get_csrf_token(request): return HttpResponse(get_token(request))
2. 前端 index.html 代码(xterm.js 5.2.1)
<!DOCTYPE html> <html> <head> <title>Web Terminal</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.2.1/css/xterm.css" /> <script src="https://cdn.jsdelivr.net/npm/xterm@5.2.1/lib/xterm.js"></script> <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.7.0/lib/xterm-addon-fit.js"></script> </head> <body> <div id="terminal-container" style="width: 90vw; height: 80vh; margin: 20px auto;"></div> <input type="hidden" name="csrfmiddlewaretoken" id="csrf-token"> <script> // 初始化终端 const term = new Terminal({ cursorBlink: true, fontSize: 14, scrollback: 1000, theme: { background: '#1a1a1a', foreground: '#e0e0e0', cursor: '#ffffff' } }); const fitAddon = new FitAddon.FitAddon(); term.loadAddon(fitAddon); term.open(document.getElementById('terminal-container')); fitAddon.fit(); // 生成唯一会话ID const sessionId = `term_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; // 获取CSRF Token fetch('/get-csrf-token') .then(res => res.text()) .then(token => document.getElementById('csrf-token').value = token); // 连接后端终端会话 fetch(`/terminal/connect?session_id=${sessionId}`) .catch(err => console.error('Failed to connect terminal:', err)); // 监听终端输入,发送到后端 term.onData(data => { fetch('/terminal/input', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRFToken': document.getElementById('csrf-token').value }, body: `session_id=${sessionId}&input=${encodeURIComponent(data)}` }); }); // 注:生产环境建议用WebSocket替代轮询实现实时输出推送,以下为简化示例 setInterval(() => { // 此处需补充后端获取终端输出的接口逻辑 // 示例省略,实际可通过WebSocket实时接收后端推送的终端输出并写入term }, 100); </script> </body> </html>
三、额外注意事项
- 上述方案中,bash启动命令不会在前端终端中显示,完全后台执行
- 日志记录逻辑在后台线程中运行,不影响终端的正常交互
- 生产环境务必用WebSocket替代轮询,实现终端输出的实时推送,提升用户体验
- 可根据需求扩展
EDITOR_BLACKLIST,添加更多需要检测的编辑器或命令
内容的提问来源于stack exchange,提问作者ivenoidea
相关产品推荐
相关产品推荐

