概述:我正在尝试开发一个基于 Web 的 SSL 扫描器,作为后端,我正在使用子进程模块通过 python 代码在 ubuntu 发行版中执行 testssl.sh 脚本。
当前状态:我开发了一个前端,它有一个按钮和一个输入字段,用户应该在其中输入主机名/IP 地址,然后为了执行扫描,用户必须单击“开始扫描”按钮,这将允许 Python FLask 应用程序从表单中删除主机名,然后执行扫描,同时扫描正在运行,网页应该显示消息“扫描 hotsname 的服务器配置”,然后显示相应的消息扫描完成后,在网页上提供报告的下载链接。
我已经在 Python Anywhere 上部署了 Python Flask 应用程序,在浏览网站时,HTML 网页按预期显示,但问题是在本地主机中,当我单击网页上的“开始扫描”按钮时,它显示消息“扫描 hotsname 的服务器配置”,扫描实际运行并在大约 7 到 10 分钟内生成报告(取决于正在测试的已部署服务器配置的复杂性)。
问题:关于 flask 应用程序,当我从 Pythonanywhere 浏览网站时,单击开始扫描按钮后,它显示消息 “主机名扫描完成:{hostname}。5 秒内刷新。” 就在几秒钟。但这在本地主机上运行成功。
我附上了 Python Flask 代码和 HTML 代码供您参考,如果有人能指导我如何解决这个问题,我将非常感激?
HTML代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<title>SSL Scanner</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" />
<link rel="shortcut icon" type="image/x-icon" href="{{ url_for('static', filename='images/icons.ico') }}" />
</head>
<body>
<div id="header">
<div id="logo">
<img src="{{ url_for('static', filename='images/image.jpeg') }}" width="150" height="50" alt="Logo"
title="Scanner Logo" />
</div>
<div>
<a href="" id="documentation">Documentation</a>
<a href="mailto:[email protected]" id="contactUs">Contact Us</a>
</div>
</div>
<div id="submitBox">
<form method="POST" action="/scan" style="color: rgb(255, 119, 1)">
<label for="hostname"><b>Hostname</b></label>
<input type="text" name="hostname" id="hostname" required />
<button id="submit-btn" type="submit" style="
color: rgb(227, 216, 203);
font-weight: bold;
background-color: rgb(255, 119, 1);
border-radius: 5px;
padding: 8px 12px;
border: none;
cursor: pointer;
">
Begin Scan
</button>
<label style="margin-left: 5px">Do not refresh or go back during an ongoing scan.</label>
</form>
</div>
<div id="loading" style="
display: none;
padding: 30px;
text-align: center;
color: rgb(255, 119, 1);
">
Scanning the server configuration of <span id="hostname-text"></span>...
</div>
<div id="return_output" style="padding: 10px; text-align: center; color: rgb(255, 119, 1)">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$("form").submit(function (event) {
event.preventDefault();
var hostname = $("#hostname").val();
$("#hostname-text").text(hostname);
$("#submit-btn").attr("disabled", true);
$("#loading").show();
$("#return_output").empty(); // Remove previous output message and download link when a hostname is submitted
$.ajax({
type: "POST",
url: "/scan",
data: $("form").serialize(),
success: function (response) {
// Display the output message
$("#return_output").text(response.return_output);
// Check if download link is available in response
if (response.download_link) {
// Create a download link element
var downloadLink = $("<a>")
.attr("href", response.download_link)
.attr("download", "report.html")
.text(" Download Scan Report");
// Append download link element to the return_output div
$("#return_output").append(downloadLink);
}
// Refreshes the webpage after 5 seconds to populate the table row and allows the user to see the output message alongwith download link in the meantime
setTimeout(function () {
location.reload();
}, 5000);
},
error: function (error) {
console.log(error);
},
complete: function () {
$("#submit-btn").attr("disabled", false);
$("#loading").hide();
},
});
});
</script>
</div>
<div id="last15scans" style="padding: 10px">
<h4>Previously Generated Reports</h4>
<table style="border: 2px solid rgb(255, 119, 1); border-collapse: collapse">
<thead>
<tr>
<th>Hostname</th>
<th>Date and Time</th>
<th>Download Link</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<script>
$(document).ready(function () {
// Retrieve last 15 scans data from Flask API and populate the table
$.ajax({
type: "GET",
url: "/last15scans",
success: function (data) {
$.each(data, function (i, item) {
var tr = $("<tr>");
tr.append($("<td>").text(item.hostname));
tr.append($("<td>").text(item.date_time));
var downloadLink = $("<a>")
.attr("href", item.download_link)
.attr("download", "report.html")
.text("Download");
tr.append($("<td>").append(downloadLink));
$("tbody", "#last15scans").append(tr);
});
},
error: function (error) {
console.log(error);
},
});
});
</script>
<footer>
<p>© 2023 <b>PB Inc.</b></p>
</footer>
</body>
</html>
改良烧瓶应用
from flask import Flask, render_template, request, jsonify, url_for, send_file
import os
import datetime
import subprocess
app = Flask(__name__) # app: Test SSL Interface
dateandtime = datetime.datetime.now().strftime("%H%M")
@app.route("/")
def index():
return render_template("Internal_Scanner.html")
@app.route("/scan", methods=["POST"])
def scan():
# Get the hostname from the form data
hostname = request.form["hostname"]
if len(hostname) > 50:
return jsonify({"return_output": "The hostname is too long."})
elif hostname.find(" ") != -1:
return jsonify(
{
"return_output": "The entered hostname is not valid as it has a whitespace."
}
)
else:
if hostname.find(":") == -1:
htmlfilename = f"{hostname}_{dateandtime}.html"
else:
htmlfilename = f"{(hostname.split(':'))[0]}_{dateandtime}.html"
# Call the backend code to scan the given hostname
testssl_script_path = r"/mnt/c/inetpub/wwwroot/sslsc/testssl.sh-3.1dev"
command = f'''bash --login -c "cd \\"{testssl_script_path}\\" && ./testssl.sh --htmlfile ../reports/scans/{htmlfilename} -p -s -f -P -S -h -H -I -T -BB -R -C -B -O -W -F -D -4 --openssl-timeout 5 {hostname}"'''
# Execute the command
subprocess.call(command, shell=True)
return_output = (
f"Scan completed for hostname: {hostname}. Refreshing in 5 seconds."
)
download_link = f"/api/download/{htmlfilename}"
return jsonify({"return_output": return_output, "download_link": download_link})
@app.route("/api/download/<string:filename>", methods=["GET"])
def download_report(filename):
# Serve the file from the reports directory
# r"C:\WSL\reports\scans"
file_path = os.path.join(r"C:\inetpub\wwwroot\sslsc\reports\scans", filename)
if os.path.isfile(file_path):
return send_file(file_path, as_attachment=True)
else:
return jsonify({"error": "File not found"})
if __name__ == "__main__":
app.run()
烧瓶应用
from flask import Flask, render_template, request, jsonify, url_for, send_file
import os
import datetime
import subprocess
app = Flask(__name__) # app: Test SSL Interface
dateandtime = datetime.datetime.now().strftime("%H%M")
@app.route("/")
def index():
return render_template("Internal_Scanner.html")
@app.route("/scan", methods=["POST"])
def scan():
# Get the hostname from the form data
hostname = request.form["hostname"]
if len(hostname) > 50:
return jsonify({"return_output": "The hostname is too long."})
elif hostname.find(" ") != -1:
return jsonify(
{
"return_output": "The entered hostname is not valid as it has a whitespace."
}
)
else:
if hostname.find(":") == -1:
htmlfilename = f"{hostname}_{dateandtime}.html"
else:
htmlfilename = f"{(hostname.split(':'))[0]}_{dateandtime}.html"
# Call the backend code to scan the given hostname
# Opens the actual path to the ubuntu.exe file and executes the ubuntu.exe file
process = subprocess.Popen(
[r"C:\inetpub\wwwroot\Ubuntu\Ubuntu_2004.2021.825.0_x64\ubuntu.exe"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
# Change the directory where the testssl.sh script is stored
process.stdin.write(b"cd /mnt/c/inetpub/wwwroot/sslsc/testssl.sh-3.1dev\n")
process.stdin.flush()
# Execute the testssl.sh script with the URL and redirect the output to a folder
if hostname.find(":") == -1:
htmlfilename = f"{hostname}_{dateandtime}.html"
jsonfilename = f"{hostname}_{dateandtime}.json"
else:
htmlfilename = f"{(hostname.split(':'))[0]}_{dateandtime}.html"
jsonfilename = f"{(hostname.split(':'))[0]}_{dateandtime}.json"
command = f"./testssl.sh --htmlfile ../reports/scans/{htmlfilename} --jsonfile ../reports/jsons/{jsonfilename} -p -s -f -P -S -h -H -I -T -BB -R -C -B -O -W -F -D -4 --openssl-timeout 5 {hostname}\n"
process.stdin.write(command.encode())
process.stdin.flush()
process.communicate()
return_output = f"Scan completed for hostname: {hostname}. Refreshing in 5 seconds."
download_link = f"/api/download/{htmlfilename}"
return jsonify({"return_output": return_output, "download_link": download_link})
@app.route("/api/download/<string:filename>", methods=["GET"])
def download_report(filename):
# Serve the file from the reports directory
# r"C:\WSL\reports\scans"
file_path = os.path.join(r"C:\inetpub\wwwroot\sslsc\reports\scans", filename)
if os.path.isfile(file_path):
return send_file(file_path, as_attachment=True)
else:
return jsonify({"error": "File not found"})
if __name__ == "__main__":
app.run()
早些时候我将它部署在 IIS 10 上,我也遇到了同样的问题。有什么方法可以通过这种方式实现目标吗?