from flask import Flask, render_template_string, request, jsonify import hashlib from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad import base64 import json import time import requests from urllib.parse import quote
app = Flask(__name__)
class AESCipher: def __init__(self, key="xxxxxxxxxxxxxxxx"): self.key = key.encode('utf-8') self.block_size = AES.block_size
def encrypt(self, plaintext): if plaintext is None: plaintext = "" elif isinstance(plaintext, int): plaintext = str(plaintext)
cipher = AES.new(self.key, AES.MODE_ECB) padded_data = pad(plaintext.encode('utf-8'), self.block_size) ciphertext = cipher.encrypt(padded_data) return base64.b64encode(ciphertext).decode('utf-8')
def encrypt_url_param(self, param_value): encrypted = self.encrypt(param_value) return quote(encrypted)
def decrypt(self, ciphertext): try: if ciphertext is None or ciphertext == "": return "" if isinstance(ciphertext, str): ciphertext = base64.b64decode(ciphertext) cipher = AES.new(self.key, AES.MODE_ECB) decrypted_data = cipher.decrypt(ciphertext) unpadded_data = unpad(decrypted_data, self.block_size) return unpadded_data.decode('utf-8') except Exception as e: return f"解密失败: {str(e)} | 原始数据: {ciphertext[:50]}..."
def generate_signature(params, sign_time, aes_key="DlXIsXNa2bdhel2s"): param_order = ["action", "equTypes", "timerandom"] param_str = ''.join(str(params.get(param, "")) for param in param_order) full_str = param_str + str(sign_time) md5_hash = hashlib.md5(full_str.encode('utf-8')).hexdigest() sign_data = {"md5": md5_hash, "signTime": sign_time} sign_json = json.dumps(sign_data, separators=(',', ':')) cipher = AESCipher(aes_key) return cipher.encrypt(sign_json)
@app.route('/', methods=['GET', 'POST']) def index(): if request.method == 'POST': return process_request() return render_main_page()
def render_main_page(): 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>FLASK</title> <style> :root { --primary: #3498db; --secondary: #2c3e50; --success: #27ae60; --danger: #e74c3c; --light: #ecf0f1; --dark: #34495e; } * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; color: #333; background-color: #f8f9fa; padding: 20px; } .container { max-width: 800px; margin: 0 auto; background: white; border-radius: 10px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); padding: 30px; } h1 { color: var(--secondary); text-align: center; margin-bottom: 30px; padding-bottom: 15px; border-bottom: 2px solid var(--primary); } .form-group { margin-bottom: 20px; } .param-row { display: flex; gap: 10px; margin-bottom: 10px; align-items: center; } .param-input { flex: 1; } .param-actions { display: flex; gap: 5px; } label { display: block; margin-bottom: 8px; font-weight: 600; color: var(--dark); } input[type="text"] { width: 100%; padding: 12px 15px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; transition: border-color 0.3s; } input[type="text"]:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2); } button, .btn { background-color: var(--primary); color: white; border: none; padding: 12px 15px; font-size: 14px; border-radius: 4px; cursor: pointer; transition: background-color 0.3s; font-weight: 600; text-align: center; } button:hover, .btn:hover { background-color: #2980b9; } .btn-danger { background-color: var(--danger); } .btn-success { background-color: var(--success); } .btn-danger:hover { background-color: #c0392b; } .result-section { margin-top: 40px; display: none; } .result-section.active { display: block; } .section-title { color: var(--secondary); margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #eee; } .result-box { background-color: #f8f9fa; border: 1px solid #e9ecef; border-radius: 5px; padding: 15px; margin-bottom: 20px; max-height: 200px; overflow-y: auto; font-family: monospace; font-size: 14px; white-space: pre-wrap; } .tabs { display: flex; margin-bottom: 15px; border-bottom: 1px solid #ddd; } .tab { padding: 10px 20px; cursor: pointer; background: #f1f1f1; border: 1px solid #ddd; border-bottom: none; border-radius: 5px 5px 0 0; margin-right: 5px; } .tab.active { background: white; border-bottom: 1px solid white; margin-bottom: -1px; font-weight: bold; color: var(--primary); } .tab-content { display: none; } .tab-content.active { display: block; } .loading { text-align: center; padding: 20px; display: none; } .spinner { border: 4px solid rgba(0, 0, 0, 0.1); border-radius: 50%; border-top: 4px solid var(--primary); width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 0 auto 20px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .error { background-color: #f8d7da; color: #721c24; padding: 15px; border-radius: 4px; margin-bottom: 20px; display: none; } </style> </head> <body> <div class="container"> <h1>FLASK</h1> <form id="queryForm" method="POST"> <div class="form-group"> <label>查询参数:</label> <div id="params-container"> <!-- 默认参数行(现在可以删除) --> <div class="param-row"> <div class="param-input"> <input type="text" name="param_name[]" value="action" placeholder="参数名"> </div> <div class="param-input"> <input type="text" name="param_value[]" value="pandian" placeholder="参数值"> </div> <div class="param-actions"> <button type="button" class="btn btn-danger remove-param">删除</button> </div> </div> <div class="param-row"> <div class="param-input"> <input type="text" name="param_name[]" value="equTypes" placeholder="参数名"> </div> <div class="param-input"> <input type="text" name="param_value[]" placeholder="请输入设备类型" required> </div> <div class="param-actions"> <button type="button" class="btn btn-danger remove-param">删除</button> </div> </div> </div> <div class="param-actions" style="margin-top: 15px;"> <button type="button" id="add-param" class="btn btn-success">添加参数</button> </div> </div> <button type="submit">发送查询</button> </form> <div class="loading" id="loading"> <div class="spinner"></div> <p>正在处理请求,请稍候...</p> </div> <div class="error" id="error"></div> <div class="result-section" id="resultSection"> <h2 class="section-title">查询结果</h2> <div class="tabs"> <div class="tab active" onclick="switchTab('summary')">结果摘要</div> <div class="tab" onclick="switchTab('url')">加密URL</div> <div class="tab" onclick="switchTab('headers')">请求头</div> <div class="tab" onclick="switchTab('response')">响应内容</div> <div class="tab" onclick="switchTab('decrypted')">解密内容</div> </div> <div class="tab-content active" id="summary"> <div class="form-group"> <label>响应状态码:</label> <div class="result-box" id="responseStatus"></div> </div> <div class="form-group"> <label>响应摘要:</label> <div class="result-box" id="responseSummary"></div> </div> </div> <div class="tab-content" id="url"> <div class="form-group"> <label>加密后的URL:</label> <div class="result-box" id="encryptedUrl"></div> </div> </div> <div class="tab-content" id="headers"> <div class="form-group"> <label>请求头信息:</label> <div class="result-box" id="requestHeaders"></div> </div> </div> <div class="tab-content" id="response"> <div class="form-group"> <label>完整响应内容:</label> <div class="result-box" id="fullResponse"></div> </div> </div> <div class="tab-content" id="decrypted"> <div class="form-group"> <label>解密后的内容:</label> <div class="result-box" id="decryptedResponse"></div> </div> </div> </div> </div> <script> function switchTab(tabName) { document.querySelectorAll('.tab-content').forEach(el => { el.classList.remove('active'); }); document.querySelectorAll('.tab').forEach(el => { el.classList.remove('active'); }); document.getElementById(tabName).classList.add('active'); event.currentTarget.classList.add('active'); } // 添加参数行 document.getElementById('add-param').addEventListener('click', function() { const container = document.getElementById('params-container'); const newRow = document.createElement('div'); newRow.className = 'param-row'; newRow.innerHTML = ` <div class="param-input"> <input type="text" name="param_name[]" placeholder="参数名" required> </div> <div class="param-input"> <input type="text" name="param_value[]" placeholder="参数值"> </div> <div class="param-actions"> <button type="button" class="btn btn-danger remove-param">删除</button> </div> `; container.appendChild(newRow); }); // 事件委托处理删除按钮(包括默认参数行) document.getElementById('params-container').addEventListener('click', function(e) { if (e.target.classList.contains('remove-param')) { const row = e.target.closest('.param-row'); row.remove(); } }); document.getElementById('queryForm').addEventListener('submit', function(e) { e.preventDefault(); document.getElementById('loading').style.display = 'block'; document.getElementById('error').style.display = 'none'; document.getElementById('resultSection').classList.remove('active'); const formData = new FormData(this); fetch('/', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { document.getElementById('loading').style.display = 'none'; if (data.error) { document.getElementById('error').textContent = data.error; document.getElementById('error').style.display = 'block'; } else { document.getElementById('responseStatus').textContent = data.response_status; document.getElementById('responseSummary').textContent = data.response_text.substring(0, 200) + (data.response_text.length > 200 ? '...' : ''); document.getElementById('encryptedUrl').textContent = data.encrypted_url; document.getElementById('requestHeaders').textContent = JSON.stringify(data.headers, null, 2); document.getElementById('fullResponse').textContent = data.response_text; document.getElementById('decryptedResponse').textContent = data.decrypted_text; document.getElementById('resultSection').classList.add('active'); document.getElementById('resultSection').scrollIntoView({ behavior: 'smooth' }); } }) .catch(error => { document.getElementById('loading').style.display = 'none'; document.getElementById('error').textContent = '请求处理错误: ' + error.message; document.getElementById('error').style.display = 'block'; }); }); </script> </body> </html> ''')
def process_request(): param_names = request.form.getlist("param_name[]") param_values = request.form.getlist("param_value[]") params = {} for name, value in zip(param_names, param_values): if name and value: params[name] = value if "equTypes" not in params or not params["equTypes"]: return jsonify({"error": "设备类型(equTypes)是必填项"}) if "action" not in params or not params["action"]: params["action"] = "pandian" try: result = execute_encrypted_request(params) return jsonify(result) except Exception as e: return jsonify({"error": f"请求处理错误: {str(e)}"})
def execute_encrypted_request(params): cipher = AESCipher() timerandom = int(time.time() * 1000) - 10 sign_time = int(time.time() * 1000) params["timerandom"] = timerandom encrypted_params = {} for key, value in params.items(): encrypted_params[key] = cipher.encrypt_url_param(value) signature = generate_signature(params, sign_time) headers = { "Host": "xxx.xxx.com.cn:8082", "Cookie": "_ga=GA1.1.1547523130; JSESSIONID=B52218556DFF2F;", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36", "Accept": "application/json, text/plain, */*", "X-Requested-With": "XMLHttpRequest", "Credential": "1749877300", "Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", "Sign": signature } base_url = "https://xxx.xxx.com.cn:8082/v1/xxx" query_string = "&".join(f"{k}={v}" for k, v in encrypted_params.items()) full_url = f"{base_url}?{query_string}" response = requests.get(full_url, headers=headers, verify=False, timeout=10) decrypted_text = cipher.decrypt(response.text) return { "encrypted_url": full_url, "headers": headers, "response_status": response.status_code, "response_text": response.text, "decrypted_text": decrypted_text }
if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)
|