Maßtrisez la programmation CGI en Python depuis les bases. Ce guide approfondi couvre la configuration, la gestion des formulaires, la gestion d'état, la sécurité et sa place dans le web moderne.
Programmation CGI en Python : Un guide complet pour créer des interfaces web
Dans le monde du développement web moderne, dominé par des frameworks sophistiqués comme Django, Flask et FastAPI, le terme CGI (Common Gateway Interface) peut sonner comme un écho d'une époque révolue. Cependant, ignorer le CGI serait négliger une technologie fondamentale qui non seulement a alimenté les débuts du web dynamique, mais qui continue également d'offrir des leçons précieuses et des applications pratiques aujourd'hui. Comprendre le CGI, c'est comme comprendre le fonctionnement d'un moteur avant d'apprendre à conduire une voiture ; cela fournit une connaissance profonde et fondamentale de l'interaction client-serveur qui sous-tend toutes les applications web.
Ce guide complet démystifiera la programmation CGI en Python. Nous l'explorerons à partir des principes de base, vous montrant comment construire des interfaces web dynamiques et interactives en utilisant uniquement les bibliothÚques standard de Python. Que vous soyez un étudiant apprenant les fondements du web, un développeur travaillant avec des systÚmes existants, ou quelqu'un opérant dans un environnement contraint, ce guide vous dotera des compétences nécessaires pour tirer parti de cette technologie puissante et simple.
Qu'est-ce que le CGI et pourquoi est-il toujours pertinent ?
L'Common Gateway Interface (CGI) est un protocole standard qui dĂ©finit comment un serveur web peut interagir avec des programmes externes, souvent appelĂ©s scripts CGI. Lorsqu'un client (comme un navigateur web) demande une URL spĂ©cifique associĂ©e Ă un script CGI, le serveur web ne se contente pas de servir un fichier statique. Au lieu de cela, il exĂ©cute le script et renvoie la sortie du script au client. Cela permet de gĂ©nĂ©rer du contenu dynamique basĂ© sur les entrĂ©es de l'utilisateur, les requĂȘtes de base de donnĂ©es, ou toute autre logique que le script contient.
Imaginez-le comme une conversation :
- Client au Serveur : "J'aimerais voir la ressource à `/cgi-bin/process-form.py` et voici quelques données d'un formulaire que j'ai rempli."
- Serveur au Script CGI : "Une requĂȘte est arrivĂ©e pour toi. Voici les donnĂ©es du client et des informations sur la requĂȘte (comme son adresse IP, son navigateur, etc.). S'il te plaĂźt, exĂ©cute-toi et donne-moi la rĂ©ponse Ă renvoyer."
- Script CGI au Serveur : "J'ai traitĂ© les donnĂ©es. Voici les en-tĂȘtes HTTP et le contenu HTML Ă retourner."
- Serveur au Client : "Voici la page dynamique que vous avez demandée."
Bien que les frameworks modernes aient abstrait cette interaction brute, les principes sous-jacents restent les mĂȘmes. Alors, pourquoi apprendre le CGI Ă l'Ăšre des frameworks de haut niveau ?
- ComprĂ©hension fondamentale : Cela vous oblige Ă apprendre les mĂ©canismes de base des requĂȘtes et rĂ©ponses HTTP, y compris les en-tĂȘtes, les variables d'environnement et les flux de donnĂ©es, sans aucune magie. Cette connaissance est inestimable pour le dĂ©bogage et l'optimisation des performances de n'importe quelle application web.
- SimplicitĂ© : Pour une tĂąche unique et isolĂ©e, Ă©crire un petit script CGI peut ĂȘtre beaucoup plus rapide et simple que de mettre en place un projet de framework entier avec son routage, ses modĂšles et ses contrĂŽleurs.
- Indépendant du langage : Le CGI est un protocole, pas une bibliothÚque. Vous pouvez écrire des scripts CGI en Python, Perl, C++, Rust, ou tout autre langage capable de lire depuis l'entrée standard et d'écrire sur la sortie standard.
- SystĂšmes existants et environnements contraints : De nombreuses applications web plus anciennes et certains environnements d'hĂ©bergement mutualisĂ© dĂ©pendent du CGI ou ne fournissent que son support. Savoir comment travailler avec peut ĂȘtre une compĂ©tence essentielle. C'est aussi courant dans les systĂšmes embarquĂ©s avec des serveurs web simples.
Configurer votre environnement CGI
Avant de pouvoir exĂ©cuter un script CGI Python, vous avez besoin d'un serveur web configurĂ© pour l'exĂ©cuter. C'est l'obstacle le plus courant pour les dĂ©butants. Pour le dĂ©veloppement et l'apprentissage, vous pouvez utiliser des serveurs populaires comme Apache ou mĂȘme le serveur intĂ©grĂ© de Python.
Prérequis : Un serveur web
La clĂ© est de dire Ă votre serveur web que les fichiers dans un rĂ©pertoire spĂ©cifique (traditionnellement nommĂ© `cgi-bin`) ne doivent pas ĂȘtre servis comme du texte mais doivent ĂȘtre exĂ©cutĂ©s, leur sortie Ă©tant envoyĂ©e au navigateur. Bien que les Ă©tapes de configuration spĂ©cifiques varient, les principes gĂ©nĂ©raux sont universels.
- Apache : Vous devez généralement activer `mod_cgi` et utiliser une directive `ScriptAlias` dans votre fichier de configuration pour mapper un chemin d'URL à un répertoire du systÚme de fichiers. Vous avez également besoin d'une directive `Options +ExecCGI` pour ce répertoire afin de permettre l'exécution.
- Nginx : Nginx n'a pas de module CGI direct comme Apache. Il utilise généralement un pont comme FCGIWrap pour exécuter les scripts CGI.
- `http.server` de Python : Pour des tests locaux simples, vous pouvez utiliser le serveur web intégré de Python, qui prend en charge le CGI d'origine. Vous pouvez le démarrer depuis votre ligne de commande avec : `python3 -m http.server --cgi 8000`. Cela démarrera un serveur sur le port 8000 et traitera tous les scripts dans un sous-répertoire `cgi-bin/` comme étant exécutables.
Votre premier "Hello, World!" en CGI Python
Un script CGI a un format de sortie trĂšs spĂ©cifique. Il doit d'abord imprimer tous les en-tĂȘtes HTTP nĂ©cessaires, suivis d'une seule ligne vide, puis du corps du contenu (par exemple, du HTML).
Créons notre premier script. Enregistrez le code suivant sous le nom `hello.py` dans votre répertoire `cgi-bin`.
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# 1. L'en-tĂȘte HTTP
# L'en-tĂȘte le plus important est Content-Type, qui indique au navigateur quel type de donnĂ©es attendre.
print("Content-Type: text/html;charset=utf-8")
# 2. La ligne vide
# Une seule ligne vide est cruciale. Elle sĂ©pare les en-tĂȘtes du corps du contenu.
print()
# 3. Le corps du contenu
# C'est le contenu HTML réel qui sera affiché dans le navigateur.
print("<h1>Bonjour, le monde !</h1>")
print("<p>Ceci est mon premier script CGI en Python.</p>")
print("<p>Il fonctionne sur un serveur web global, accessible Ă tous !</p>")
Décortiquons cela :
#!/usr/bin/env python3
: C'est la ligne "shebang". Sur les systÚmes de type Unix (Linux, macOS), elle indique au systÚme d'exploitation d'exécuter ce fichier en utilisant l'interpréteur Python 3.print("Content-Type: text/html;charset=utf-8")
: C'est l'en-tĂȘte HTTP. Il informe le navigateur que le contenu suivant est du HTML et est encodĂ© en UTF-8, ce qui est essentiel pour prendre en charge les caractĂšres internationaux.print()
: Ceci imprime la ligne vide obligatoire qui sĂ©pare les en-tĂȘtes du corps. L'oublier est une erreur trĂšs courante.- Les derniĂšres instructions `print` produisent le HTML que l'utilisateur verra.
Enfin, vous devez rendre le script exécutable. Sur Linux ou macOS, vous exécuteriez cette commande dans votre terminal : `chmod +x cgi-bin/hello.py`. Maintenant, lorsque vous accédez à `http://votre-adresse-serveur/cgi-bin/hello.py` dans votre navigateur, vous devriez voir votre message "Bonjour, le monde !".
Le cĆur du CGI : les variables d'environnement
Comment le serveur web communique-t-il les informations sur la requĂȘte Ă notre script ? Il utilise les variables d'environnement. Ce sont des variables dĂ©finies par le serveur dans l'environnement d'exĂ©cution du script, fournissant une mine d'informations sur la requĂȘte entrante et le serveur lui-mĂȘme. C'est la "Gateway" (passerelle) dans Common Gateway Interface.
Variables d'environnement clés du CGI
Le module `os` de Python nous permet d'accéder à ces variables. Voici quelques-unes des plus importantes :
REQUEST_METHOD
: La mĂ©thode HTTP utilisĂ©e pour la requĂȘte (par ex., 'GET', 'POST').QUERY_STRING
: Contient les donnĂ©es envoyĂ©es aprĂšs le '?' dans une URL. C'est ainsi que les donnĂ©es sont passĂ©es dans une requĂȘte GET.CONTENT_LENGTH
: La longueur des donnĂ©es envoyĂ©es dans le corps de la requĂȘte, utilisĂ©e pour les requĂȘtes POST.CONTENT_TYPE
: Le type MIME des donnĂ©es dans le corps de la requĂȘte (par ex., 'application/x-www-form-urlencoded').REMOTE_ADDR
: L'adresse IP du client qui effectue la requĂȘte.HTTP_USER_AGENT
: La chaĂźne user-agent du navigateur du client (par ex., 'Mozilla/5.0...').SERVER_NAME
: Le nom d'hĂŽte ou l'adresse IP du serveur.SERVER_PROTOCOL
: Le protocole utilisé, tel que 'HTTP/1.1'.SCRIPT_NAME
: Le chemin vers le script en cours d'exécution.
Exemple pratique : Un script de diagnostic
Créons un script qui affiche toutes les variables d'environnement disponibles. C'est un outil incroyablement utile pour le débogage. Enregistrez-le sous `diagnostics.py` dans votre répertoire `cgi-bin` et rendez-le exécutable.
#!/usr/bin/env python3
import os
print("Content-Type: text/html\n")
print("<h1>Variables d'environnement CGI</h1>")
print("<p>Ce script affiche toutes les variables d'environnement transmises par le serveur web.</p>")
print("<table border='1' style='border-collapse: collapse; width: 80%;'>")
print("<tr><th>Variable</th><th>Valeur</th></tr>")
# Itérer à travers toutes les variables d'environnement et les imprimer dans un tableau
for key, value in sorted(os.environ.items()):
print(f"<tr><td>{key}</td><td>{value}</td></tr>")
print("</table>")
Lorsque vous exĂ©cutez ce script, vous verrez un tableau dĂ©taillĂ© rĂ©pertoriant chaque information que le serveur a transmise Ă votre script. Essayez d'ajouter une chaĂźne de requĂȘte Ă l'URL (par ex., `.../diagnostics.py?name=test&value=123`) et observez comment la variable `QUERY_STRING` change.
Gérer les entrées utilisateur : Formulaires et données
L'objectif principal du CGI est de traiter les entrées des utilisateurs, généralement à partir de formulaires HTML. La bibliothÚque standard de Python fournit des outils robustes pour cela. Voyons comment gérer les deux principales méthodes HTTP : GET et POST.
Tout d'abord, créons un formulaire HTML simple. Enregistrez ce fichier sous `feedback_form.html` dans votre répertoire web principal (pas le répertoire cgi-bin).
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Formulaire de feedback global</title>
</head>
<body>
<h1>Envoyez vos commentaires</h1>
<p>Ce formulaire démontre les méthodes GET et POST.</p>
<h2>Exemple de méthode GET</h2>
<form action="/cgi-bin/form_handler.py" method="GET">
<label for="get_name">Votre nom :</label>
<input type="text" id="get_name" name="username">
<br/><br/>
<label for="get_topic">Sujet :</label>
<input type="text" id="get_topic" name="topic">
<br/><br/>
<input type="submit" value="Envoyer avec GET">
</form>
<hr>
<h2>Exemple de méthode POST (Plus de fonctionnalités)</h2>
<form action="/cgi-bin/form_handler.py" method="POST">
<label for="post_name">Votre nom :</label>
<input type="text" id="post_name" name="username">
<br/><br/>
<label for="email">Votre email :</label>
<input type="email" id="email" name="email">
<br/><br/>
<p>Ătes-vous satisfait de notre service ?</p>
<input type="radio" id="happy_yes" name="satisfaction" value="yes">
<label for="happy_yes">Oui</label><br>
<input type="radio" id="happy_no" name="satisfaction" value="no">
<label for="happy_no">Non</label><br>
<input type="radio" id="happy_neutral" name="satisfaction" value="neutral">
<label for="happy_neutral">Neutre</label>
<br/><br/>
<p>Quels produits vous intéressent ?</p>
<input type="checkbox" id="prod_a" name="products" value="Product A">
<label for="prod_a">Produit A</label><br>
<input type="checkbox" id="prod_b" name="products" value="Product B">
<label for="prod_b">Produit B</label><br>
<input type="checkbox" id="prod_c" name="products" value="Product C">
<label for="prod_c">Produit C</label>
<br/><br/>
<label for="comments">Commentaires :</label><br>
<textarea id="comments" name="comments" rows="4" cols="50"></textarea>
<br/><br/>
<input type="submit" value="Envoyer avec POST">
</form>
</body>
</html>
Ce formulaire soumet ses donnĂ©es Ă un script nommĂ© `form_handler.py`. Maintenant, nous devons Ă©crire ce script. Bien que vous puissiez analyser manuellement la `QUERY_STRING` pour les requĂȘtes GET et lire depuis l'entrĂ©e standard pour les requĂȘtes POST, c'est sujet aux erreurs et complexe. Ă la place, nous devrions utiliser le module `cgi` intĂ©grĂ© de Python, qui est conçu exactement pour cela.
La classe `cgi.FieldStorage` est l'hĂ©roĂŻne ici. Elle analyse la requĂȘte entrante et fournit une interface de type dictionnaire pour les donnĂ©es du formulaire, qu'elles aient Ă©tĂ© envoyĂ©es via GET ou POST.
Voici le code pour `form_handler.py`. Enregistrez-le dans votre répertoire `cgi-bin` et rendez-le exécutable.
#!/usr/bin/env python3
import cgi
import html
# Créer une instance de FieldStorage
# Cet unique objet gĂšre les requĂȘtes GET et POST de maniĂšre transparente
form = cgi.FieldStorage()
# Commencer à imprimer la réponse
print("Content-Type: text/html\n")
print("<h1>Soumission de formulaire reçue</h1>")
print("<p>Merci pour vos commentaires. Voici les données que nous avons reçues :</p>")
# Vérifier si des données de formulaire ont été soumises
if not form:
print("<p><em>Aucune donnée de formulaire n'a été soumise.</em></p>")
else:
print("<table border='1' style='border-collapse: collapse;'>")
print("<tr><th>Nom du champ</th><th>Valeur(s)</th></tr>")
# Itérer à travers toutes les clés des données du formulaire
for key in form.keys():
# IMPORTANT : Assainir les entrées utilisateur avant de les afficher pour prévenir les attaques XSS.
# html.escape() convertit les caractÚres comme <, >, & en leurs entités HTML.
sanitized_key = html.escape(key)
# La méthode .getlist() est utilisée pour gérer les champs qui peuvent avoir plusieurs valeurs,
# comme les cases Ă cocher. Elle retourne toujours une liste.
values = form.getlist(key)
# Assainir chaque valeur dans la liste
sanitized_values = [html.escape(v) for v in values]
# Joindre la liste des valeurs en une chaßne séparée par des virgules pour l'affichage
display_value = ", ".join(sanitized_values)
print(f"<tr><td><strong>{sanitized_key}</strong></td><td>{display_value}</td></tr>")
print("</table>")
# Exemple d'accĂšs direct Ă une seule valeur
# Utilisez form.getvalue('key') pour les champs dont vous attendez une seule valeur.
# Il retourne None si la clé n'existe pas.
username = form.getvalue("username")
if username:
print(f"<h2>Bienvenue, {html.escape(username)} !</h2>")
Points clés à retenir de ce script :
- `import cgi` et `import html` : Nous importons les modules nécessaires. `cgi` pour l'analyse du formulaire et `html` pour la sécurité.
- `form = cgi.FieldStorage()` : Cette seule ligne fait tout le gros du travail. Elle vérifie les variables d'environnement (`REQUEST_METHOD`, `CONTENT_LENGTH`, etc.), lit le flux d'entrée approprié et analyse les données dans un objet facile à utiliser.
- La sécurité d'abord (`html.escape`) : Nous n'imprimons jamais les données soumises par l'utilisateur directement dans notre HTML. Le faire crée une vulnérabilité de type Cross-Site Scripting (XSS). La fonction `html.escape()` est utilisée pour neutraliser tout HTML ou JavaScript malveillant qu'un attaquant pourrait soumettre.
- `form.keys()` : Nous pouvons itérer sur tous les noms de champs soumis.
- `form.getlist(key)` : C'est le moyen le plus sĂ»r de rĂ©cupĂ©rer les valeurs. Comme un formulaire peut soumettre plusieurs valeurs pour le mĂȘme nom (par ex., des cases Ă cocher), `getlist()` retourne toujours une liste. Si le champ n'avait qu'une seule valeur, ce sera une liste avec un seul Ă©lĂ©ment.
- `form.getvalue(key)` : C'est un raccourci pratique lorsque vous n'attendez qu'une seule valeur. Il retourne la valeur unique directement, ou s'il y a plusieurs valeurs, il retourne une liste. Il retourne `None` si la clé n'est pas trouvée.
Maintenant, ouvrez `feedback_form.html` dans votre navigateur, remplissez les deux formulaires et voyez comment le script gÚre les données différemment mais efficacement à chaque fois.
Techniques CGI avancées et meilleures pratiques
Gestion de l'état : les cookies
HTTP est un protocole sans Ă©tat. Chaque requĂȘte est indĂ©pendante, et le serveur n'a aucune mĂ©moire des requĂȘtes prĂ©cĂ©dentes du mĂȘme client. Pour crĂ©er une expĂ©rience persistante (comme un panier d'achat ou une session connectĂ©e), nous devons gĂ©rer l'Ă©tat. La maniĂšre la plus courante de le faire est avec les cookies.
Un cookie est un petit morceau de donnĂ©es que le serveur envoie au navigateur du client. Le navigateur renvoie ensuite ce cookie avec chaque requĂȘte ultĂ©rieure au mĂȘme serveur. Un script CGI peut dĂ©finir un cookie en imprimant un en-tĂȘte `Set-Cookie` et peut lire les cookies entrants Ă partir de la variable d'environnement `HTTP_COOKIE`.
Créons un simple script de compteur de visiteurs. Enregistrez-le sous `cookie_counter.py`.
#!/usr/bin/env python3
import os
import http.cookies
# Charger les cookies existants depuis la variable d'environnement
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
visit_count = 0
# Essayer d'obtenir la valeur de notre cookie 'visit_count'
if 'visit_count' in cookie:
try:
# La valeur du cookie est une chaĂźne, donc nous devons la convertir en entier
visit_count = int(cookie['visit_count'].value)
except ValueError:
# GĂ©rer les cas oĂč la valeur du cookie n'est pas un nombre valide
visit_count = 0
# Incrémenter le compteur de visites
visit_count += 1
# DĂ©finir le cookie pour la rĂ©ponse. Cela sera envoyĂ© comme un en-tĂȘte 'Set-Cookie'.
# Nous définissons la nouvelle valeur pour 'visit_count'.
cookie['visit_count'] = visit_count
# Vous pouvez également définir des attributs de cookie comme la date d'expiration, le chemin, etc.
# cookie['visit_count']['expires'] = '...'
# cookie['visit_count']['path'] = '/'
# Imprimer d'abord l'en-tĂȘte Set-Cookie
print(cookie.output())
# Puis imprimer l'en-tĂȘte Content-Type normal
print("Content-Type: text/html\n")
# Et enfin le corps HTML
print("<h1>Compteur de visiteurs basé sur les cookies</h1>")
print(f"<p>Bienvenue ! C'est votre visite numéro : <strong>{visit_count}</strong>.</p>")
print("<p>Actualisez cette page pour voir le compteur augmenter.</p>")
print("<p><em>(Votre navigateur doit avoir les cookies activés pour que cela fonctionne.)</em></p>")
Ici, le module `http.cookies` de Python simplifie l'analyse de la chaĂźne `HTTP_COOKIE` et la gĂ©nĂ©ration de l'en-tĂȘte `Set-Cookie`. Chaque fois que vous visitez cette page, le script lit l'ancien compte, l'incrĂ©mente et renvoie la nouvelle valeur pour qu'elle soit stockĂ©e dans votre navigateur.
Débogage des scripts CGI : le module `cgitb`
Quand un script CGI échoue, le serveur renvoie souvent un message générique "500 Internal Server Error", ce qui n'est pas utile pour le débogage. Le module `cgitb` (CGI Traceback) de Python est une véritable bouée de sauvetage. En l'activant en haut de votre script, toute exception non gérée générera un rapport détaillé et formaté directement dans le navigateur.
Pour l'utiliser, ajoutez simplement ces deux lignes au début de votre script :
import cgitb
cgitb.enable()
Avertissement : Bien que `cgitb` soit inestimable pour le développement, vous devriez le désactiver ou le configurer pour journaliser dans un fichier dans un environnement de production. Exposer des traces d'exécution détaillées au public peut révéler des informations sensibles sur la configuration et le code de votre serveur.
Téléchargements de fichiers avec CGI
L'objet `cgi.FieldStorage` gĂšre Ă©galement de maniĂšre transparente les tĂ©lĂ©chargements de fichiers. Le formulaire HTML doit ĂȘtre configurĂ© avec `method="POST"` et, de maniĂšre cruciale, `enctype="multipart/form-data"`.
Créons un formulaire de téléchargement de fichiers, `upload.html` :
<!DOCTYPE html>
<html lang="fr">
<head>
<title>Téléchargement de fichier</title>
</head>
<body>
<h1>Télécharger un fichier</h1>
<form action="/cgi-bin/upload_handler.py" method="POST" enctype="multipart/form-data">
<label for="userfile">Sélectionnez un fichier à télécharger :</label>
<input type="file" id="userfile" name="userfile">
<br/><br/>
<input type="submit" value="Télécharger le fichier">
</form>
</body>
</html>
Et maintenant le gestionnaire, `upload_handler.py`. Note : Ce script nĂ©cessite un rĂ©pertoire nommĂ© `uploads` au mĂȘme emplacement que le script, et le serveur web doit avoir la permission d'y Ă©crire.
#!/usr/bin/env python3
import cgi
import os
import html
# Activer le rapport d'erreurs détaillé pour le débogage
import cgitb
cgitb.enable()
print("Content-Type: text/html\n")
print("<h1>Gestionnaire de téléchargement de fichiers</h1>")
# RĂ©pertoire oĂč les fichiers seront sauvegardĂ©s. SĂCURITĂ : Ce devrait ĂȘtre un rĂ©pertoire sĂ©curisĂ© et non accessible via le web.
upload_dir = './uploads/'
# Créer le répertoire s'il n'existe pas
if not os.path.exists(upload_dir):
os.makedirs(upload_dir, exist_ok=True)
# IMPORTANT : Définir les bonnes permissions. Dans un scénario réel, ce serait plus restrictif.
# os.chmod(upload_dir, 0o755)
form = cgi.FieldStorage()
# Obtenir l'élément fichier du formulaire. 'userfile' est le 'name' du champ de saisie.
file_item = form['userfile']
# Vérifier si un fichier a bien été téléchargé
if file_item.filename:
# SĂCURITĂ : Ne jamais faire confiance au nom de fichier fourni par l'utilisateur.
# Il pourrait contenir des caractÚres de chemin comme '../' (attaque par traversée de répertoire).
# Nous utilisons os.path.basename pour supprimer toute information de répertoire.
fn = os.path.basename(file_item.filename)
# Créer le chemin complet pour sauvegarder le fichier
file_path = os.path.join(upload_dir, fn)
try:
# Ouvrir le fichier en mode écriture binaire et écrire les données téléchargées
with open(file_path, 'wb') as f:
f.write(file_item.file.read())
message = f"Le fichier '{html.escape(fn)}' a été téléchargé avec succÚs !"
print(f"<p style='color: green;'>{message}</p>")
except IOError as e:
message = f"Erreur lors de la sauvegarde du fichier : {e}. Vérifiez les permissions du serveur pour le répertoire '{upload_dir}'."
print(f"<p style='color: red;'>{message}</p>")
else:
message = 'Aucun fichier n\'a été téléchargé.'
print(f"<p style='color: orange;'>{message}</p>")
print("<a href='/upload.html'>Télécharger un autre fichier</a>")
Sécurité : la préoccupation primordiale
Parce que les scripts CGI sont des programmes exécutables directement exposés à Internet, la sécurité n'est pas une option, c'est une exigence. Une seule erreur peut conduire à la compromission du serveur.
Validation et assainissement des entrées (Prévention du XSS)
Comme nous l'avons déjà vu, vous ne devez jamais faire confiance aux entrées de l'utilisateur. Supposez toujours qu'elles sont malveillantes. Lorsque vous affichez des données fournies par l'utilisateur dans une page HTML, échappez-les toujours avec `html.escape()` pour prévenir les attaques de type Cross-Site Scripting (XSS). Un attaquant pourrait sinon injecter des balises `