from flask import Flask, request, jsonify, render_template_string import requests from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_v1_5 import base64 import time from datetime import datetime
app = Flask(__name__)
RSA_PUBLIC_KEY = """-----BEGIN PUBLIC KEY----- MIGfMxxxxxx -----END PUBLIC KEY-----"""
TARGET_URL = "http://xxx.xxxxxx.xxx/xxxxxxLogin.do"
def rsa_encrypt_long(data, chunk_size=117): """ RSA分段加密函数 对于1024位密钥,每个块最大117字节[1,5](@ref) """ try: rsa_key = RSA.import_key(RSA_PUBLIC_KEY) cipher = PKCS1_v1_5.new(rsa_key) data_bytes = data.encode('utf-8') encrypted_chunks = [] for i in range(0, len(data_bytes), chunk_size): chunk = data_bytes[i:i + chunk_size] encrypted_chunk = cipher.encrypt(chunk) encrypted_chunks.append(encrypted_chunk) encrypted_data = b''.join(encrypted_chunks) return base64.b64encode(encrypted_data).decode('utf-8') except Exception as e: raise Exception(f"RSA分段加密失败: {str(e)}")
@app.route('/') def index(): """显示前端界面""" return render_template_string(''' <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>RSA分段加密登录代理</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; padding: 20px; display: flex; justify-content: center; align-items: center; } .container { background: white; border-radius: 10px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); overflow: hidden; width: 100%; max-width: 900px; } .header { background: #2c3e50; color: white; padding: 20px; text-align: center; } .content { display: flex; min-height: 600px; } .input-section { flex: 1; padding: 30px; border-right: 1px solid #eee; background: #f8f9fa; } .output-section { flex: 1; padding: 30px; background: white; display: flex; flex-direction: column; } .form-group { margin-bottom: 20px; } label { display: block; margin-bottom: 8px; font-weight: 600; color: #2c3e50; } input[type="text"], input[type="password"], textarea { width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 5px; font-size: 14px; transition: border-color 0.3s; } textarea { height: 100px; resize: vertical; } input:focus, textarea:focus { outline: none; border-color: #667eea; box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1); } button { background: #667eea; color: white; border: none; padding: 12px 24px; border-radius: 5px; cursor: pointer; font-size: 16px; font-weight: 600; transition: background 0.3s; width: 100%; } button:hover { background: #5a6fd8; } button:disabled { background: #ccc; cursor: not-allowed; } .response-info { flex: 1; display: flex; flex-direction: column; } .status { padding: 10px; border-radius: 5px; margin-bottom: 15px; font-weight: 600; } .status.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .status.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .timing-info { background: #e9ecef; padding: 15px; border-radius: 5px; margin-bottom: 15px; font-size: 14px; } .response-content { background: #f8f9fa; border: 1px solid #e9ecef; border-radius: 5px; padding: 15px; flex: 1; overflow-y: auto; font-family: 'Courier New', monospace; font-size: 12px; white-space: pre-wrap; word-wrap: break-word; } .loading { display: none; text-align: center; padding: 20px; } .spinner { border: 3px solid #f3f3f3; border-top: 3px solid #667eea; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; margin: 0 auto 10px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } h3 { margin-bottom: 20px; color: #2c3e50; border-bottom: 2px solid #667eea; padding-bottom: 10px; } .info-text { background: #e7f3ff; padding: 10px; border-radius: 5px; margin-bottom: 15px; font-size: 13px; color: #0066cc; } </style> </head> <body> <div class="container"> <div class="header"> <h1>RSA分段加密登录代理系统</h1> <p>支持长文本加密 • 自动分段处理 • 实时响应监控</p> </div> <div class="content"> <div class="input-section"> <h3>登录信息</h3> <div class="info-text"> <strong>技术支持:</strong>使用RSA分段加密技术,支持加密超长文本内容(最大支持32KB) </div> <div class="form-group"> <label for="username">用户名:</label> <input type="text" id="username" placeholder="请输入用户名(支持长用户名)" value="这是一个可能很长的用户名示例,可以包含特殊字符、数字和中文测试内容"> </div> <div class="form-group"> <label for="password">密码:</label> <input type="password" id="password" placeholder="请输入密码(支持长密码)" value="这是一个可能很长的密码示例,可以包含特殊字符、数字和中文测试内容,甚至可以是整个段落的文本"> </div> <div class="form-group"> <label for="serverId">服务器ID:</label> <input type="text" id="serverId" value="a47f73e97d5943eba7676f1f3fefd5e8"> </div> <button id="sendButton" onclick="sendLoginRequest()">发送登录请求(分段加密)</button> <div class="loading" id="loading"> <div class="spinner"></div> <p>正在加密并发送请求,请稍候...</p> </div> </div> <div class="output-section"> <h3>服务器响应</h3> <div id="responseContainer" class="response-info"> <p>请求结果将显示在这里...</p> </div> </div> </div> </div>
<script> async function sendLoginRequest() { const button = document.getElementById('sendButton'); const loading = document.getElementById('loading'); const responseContainer = document.getElementById('responseContainer'); // 获取输入值 const username = document.getElementById('username').value.trim(); const password = document.getElementById('password').value.trim(); const serverId = document.getElementById('serverId').value.trim(); if (!username || !password) { showResponse('error', '错误', '用户名和密码不能为空'); return; } // 显示加载状态 button.disabled = true; loading.style.display = 'block'; responseContainer.innerHTML = '<p>正在加密并发送请求...</p>'; try { // 记录客户端开始时间 const clientStartTime = Date.now(); // 发送请求到Flask后端 const response = await fetch('/proxy-login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username: username, password: password, xxx: xxx }) }); // 计算客户端收到响应的时间 const clientTime = Date.now() - clientStartTime; const data = await response.json(); if (data.success) { showResponse('success', '请求成功', data, clientTime); } else { showResponse('error', '请求失败', data.message); } } catch (error) { console.error('Error:', error); showResponse('error', '网络错误', '无法连接到代理服务器: ' + error.message); } finally { // 恢复按钮状态 button.disabled = false; loading.style.display = 'none'; } } function showResponse(type, title, content, clientTime = 0) { const responseContainer = document.getElementById('responseContainer'); let contentHtml = ''; if (typeof content === 'object' && content.timing) { // 成功响应,显示详细时间信息和响应内容 contentHtml = ` <div class="timing-info"> <strong>加密统计:</strong><br> 原始用户名长度: ${content.encryption_info.original_username_length}字符<br> 原始密码长度: ${content.encryption_info.original_password_length}字符<br> 加密后用户名长度: ${content.encryption_info.encrypted_username_length}字符<br> 加密后密码长度: ${content.encryption_info.encrypted_password_length}字符<br> 分段加密块数: ${content.encryption_info.chunk_count}块 </div> <div class="timing-info"> <strong>时间统计:</strong><br> 服务端总耗时: ${content.timing.total_response_time}秒<br> 加密时间: ${content.timing.encryption_time}秒<br> API调用时间: ${content.timing.api_call_time}秒<br> 客户端收到响应: ${clientTime}毫秒<br> 请求ID: ${content.request_id} </div> <div> <strong>目标服务器响应:</strong> <div class="response-content"> 状态码: ${content.target_server_response.status_code}
响应头: ${JSON.stringify(content.target_server_response.headers, null, 2)}
响应内容: ${content.target_server_response.content} </div> </div> `; } else if (typeof content === 'object') { contentHtml = `<div class="response-content">${JSON.stringify(content, null, 2)}</div>`; } else { contentHtml = `<p>${content}</p>`; } responseContainer.innerHTML = ` <div class="status ${type}">${title}</div> ${contentHtml} `; } // 页面加载完成后自动聚焦到用户名输入框 document.addEventListener('DOMContentLoaded', function() { document.getElementById('username').focus(); }); // 支持按Enter键提交 document.addEventListener('keypress', function(event) { if (event.key === 'Enter') { sendLoginRequest(); } }); </script> </body> </html> ''')
@app.route('/proxy-login', methods=['POST']) def proxy_login(): """代理登录接口:接收明文,分段加密后转发到目标服务器""" start_time = time.time() request_id = f"req_{datetime.now().strftime('%H%M%S%f')[:-3]}" try: data = request.get_json() if not data: return jsonify({ 'success': False, 'message': '无效的请求数据', 'response_time': time.time() - start_time, 'request_id': request_id }), 400 username = data.get('username', '').strip() password = data.get('password', '').strip() server_id = data.get('xxx', 'xxx') if not username or not password: return jsonify({ 'success': False, 'message': '用户名和密码不能为空', 'response_time': time.time() - start_time, 'request_id': request_id }), 400 encrypt_start = time.time() encrypted_user = rsa_encrypt_long(username) encrypted_password = rsa_encrypt_long(password) encrypt_time = time.time() - encrypt_start chunk_size = 117 username_chunks = (len(username.encode('utf-8')) + chunk_size - 1) // chunk_size password_chunks = (len(password.encode('utf-8')) + chunk_size - 1) // chunk_size headers = { 'Host': 'xxx.xxx.xxx.xxx', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Content-Type': 'application/json; charset=UTF-8', 'token': '', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive' } request_data = { "user": encrypted_user, "password": encrypted_password, "xxx": xxx } api_start = time.time() target_response = requests.post( TARGET_URL, headers=headers, json=request_data, timeout=30 ) api_time = time.time() - api_start total_time = time.time() - start_time return jsonify({ 'success': True, 'request_id': request_id, 'timing': { 'total_response_time': round(total_time, 4), 'encryption_time': round(encrypt_time, 4), 'api_call_time': round(api_time, 4), 'other_processing_time': round(total_time - encrypt_time - api_time, 4) }, 'target_server_response': { 'status_code': target_response.status_code, 'content': target_response.text, 'headers': dict(target_response.headers) }, 'encryption_info': { 'original_username_length': len(username), 'original_password_length': len(password), 'encrypted_username_length': len(encrypted_user), 'encrypted_password_length': len(encrypted_password), 'chunk_count': username_chunks + password_chunks }, 'timestamp': datetime.now().isoformat() }) except requests.exceptions.Timeout: return jsonify({ 'success': False, 'message': '请求目标服务器超时', 'response_time': time.time() - start_time, 'request_id': request_id }), 504 except requests.exceptions.ConnectionError: return jsonify({ 'success': False, 'message': '无法连接到目标服务器', 'response_time': time.time() - start_time, 'request_id': request_id }), 502 except Exception as e: return jsonify({ 'success': False, 'message': f'处理请求时出错: {str(e)}', 'response_time': time.time() - start_time, 'request_id': request_id }), 500
if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)
|