Erstellung eines webbasierten TCP-Port-Scanners

HTMLBeginner
Jetzt üben

Einführung

Im vorangegangenen Projekt haben wir einen Python-Port-Scanner entwickelt, der Threading und Sockets zum Scannen von TCP-Ports nutzt. Obwohl dieser effektiv ist, gibt es durch den Einsatz von Drittanbieter-Paketen noch Raum für Verbesserungen.

In diesem Projekt werden wir unseren Port-Scanner durch die Integration der Bibliothek python-nmap aufwerten, was robustere Scan-Funktionen ermöglicht. Darüber hinaus werden wir eine Webanwendung mit Flask erstellen, um eine benutzerfreundliche Oberfläche für unseren Scanner bereitzustellen. Dieses Schritt-für-Schritt-Projekt wird Sie durch den Prozess führen und sicherstellen, dass Sie den Schritten folgen und auf Ihrem vorhandenen Wissen aufbauen können.

👀 Vorschau

🎯 Aufgaben

In diesem Projekt lernen Sie:

  • Wie man ein Flask-Projekt aufsetzt und dessen Struktur organisiert
  • Wie man Flask-WTF verwendet, um Webformulare sicher zu erstellen und zu verarbeiten
  • Wie man Flask-Routen implementiert, um Webseiten-Anfragen und Formularübermittlungen zu handhaben
  • Wie man die Nmap-Bibliothek in Python nutzt, um Port-Scans durchzuführen
  • Wie man Scan-Ergebnisse dynamisch auf einer Webseite mit Flask und HTML-Templates anzeigt
  • Wie man grundlegendes Tailwind CSS anwendet, um das Frontend-Design zu verbessern

🏆 Lernerfolge

Nach Abschluss dieses Projekts werden Sie in der Lage sein:

  • Ein grundlegendes Verständnis der Webentwicklung mit Flask zu demonstrieren, einschließlich Routing, Template-Rendering und Formularverarbeitung
  • Praktische Erfahrung bei der Integration von Python-Skripten in Web-Oberflächen anzuwenden
  • Kompetenz im Umgang mit der Nmap-Bibliothek für Netzwerk-Scanning-Aufgaben zu zeigen
  • Flask-WTF für die Erstellung und Validierung von Formularen in einer Webanwendung zu nutzen
  • Vertrautheit mit der Verwendung von Tailwind CSS zur Gestaltung von Webseiten und zur Verbesserung des Benutzeroberflächen-Designs zu beweisen
  • Eine funktionale webbasierte Anwendung zu erstellen, die mit Backend-Python-Skripten interagiert, um Netzwerk-Scans durchzuführen

Implementierung der Startseite

Öffnen Sie zu Beginn die Datei templates/index.html und fügen Sie den folgenden Code hinzu, um sicherzustellen, dass das Formular korrekt für die Übermittlung von Scan-Anfragen eingerichtet ist:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>TCP Port Scanner</title>
    <link
      href="https://cdn.jsdelivr.net/npm/tailwindcss@2.0.3/dist/tailwind.min.css"
      rel="stylesheet"
    />
    <script>
      function updateButton() {
        var submitButton = document.getElementById("scanButton");
        submitButton.value = "Scanning...";
        submitButton.classList.add("cursor-not-allowed", "opacity-50");
        submitButton.disabled = true;
      }
    </script>
  </head>
  <body class="bg-gray-100 flex items-center justify-center h-screen">
    <div class="bg-white p-8 rounded-lg shadow-md">
      <h1 class="text-2xl font-bold mb-4">TCP Port Scanner</h1>
      <form action="" method="post" class="space-y-4"
        {{ form.hidden_tag() }}
        <div>
          {{ form.host.label(class="block text-sm font-medium text-gray-700") }}
          {{ form.host(class="mt-1 block w-full rounded-md border-gray-300
          shadow-sm focus:border-indigo-500 focus:ring-indigo-500") }}
        </div>
        <div>
          {{ form.ports.label(class="block text-sm font-medium text-gray-700")
          }} {{ form.ports(class="mt-1 block w-full rounded-md border-gray-300
          shadow-sm focus:border-indigo-500 focus:ring-indigo-500") }}
        </div>
        <div>
          {{ form.submit(id="scanButton", class="w-full flex justify-center py-2
          px-4 border border-transparent rounded-md shadow-sm text-sm
          font-medium text-white bg-indigo-600 hover:bg-indigo-700
          focus:outline-none focus:ring-2 focus:ring-offset-2
          focus:ring-indigo-500") }}
        </div>
      </form>
    </div>
  </body>
</html>

Das Template index.html bietet eine benutzerfreundliche Oberfläche zur Eingabe eines Hosts und eines Portbereichs für den Scan. Das HTML-Formular enthält zwei Hauptfelder: eines für die Host-Adresse und ein weiteres zur Angabe des Portbereichs.

Flask-WTF, eine Flask-Erweiterung für die Arbeit mit WTForms, wird verwendet, um diese Felder im Template zu rendern. Die Formularübermittlung wird durch eine kleine JavaScript-Funktion updateButton() ergänzt, die den Text des Absende-Buttons beim Absenden auf "Scanning..." ändert. Dieses visuelle Feedback informiert den Benutzer darüber, dass seine Scan-Anfrage gerade verarbeitet wird.

Die Gestaltung der Seite erfolgt über Tailwind CSS, ein Utility-First-CSS-Framework, das eine schnelle Entwicklung von Benutzeroberflächen ermöglicht.

Implementierung der Ergebnisseite

Öffnen Sie templates/results.html und stellen Sie sicher, dass der folgende Code enthalten ist, um die Scan-Ergebnisse anzuzeigen:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Scan Results</title>
    <link
      href="https://cdn.jsdelivr.net/npm/tailwindcss@2.0.3/dist/tailwind.min.css"
      rel="stylesheet"
    />
  </head>
  <body class="bg-gray-100">
    <div class="flex flex-col items-center justify-center min-h-screen">
      <div class="bg-white p-8 rounded-lg shadow-lg w-full max-w-4xl">
        <h1 class="text-2xl font-bold mb-4 text-center">
          Scan Results for {{ host }}
        </h1>
        <div class="overflow-x-auto">
          <table class="table-auto w-full text-left whitespace-no-wrap">
            <thead>
              <tr
                class="text-xs font-semibold tracking-wide text-left text-gray-500 uppercase border-b dark:border-gray-700 bg-gray-50"
              >
                <th class="px-4 py-3">PORT</th>
                <th class="px-4 py-3">STATE</th>
                <th class="px-4 py-3">SERVICE</th>
                <th class="px-4 py-3">VERSION</th>
              </tr>
            </thead>
            <tbody
              class="bg-white divide-y dark:divide-gray-700 dark:bg-gray-800"
            >
              {% for result in scan_results %}
              <tr class="text-gray-700 dark:text-gray-400">
                <td class="px-4 py-3 text-sm">{{ result.port }}/tcp</td>
                <td class="px-4 py-3 text-sm">{{ result.state }}</td>
                <td class="px-4 py-3 text-sm">{{ result.name }}</td>
                <td class="px-4 py-3 text-sm">
                  {{ result.product }} {{ result.version }} {{ result.extra }}
                </td>
              </tr>
              {% endfor %}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </body>
</html>

Das Template results.html ist für die Anzeige des Ergebnisses des Port-Scans verantwortlich. Es präsentiert die Scan-Ergebnisse in Tabellenform und listet jeden Port mit seinem entsprechenden Status, dem Dienstnamen und der Dienstversion (falls verfügbar) auf.

Dieses Template verwendet Tailwind CSS für das Styling, um sicherzustellen, dass die Ergebnisseite sowohl responsiv als auch optisch ansprechend ist. Die Verwendung der Jinja2-Template-Engine (integriert in Flask) ermöglicht das dynamische Rendern von Inhalten, wobei die Scan-Ergebnisse von der Flask-Anwendung an das Template übergeben und in einer Schleife durchlaufen werden, um die Tabelle zu füllen.

Initialisierung der Flask-Anwendung

In diesem Schritt erstellen wir das Haupt-Python-Skript für unsere Flask-Anwendung.

Fügen Sie den folgenden Code in app.py ein:

## Import necessary modules
from flask import Flask, render_template, request, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, Regexp
import nmap

## Initialize Flask app
app = Flask(__name__)
app.config['SECRET_KEY'] = 'labex'

## Initialize Nmap PortScanner
nm = nmap.PortScanner()

## Define Flask-WTF form for scanning inputs
class ScanForm(FlaskForm):
    host = StringField('Host', validators=[DataRequired()])
    ports = StringField('Port Range', validators=[DataRequired(), Regexp(r'^\d+-\d+$', message="Format must be start-end")])
    submit = SubmitField('Scan')

In diesem Schritt werden die Flask-Anwendung und die Formular-Klasse initialisiert.

Das Skript app.py beginnt mit dem Import der notwendigen Module, darunter Flask selbst, Flask-WTF für die Formularverarbeitung und Nmap für die Durchführung der Port-Scans. Die Instanz der Flask-Anwendung wird erstellt und mit einem geheimen Schlüssel konfiguriert, um vor CSRF-Angriffen zu schützen.

Die Klasse ScanForm definiert die Formularfelder für die Host- und Portbereichs-Eingaben und verwendet Validatoren, um sicherzustellen, dass die Daten vorhanden sind und das korrekte Format aufweisen (insbesondere für den Portbereich).

Ersetzen Sie 'your_secret_key' durch einen echten geheimen Schlüssel, der zum Schutz der Formulare gegen CSRF-Angriffe dient.

Handhabung der Index-Route

In diesem Schritt bearbeiten wir die Index-Route, auf der Benutzer den Host und den Portbereich eingeben können, den sie scannen möchten. Fügen Sie die folgende Funktion zu app.py hinzu:

## Define route for the index page
@app.route('/', methods=['GET', 'POST'])
def index():
    form = ScanForm()  ## Instantiate the form
    if form.validate_on_submit():
        ## Get data from the form
        host = form.host.data
        ports = form.ports.data  ## Format: "start-end"
        ## Redirect to the scan route with form data
        return redirect(url_for('scan', host=host, ports=ports))
    ## Render the index page template with the form
    return render_template('index.html', form=form)

Dieser Teil des Skripts app.py definiert die Route für die Startseite der Webanwendung. Die Funktion index() rendert das Template index.html zusammen mit der Instanz von ScanForm.

Wenn das Formular abgeschickt wird und die Validierungsprüfungen besteht, leitet die Funktion den Benutzer zur Scan-Route weiter und übergibt dabei die Formulardaten (Host und Portbereich) über URL-Parameter. Diese Weiterleitung leitet den eigentlichen Scan-Vorgang ein.

Implementierung der Scan-Route

Dieser Schritt beinhaltet das Erstellen einer Route, um den eigentlichen Scan durchzuführen und die Ergebnisse anzuzeigen. Fügen Sie die folgende Funktion zu app.py hinzu:

## Define route for the scan results
@app.route('/scan')
def scan():
    ## Retrieve host and ports from the query string
    host = request.args.get('host')
    ports = request.args.get('ports')
    ## Perform the scan using Nmap
    nm.scan(hosts=host, ports=ports, arguments='-sV')  ## -sV for service/version detection
    scan_results = []

    ## Process scan results and store them in a list
    for host in nm.all_hosts():
        for proto in nm[host].all_protocols():
            lport = nm[host][proto].keys()
            for port in lport:
                service = nm[host][proto][port]
                scan_results.append({
                    'port': port,
                    'state': service['state'],
                    'name': service.get('name', 'Unknown'),
                    'product': service.get('product', ''),
                    'version': service.get('version', ''),
                    'extra': service.get('extrainfo', '')
                })

    ## Render the results page template with the scan results
    return render_template('results.html', scan_results=scan_results, host=host)

Die Funktion scan() verwaltet die Route, die für die Durchführung des eigentlichen Port-Scans und die Anzeige der Ergebnisse zuständig ist. Sie ruft den Host und den Portbereich aus den Query-String-Parametern ab, die in der URL übergeben wurden.

Unter Verwendung der Nmap-PortScanner-Instanz führt sie einen Scan auf dem angegebenen Host und den Ports durch, wobei das Argument -sV zur Erkennung von Dienstversionen verwendet wird.

Die Scan-Ergebnisse werden verarbeitet und in einer Liste von Dictionaries organisiert, von denen jedes Details zu einem gescannten Port enthält. Diese Details werden dann an das Template results.html übergeben, wo sie dem Benutzer angezeigt werden.

Ausführen der Flask-Anwendung

Da nun alle Komponenten bereitstehen, können Sie die Flask-Anwendung starten und Ihren TCP-Port-Scanner zum Leben erwecken. Das letzte Codestück in Ihrer app.py stellt sicher, dass die Flask-Anwendung nur ausgeführt wird, wenn das Skript direkt gestartet wird und nicht, wenn es als Modul in ein anderes Skript importiert wird. Dies ist ein gängiges Muster in Python-Anwendungen, die ein ausführbares Skript enthalten.

Platzieren Sie den folgenden Code-Schnipsel am Ende Ihrer app.py-Datei:

if __name__ == '__main__':
    app.run(debug=True, port=8080, host='0.0.0.0')

Dieser Code weist Flask an, Ihre Anwendung mit aktiviertem Debugging zu starten, was das Aufspüren von Fehlern erleichtert. Die Anwendung wird auf allen Netzwerkschnittstellen (host='0.0.0.0') lauschen und den Port 8080 verwenden. Der Debug-Modus sollte nur während der Entwicklung verwendet werden, da sein Einsatz in einer Produktionsumgebung unsicher sein kann.

Um Ihre Flask-Anwendung auszuführen, stellen Sie sicher, dass Sie sich im Projektverzeichnis befinden, in dem app.py liegt. Führen Sie dann den folgenden Befehl im Terminal aus:

python app.py

Wechseln Sie zum Tab Web 8080, um auf den TCP-Port-Scanner zuzugreifen. Sie können nun einen Host und einen Portbereich für den Scan eingeben und die Ergebnisse auf der Ergebnisseite einsehen.

Die Ports 22 und 3306 werden üblicherweise mit SSH- bzw. MySQL-Diensten in Verbindung gebracht, während der Port 3000 für die WebIDE-Umgebungen genutzt wird.

Zusammenfassung

In diesem Projekt haben Sie gelernt, wie man einen einfachen, aber leistungsstarken webbasierten TCP-Port-Scanner mit Flask und Nmap erstellt. Wir begannen mit der Einrichtung der Projektumgebung und der Installation der notwendigen Abhängigkeiten. Anschließend haben wir die Flask-Anwendung erstellt, Formularübermittlungen verarbeitet, den Port-Scan durchgeführt und die Ergebnisse benutzerfreundlich dargestellt. Dieses Projekt dient als hervorragende Einführung in die Webentwicklung mit Flask und das Netzwerk-Scanning mit Nmap und bietet eine praktische Anwendung, die beide Fähigkeiten kombiniert.

✨ Lösung prüfen und üben✨ Lösung prüfen und üben✨ Lösung prüfen und üben✨ Lösung prüfen und üben✨ Lösung prüfen und üben✨ Lösung prüfen und üben