Explorer HTTPS avec Python – Real Python

By | janvier 8, 2020

Python pas cher

Vous êtes-vous déjà demandé pourquoi vous pouvez envoyer vos informations de carte de crédit sur Internet? Vous avez peut-être remarqué https: // sur les URL de votre navigateur, mais qu'est-ce que c'est et comment garder vos informations en sécurité? Ou peut-être souhaitez-vous créer une application Python HTTPS, mais vous ne savez pas exactement ce que cela signifie. Comment pouvez-vous être sûr que votre application Web est sûre?

Cela peut vous surprendre de savoir que vous n'avez pas besoin d'être un expert en sécurité pour répondre à ces questions! Dans ce didacticiel, vous obtiendrez une connaissance pratique des différents facteurs qui se combinent pour assurer la sécurité des communications sur Internet. Vous verrez des exemples concrets de la façon dont une application Python HTTPS sécurise les informations.

Dans ce didacticiel, vous apprendrez à:

  • Surveiller et analyser trafic réseau
  • Appliquer la cryptographie pour protéger les données
  • Décrire les concepts fondamentaux de Infrastructure à clé publique (PKI)
  • Crée le tien Autorité de certification
  • Construire un Application HTTPS Python
  • Identifier les HTTPS Python courants avertissements et erreurs

Qu'est-ce que HTTP?

Avant de vous plonger dans HTTPS et son utilisation dans Python, il est important de comprendre son parent, HTTP. Cet acronyme signifie Protocole de transfert hypertexte, qui sous-tend la plupart des communications qui se produisent lorsque vous surfez sur vos sites Web préférés. Plus précisément, HTTP est la façon dont un agent utilisateur, comme votre navigateur Web, communique avec un serveur Web, comme realpython.com. Voici un schéma simplifié des communications HTTP:

Flux de négociation HTTP

Ce diagramme montre une version simplifiée de la façon dont votre ordinateur communique avec un serveur. Voici la répartition de chaque étape:

  1. Vous dites à votre navigateur d'accéder à http://someserver.com/link.
  2. Votre appareil et le serveur configurent une connexion TCP.
  3. Votre navigateur envoie un Requête HTTP au serveur.
  4. Le serveur reçoit la requête HTTP et l’analyse.
  5. Le serveur répond par un Réponse HTTP.
  6. Votre ordinateur reçoit, analyse et affiche la réponse.

Cette ventilation capture les bases de HTTP. Vous faites une demande à un serveur et le serveur renvoie une réponse. Bien que HTTP ne nécessite pas TCP, il nécessite un protocole fiable de niveau inférieur. En pratique, il s'agit presque toujours de TCP sur IP (bien que Google essaie de créer un remplaçant). Si vous avez besoin d'une mise à jour, consultez la programmation des sockets en Python (Guide).

Au fur et à mesure des protocoles, HTTP est l'un des plus simples. Il a été conçu pour envoyer du contenu sur Internet, comme du HTML, des vidéos, des images, etc. Cela se fait avec une requête et une réponse HTTP. Les requêtes HTTP contiennent les éléments suivants:

  • La méthode décrit l'action que le client souhaite effectuer. La méthode pour le contenu statique est généralement AVOIR, bien qu'il en existe d'autres, comme PUBLIER, TÊTE, et SUPPRIMER.
  • Le chemin indique au serveur la page Web que vous souhaitez demander. Par exemple, le chemin de cette page est / python-https.
  • La version est l'une des nombreuses versions HTTP, comme 1.0, 1.1 ou 2.0. Le plus courant est probablement le 1.1.
  • Les en-têtes aide à décrire des informations supplémentaires pour le serveur.
  • Le corps fournit au serveur les informations du client. Bien que ce champ ne soit pas obligatoire, il est typique pour certaines méthodes d'avoir un corps, comme un PUBLIER.

Ce sont les outils que votre navigateur utilise pour communiquer avec un serveur. Le serveur répond avec une réponse HTTP. La réponse HTTP contient les éléments suivants:

  • La version identifie la version HTTP, qui sera généralement la même que la version de la demande.
  • Le code d'état indique si une demande a abouti. Il existe plusieurs codes d'état.
  • Le message d'état fournit un message lisible par l'homme qui aide à décrire le code d'état.
  • Les en-têtes permettre au serveur de répondre avec des métadonnées supplémentaires sur la demande. Il s'agit du même concept que les en-têtes de demande.
  • Le corps porte le contenu. Techniquement, c'est facultatif, mais il contient généralement une ressource utile.

Ce sont les éléments constitutifs de HTTP. Si vous souhaitez en savoir plus sur HTTP, vous pouvez consulter une page de présentation pour en savoir plus sur le protocole.

Qu'est-ce que HTTPS?

Maintenant que vous en savez un peu plus sur HTTP, qu'est-ce que HTTPS? La bonne nouvelle est que vous le savez déjà! HTTPS signifie Protocole de transfert hypertexte sécurisé de. Fondamentalement, HTTPS est le même protocole que HTTP mais avec l'implication supplémentaire que les communications sont sécurisées.

HTTPS ne réécrit aucun des principes fondamentaux HTTP sur lesquels il est basé. Au lieu de cela, HTTPS consiste en HTTP standard envoyé via une connexion cryptée. En règle générale, cette connexion cryptée est fournie par TLS ou SSL, qui sont protocoles cryptographiques qui chiffrent les informations avant leur envoi sur un réseau.

Alors, pourquoi créer cette séparation? Pourquoi ne pas simplement introduire la complexité dans le protocole HTTP lui-même? La réponse est portabilité. La sécurisation des communications est un problème important et difficile, mais HTTP n'est qu'un des nombreux protocoles qui nécessitent une sécurité. Il existe d'innombrables autres dans une grande variété d'applications:

  • Email
  • Messagerie instantannée
  • VoIP (voix sur IP)

Il y a d'autres aussi! Si chacun de ces protocoles devait créer son propre mécanisme de sécurité, le monde serait beaucoup moins sûr et beaucoup plus déroutant. TLS, qui est souvent utilisé par les protocoles ci-dessus, fournit une méthode courante pour sécuriser les communications.

Presque toutes les informations que vous apprendrez dans ce didacticiel seront applicables à plus que des applications Python HTTPS. Vous apprendrez les bases des communications sécurisées ainsi que la manière dont elles s'appliquent spécifiquement au HTTPS.

Pourquoi le HTTPS est-il important?

Les communications sécurisées sont essentielles pour fournir un environnement en ligne sûr. Alors que de plus en plus de monde se déplace en ligne, y compris les banques et les sites de soins de santé, il devient de plus en plus important pour les développeurs de créer des applications Python HTTPS. Encore une fois, HTTPS est simplement HTTP sur TLS ou SSL. TLS est conçu pour assurer la confidentialité des écoutes. Il peut également fournir une authentification à la fois du client et du serveur.

Dans cette section, vous allez explorer ces concepts en profondeur en procédant comme suit:

  1. Créer un serveur Python HTTPS
  2. Communicant avec votre serveur Python HTTPS
  3. Capture ces communications
  4. en cours d'analyse ces messages

Commençons!

Création d'un exemple d'application

Supposons que vous soyez le chef d'un club de Python cool appelé les écureuils secrets. Les écureuils, étant secrets, ont besoin d'un message secret pour assister à leurs réunions. En tant que leader, vous choisissez le message secret, qui change pour chaque réunion. Parfois, cependant, il est difficile pour vous de rencontrer tous les membres avant la réunion pour leur dire le message secret! Vous décidez de mettre en place un serveur secret où les membres peuvent simplement voir le message secret par eux-mêmes.

Vous avez suivi quelques didacticiels sur Real Python et décidez d'utiliser certaines dépendances que vous connaissez:

  • Ballon construire une application web
  • uWSGI comme serveur de production
  • demandes exercer votre serveur

Pour installer toutes ces dépendances, vous pouvez utiliser pépin:

$ pip install flask uwsgi request

Une fois vos dépendances installées, vous commencez à écrire votre application. Dans un fichier appelé server.py, vous créez une application Flask:

# server.py
de ballon importation Ballon

SECRET_MESSAGE = "queue duveteuse"
app = Ballon(__Nom__)

@app.route("/")
def get_secret_message():
    revenir SECRET_MESSAGE

Cette application Flask affichera le message secret chaque fois que quelqu'un visite le / chemin de votre serveur. Avec cela à l'écart, vous déployez votre application sur votre serveur secret et l'exécutez:

$ uwsgi --http-socket 127.0.0.1: 5683 --mount /=serveur: application

Cette commande démarre un serveur à l'aide de l'application Flask ci-dessus. Vous le démarrez sur un port étrange parce que vous ne voulez pas que les gens puissent le trouver, et vous tapotez le dos pour être si sournois! Vous pouvez confirmer que cela fonctionne en visitant http: // localhost: 5683 dans votre navigateur.

Étant donné que tout le monde dans les écureuils secrets connaît Python, vous décidez de les aider. Vous écrivez un script appelé client.py qui les aidera à obtenir le message secret:

# client.py
importation os
importation demandes

def get_secret_message():
    url = os.environ[[[["SECRET_URL"]
    réponse = demandes.avoir(url)
    impression(F"Le message secret est: response.text")

si __Nom__ == "__principale__":
    get_secret_message()

Ce code imprimera le message secret tant qu'il aura le SECRET_URL ensemble de variables d'environnement. Dans ce cas, le SECRET_URL est 127.0.0.1:5683. Donc, votre plan est de donner à chaque membre du club l'URL secrète et de leur dire de la garder secrète et sûre.

Bien que cela puisse sembler correct, soyez assuré que ce n'est pas le cas! En fait, même si vous deviez mettre un nom d’utilisateur et un mot de passe sur ce site, ce ne serait toujours pas sûr. Mais même si votre équipe a réussi à protéger l'URL, votre message secret ne serait toujours pas sécurisé. Pour montrer pourquoi vous devez en savoir un peu plus sur la surveillance du trafic réseau. Pour ce faire, vous allez utiliser un outil appelé Wireshark.

Configuration de Wireshark

Wireshark est un outil largement utilisé pour l'analyse de réseaux et de protocoles. Cela signifie que cela peut vous aider à voir ce qui se passe sur les connexions réseau. L'installation et la configuration de Wireshark sont facultatives pour ce didacticiel, mais n'hésitez pas si vous souhaitez suivre. La page de téléchargement propose plusieurs programmes d'installation:

  • macOS 10.12 et versions ultérieures
  • Programme d'installation de Windows 64 bits
  • Programme d'installation de Windows 32 bits

Si vous utilisez Windows ou Mac, vous devriez pouvoir télécharger le programme d'installation approprié et suivre les invites. À la fin, vous devriez avoir un Wireshark en cours d'exécution.

Si vous êtes dans un environnement Linux basé sur Debian, l'installation est un peu plus difficile, mais toujours possible. Vous pouvez installer Wireshark avec les commandes suivantes:

$ sudo add-apt-repository ppa: cableshark-dev / stable
$ mise à jour sudo apt-get
$ sudo apt-get install filshark
$ sudo filshark

Vous devriez rencontrer un écran qui ressemble à ceci:

Écran principal de Wireshark

Avec Wireshark en marche, il est temps d'analyser du trafic!

S'assurer que vos données ne sont pas sécurisées

La façon dont votre client et serveur actuel s'exécute est pas sécurisé. HTTP enverra tout en clair pour que tout le monde puisse le voir. Cela signifie que même si quelqu'un n'a pas votre SECRET_URL, ils peuvent toujours voir tout ce que vous faites tant qu'ils peuvent surveiller le trafic sur tout entre vous et le serveur.

Cela devrait être relativement effrayant pour vous. Après tout, vous ne voulez pas que d'autres personnes se présentent pour vos réunions Secret Squirrel! Vous pouvez prouver que cela se produit. Tout d'abord, démarrez votre serveur si vous ne le faites pas encore fonctionner:

$ uwsgi --http-socket 127.0.0.1: 5683 --mount /=serveur: application

Cela démarrera votre application Flask sur le port 5683. Ensuite, vous commencerez une capture de paquets dans Wireshark. Cette capture de paquets vous aidera à voir tout le trafic entrant et sortant du serveur. Commencez par sélectionner le Bouclage: lo interface sur Wireshark:

Wireshark avec Loopback sélectionné

Vous pouvez voir que le Bouclage: lo est mise en évidence. Cela demande à Wireshark de surveiller ce port pour le trafic. Vous pouvez faire mieux et spécifier le port et le protocole que vous souhaitez capturer. Vous pouvez taper port 5683 dans le filtre de capture et http dans le filtre d'affichage:

Wireshark avec le port 5683 rempli

La case verte indique que Wireshark est satisfait du filtre que vous avez tapé. Vous pouvez maintenant commencer la capture en cliquant sur l'ailette en haut à gauche:

Wireshark avec bouclage et filtrage de port cliqué

Cliquez sur ce bouton pour ouvrir une nouvelle fenêtre dans Wireshark:

Page de capture de Wireshark sans rien capturé

Cette nouvelle fenêtre est assez simple, mais le message en bas dit , ce qui indique que cela fonctionne. Ne vous inquiétez pas que rien ne soit affiché, car c'est normal. Pour que Wireshark signale quoi que ce soit, il doit y avoir une certaine activité sur votre serveur. Pour obtenir des données, essayez d'exécuter votre client:

$ SECRET_URL="http://127.0.0.1:5683" python client.py
Le message secret est: queue moelleuse

Après avoir exécuté le client.py code ci-dessus, vous devriez maintenant voir quelques entrées dans Wireshark. Si tout s'est bien passé, vous verrez deux entrées qui ressemblent à ceci:

Wireshark avec requête HTTP et réponse capturée

Ces deux entrées représentent les deux parties de la communication qui ont eu lieu. Le premier est la demande du client à votre serveur. Lorsque vous cliquez sur la première entrée, vous verrez une multitude d'informations:

La première requête HTTP dans Wireshark

C’est beaucoup d’informations! En haut, vous avez toujours votre demande et votre réponse HTTP. Une fois que vous avez sélectionné l'une de ces entrées, vous verrez les lignes du milieu et du bas remplies d'informations.

La ligne du milieu vous fournit une ventilation des protocoles que Wireshark a pu identifier pour la demande sélectionnée. Cette ventilation vous permet d'explorer ce qui s'est réellement passé dans votre requête HTTP. Voici un bref résumé des informations que Wireshark décrit dans la ligne du milieu de haut en bas:

  1. Couche physique: Cette ligne décrit l'interface physique utilisée pour envoyer la demande. Dans votre cas, il s'agit probablement de l'ID d'interface 0 (lo) pour votre interface de bouclage.
  2. Informations Ethernet: Cette ligne vous montre le protocole de couche 2, qui inclut les adresses MAC source et de destination.
  3. IPv4: Cette ligne affiche les adresses IP source et de destination (127.0.0.1).
  4. TCP: Cette ligne inclut la négociation TCP requise afin de créer un canal de données fiable.
  5. HTTP: Cette ligne affiche des informations sur la demande HTTP elle-même.

Lorsque vous développez la couche Hypertext Transfer Protocol, vous pouvez voir toutes les informations qui composent une demande HTTP:

Requête HTTP avec des détails étendus dans Wireshark

Cette image vous montre la requête HTTP de votre script:

  • Méthode: AVOIR
  • Chemin: /
  • Version: 1.1
  • En-têtes: Hôte: 127.0.0.1:5683, Connexion: garder en vie, et d'autres
  • Corps: Personne

La dernière ligne que vous verrez est un vidage hexadécimal des données. Vous pouvez remarquer dans ce vidage hexadécimal que vous pouvez réellement voir les parties de votre requête HTTP. C'est parce que votre demande HTTP a été envoyée en plein air. Mais qu'en est-il de la réponse? Si vous cliquez sur la réponse HTTP, vous verrez une vue similaire:

Wireshark avec réponse HTTP étendu

Encore une fois, vous avez les trois mêmes sections. Si vous regardez attentivement le vidage hexadécimal, vous verrez le message secret en texte clair! C'est un gros problème pour les écureuils secrets. Cela signifie que toute personne possédant un certain savoir-faire technique peut très facilement voir ce trafic si elle est intéressée. Alors, comment résolvez-vous ce problème? La réponse est la cryptographie.

Comment la cryptographie aide-t-elle?

Dans cette section, vous apprendrez comment protéger vos données en créant les vôtres clés de cryptographie et en les utilisant à la fois sur votre serveur et sur votre client. Bien que ce ne soit pas votre dernière étape, cela vous aidera à obtenir une base solide sur la façon de créer des applications Python HTTPS.

Comprendre les bases de la cryptographie

La cryptographie est un moyen de sécuriser les communications des écoutes ou des adversaires. Une autre façon de le dire est que vous prenez des informations normales, appelées texte en clair, et le convertir en texte brouillé, appelé texte chiffré.

La cryptographie peut être intimidante au début, mais les concepts fondamentaux sont assez accessibles. En fait, vous avez probablement déjà pratiqué la cryptographie auparavant. Si vous avez déjà eu une langue secrète avec vos amis et l'avez utilisée pour passer des notes en classe, alors vous avez pratiqué la cryptographie. (Si vous ne l'avez pas fait, ne vous inquiétez pas, vous êtes sur le point de le faire.)

D'une certaine manière, vous devez prendre la chaîne "queue duveteuse" et le convertir en quelque chose d'inintelligible. Une façon de procéder consiste à mapper certains personnages sur des personnages différents. Un moyen efficace de le faire est de reculer les caractères d'un point dans l'alphabet. Cela ressemblerait à quelque chose comme ceci:

Un chiffre alphabétique décalé de 1 espace

Cette image vous montre comment traduire de l'alphabet original vers le nouvel alphabet et inversement. Donc, si vous aviez le message abc, vous enverriez alors le message ZAB. Si vous appliquez ceci à "queue duveteuse", puis en supposant que les espaces restent les mêmes, vous obtenez ekteex szhk. Bien qu'il ne soit pas parfait, il ressemblera probablement à du charabia pour quiconque le verra.

Toutes nos félicitations! Vous avez créé ce qui est connu en cryptographie comme chiffrer, qui décrit comment convertir du texte en clair en texte chiffré et inversement. Votre chiffre, dans ce cas, est décrit en anglais. Ce type particulier de chiffrement est appelé chiffre de substitution. Fondamentalement, il s'agit du même type de chiffrement utilisé dans la machine Enigma, bien que sa version soit beaucoup plus simple.

Maintenant, si vous souhaitez envoyer un message aux écureuils secrets, vous devez d'abord leur dire combien de lettres à déplacer, puis leur donner le message codé. En Python, cela pourrait ressembler à ceci:

CHIFFRER = "une": "z", "UNE": "Z", "b": "une" # Etc

def Crypter(texte en clair: str):
    revenir "".joindre(CHIFFRER.avoir(lettre, lettre) pour lettre dans texte en clair)

Ici, vous avez créé une fonction appelée Crypter(), qui prendra le texte en clair et le convertira en texte chiffré. Imaginez que vous ayez un dictionnaire CHIFFRER qui a tous les personnages tracés. De même, vous pouvez créer un déchiffrer ():

DÉCHIFFRER = v: k pour k, v dans CHIFFRER.articles()

def décrypter(texte chiffré: str):
    revenir "".joindre(DÉCHIFFRER.avoir(lettre, lettre) pour lettre dans texte chiffré)

Cette fonction est l'opposé de Crypter(). Il prendra le texte chiffré et le convertira en texte clair. Dans cette forme de chiffrement, vous disposez d'une clé spéciale que les utilisateurs doivent connaître pour chiffrer et déchiffrer les messages. Pour l'exemple ci-dessus, cette clé est 1. Autrement dit, le chiffre indique que vous devez reculer chaque lettre d'un caractère. La clé est très importante à garder secrète car toute personne possédant la clé peut facilement décrypter votre message.

À l'ère moderne, la cryptographie est beaucoup plus avancée. Il repose sur la théorie mathématique complexe et l'informatique pour être sécurisé. Bien que les mathématiques derrière ces chiffres sortent du cadre de ce didacticiel, les concepts sous-jacents sont toujours les mêmes. Vous disposez d'un chiffre qui décrit comment prendre du texte en clair et le convertir en texte chiffré.

La seule vraie différence entre votre chiffre de substitution et les chiffres modernes est que les chiffres modernes se sont révélés mathématiquement peu pratiques à briser par une écoute indiscrète. Voyons maintenant comment utiliser vos nouveaux chiffres.

Utilisation de la cryptographie dans les applications Python HTTPS

Heureusement pour vous, vous n'avez pas besoin d'être un expert en mathématiques ou en informatique pour utiliser la cryptographie. Python a également un les secrets module qui peut vous aider à générer des données aléatoires cryptographiquement sécurisées. Dans ce didacticiel, vous découvrirez une bibliothèque Python qui porte bien son nom la cryptographie. Il est disponible sur PyPI, vous pouvez donc l'installer avec pip:

$ pip installer la cryptographie

Cela va installer la cryptographie dans votre environnement virtuel. Avec la cryptographie installé, vous pouvez désormais crypter et décrypter des éléments de manière mathématiquement sécurisée en utilisant Fernet méthode.

Rappelez-vous que votre clé secrète dans votre chiffre était 1. Dans le même esprit, vous devez créer une clé pour que Fernet fonctionne correctement:

>>>

>>> de cryptography.fernet importation Fernet
>>> clé = Fernet.generate_key()
>>> clé
b'8jtTR9QcD-k3RO9Pcd5ePgmTu_itJQt9WKQPzqjrcoM = '

Dans ce code, vous avez importé Fernet et a généré une clé. La clé n'est qu'un tas d'octets, mais il est extrêmement important que vous gardiez cette clé secrète et en sécurité. Tout comme l'exemple de substitution ci-dessus, toute personne possédant cette clé peut facilement décrypter vos messages.

Cette clé se comporte un peu comme la clé précédente. Il est nécessaire de passer au texte chiffré et de revenir au texte en clair. Il est maintenant temps pour la partie amusante! Vous pouvez crypter un message comme celui-ci:

>>>

>>> my_cipher = Fernet(clé)
>>> texte chiffré = my_cipher.Crypter(b"queue duveteuse")
>>> texte chiffré
b'gAAAAABdlW033LxsrnmA2P0WzaS-wk1UKXA1IdyDpmHcV6yrE7H_ApmSK8KpCW-6jaODFaeTeDRKJMMsa_526koApx1suJ4_dQ == '

Dans ce code, vous avez créé un objet Fernet appelé my_cipher, que vous pouvez ensuite utiliser pour crypter votre message. Notez que votre message secret "queue duveteuse" doit être un octets objet afin de le crypter. Après le cryptage, vous pouvez voir que le texte chiffré est un long flux d'octets.

Grâce à Fernet, ce texte chiffré ne peut pas être manipulé ou lu sans la clé! Ce type de cryptage nécessite que le serveur et le client aient accès à la clé. Lorsque les deux côtés ont besoin de la même clé, cela s'appelle un cryptage symétrique. Dans la section suivante, vous verrez comment utiliser ce cryptage symétrique pour protéger vos données.

S'assurer que vos données sont en sécurité

Maintenant que vous comprenez certaines des bases de la cryptographie en Python, vous pouvez appliquer ces connaissances à votre serveur. Créez un nouveau fichier appelé symmetric_server.py:

# symmetric_server.py
importation os
de ballon importation Ballon
de cryptography.fernet importation Fernet

CLEF SECRÈTE = os.environb[[[[b"CLEF SECRÈTE"]
SECRET_MESSAGE = b"queue duveteuse"
app = Ballon(__Nom__)

my_cipher = Fernet(CLEF SECRÈTE)

@app.route("/")
def get_secret_message():
    revenir my_cipher.Crypter(SECRET_MESSAGE)

Ce code combine votre code de serveur d'origine avec le Fernet objet que vous avez utilisé dans la section précédente. La clé est maintenant lue comme octets objet de l'environnement à l'aide os.environb. Le serveur étant à l'écart, vous pouvez désormais vous concentrer sur le client. Collez ce qui suit dans symmetric_client.py:

# symmetric_client.py
importation os
importation demandes
de cryptography.fernet importation Fernet

CLEF SECRÈTE = os.environb[[[[b"CLEF SECRÈTE"]
my_cipher = Fernet(CLEF SECRÈTE)

def get_secret_message():
    réponse = demandes.avoir("http://127.0.0.1:5683")

    decrypted_message = my_cipher.décrypter(réponse.contenu)
    impression(F"Le mot de code est: decrypted_message")

si __Nom__ == "__principale__":
    get_secret_message()

Encore une fois, il s'agit d'un code modifié pour combiner votre ancien client avec le Fernet mécanisme de cryptage. get_secret_message () fait ce qui suit:

  1. Faire la demande à votre serveur.
  2. Prendre les octets bruts de la réponse.
  3. Tentative pour décrypter les octets bruts.
  4. Impression le message déchiffré.

Si vous exécutez à la fois le serveur et le client, vous verrez que vous réussissez à crypter et décrypter votre message secret:

$ uwsgi --http-socket 127.0.0.1: 5683 
    --env CLEF SECRÈTE="8jtTR9QcD-k3RO9Pcd5ePgmTu_itJQt9WKQPzqjrcoM ="
                --mount / = symmetric_server: app

Dans cet appel, vous redémarrez le serveur sur le port 5683. Cette fois, vous passez dans un CLEF SECRÈTE qui doit être au moins une chaîne codée en base64. Avec votre serveur redémarré, vous pouvez maintenant l'interroger:

$ CLEF SECRÈTE="8jtTR9QcD-k3RO9Pcd5ePgmTu_itJQt9WKQPzqjrcoM =" python symmetric_client.py
Le message secret est: b'fluffy tail '

Woohoo! Vous avez pu crypter et décrypter votre message. Si vous essayez d'exécuter ceci avec un invalide CLEF SECRÈTE, vous obtiendrez alors une erreur:

$ CLEF SECRÈTE="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA =" python symmetric_client.py
Traceback (dernier appel le plus récent):
        Fichier "... / cryptography / fernet.py", ligne 104, dans _verify_signature
                h.verify (données[-32:])
        Fichier "... / cryptographie / hazmat / primitives / hmac.py", ligne 66, en vérification
                ctx.verify (signature)
        Fichier "... / cryptography / hazmat / backends / openssl / hmac.py", ligne 74, en vérification
                augmenter InvalidSignature ("La signature ne correspond pas au résumé.")
cryptography.exceptions.InvalidSignature: la signature ne correspond pas au résumé.

Lors du traitement de l'exception ci-dessus, une autre exception s'est produite:

Traceback (dernier appel le plus récent):
        Fichier "symmetric_client.py", ligne 16, dans 
                get_secret_message ()
        Fichier "symmetric_client.py", ligne 11, dans get_secret_message
                decrypted_message = my_cipher.decrypt (response.content)
        Fichier "... / cryptography / fernet.py", ligne 75, en décryptage
                return self._decrypt_data (data, timestamp, ttl)
        Fichier "... / cryptography / fernet.py", ligne 117, dans _decrypt_data
                self._verify_signature (données)
        Fichier "... / cryptography / fernet.py", ligne 106, dans _verify_signature
                soulever InvalidToken
cryptography.fernet.InvalidToken

Donc, vous savez que le chiffrement et le déchiffrement fonctionnent. Mais est-ce sécurise? Eh bien, oui. Pour le prouver, vous pouvez revenir à Wireshark et démarrer une nouvelle capture avec les mêmes filtres qu'auparavant. Une fois la configuration de capture terminée, réexécutez le code client:

$ CLEF SECRÈTE="8jtTR9QcD-k3RO9Pcd5ePgmTu_itJQt9WKQPzqjrcoM =" python symmetric_client.py
Le message secret est: b'fluffy tail '

Vous avez effectué une autre requête et réponse HTTP réussie et, une fois de plus, vous voyez ces messages dans Wireshark. Étant donné que le message secret n'est transféré que dans la réponse, vous pouvez cliquer dessus pour consulter les données:

Vue de Wireshark de la réponse HTTP qui a été chiffrée à l'aide du chiffrement symétrique

Dans la ligne centrale de cette image, vous pouvez voir les données qui ont été réellement transférées:

gAAAAABdlXSesekh9LYGDpZE4jkxm4Ai6rZQg2iHaxyDXkPWz1O74AB37V_a4vabF13fEr4kwmCe98Wlr8Zo1XNm-WjAVtSgFQ ==

Impressionnant! Cela signifie que les données ont été cryptées et que les écoutes ne savent pas quel est le contenu du message. Non seulement cela, mais cela signifie également qu'ils pourraient passer un temps incroyablement long à essayer de casser ces données par force brute, et ils ne réussiraient presque jamais.

Vos données sont en sécurité! Mais attendez une minute – vous n'aviez jamais eu à connaître quoi que ce soit sur une clé lorsque vous utilisiez des applications Python HTTPS auparavant. En effet, HTTPS n'utilise pas exclusivement le chiffrement symétrique. Il s'avère que le partage des secrets est un problème difficile.

Pour prouver ce concept, accédez à http://127.0.0.1:5683 dans votre navigateur, et vous verrez le texte de réponse chiffré. En effet, votre navigateur ne sait rien de votre clé de chiffrement secrète. Alors, comment fonctionnent réellement les applications Python HTTPS? C'est là que chiffrement asymétrique entre en jeu.

Comment les clés sont-elles partagées?

Dans la section précédente, vous avez vu comment utiliser le chiffrement symétrique pour sécuriser vos données lors de leur passage sur Internet. Pourtant, même si le cryptage symétrique est sécurisé, ce n'est pas la seule technique de cryptage utilisée par les applications Python HTTPS pour protéger vos données. Le chiffrement symétrique introduit certains problèmes fondamentaux qui ne sont pas si facilement résolus.

Alors, comment allez-vous changement ta clé? Si vous n'avez qu'un seul serveur et un seul client, cela peut être une tâche rapide. Cependant, à mesure que vous obtenez plus de clients et plus de serveurs, il y a de plus en plus de coordination qui doit se produire afin de changer la clé et de garder vos secrets en sécurité efficacement.

De plus, vous devez à chaque fois choisir un nouveau secret. Dans l'exemple ci-dessus, vous avez vu une clé générée de manière aléatoire. Il peut être presque impossible pour vous d'essayer de faire en sorte que les gens se souviennent de cette clé. À mesure que votre nombre de clients et de serveurs augmente, vous utiliserez probablement des clés plus faciles à mémoriser et à deviner.

Si vous parvenez à changer votre clé, vous avez encore un problème à résoudre. Comment tu partager votre clé initiale? Dans l'exemple des écureuils secrets, vous avez résolu ce problème en ayant un accès physique à chacun des membres. Vous pourriez donner à chaque membre le secret en personne et leur dire de le garder secret, mais rappelez-vous que quelqu'un sera le maillon le plus faible.

Supposons maintenant que vous ajoutez un membre aux écureuils secrets à partir d'un autre emplacement physique. Comment partagez-vous le secret avec ce membre? Leur faites-vous prendre l'avion à chaque fois que la clé change? Ce serait bien si vous pouviez mettre en place la clé secrète sur votre serveur et la partager automatiquement. Malheureusement, cela irait à l'encontre de l'objectif du cryptage, car n'importe qui pourrait obtenir la clé secrète!

Bien sûr, vous pouvez donner à tout le monde une clé principale initiale pour obtenir le message secret, mais maintenant vous avez juste deux fois plus de problèmes qu'auparavant. Si votre tête vous fait mal, ne vous inquiétez pas! Tu n'es pas le seul.

Ce dont vous avez besoin, c'est que deux parties qui n'ont jamais communiqué aient un secret partagé. Cela semble impossible, non? Heureusement, trois gars du nom de Ralph Merkle, Whitfield Diffie et Martin Hellman ont le dos. Ils ont aidé à démontrer que la cryptographie à clé publique, également connue sous le nom de cryptage asymétrique, était possible.

Cryptage asymétrique permet à deux utilisateurs qui n'ont jamais communiqué auparavant de partager un secret commun. L'une des façons les plus simples de comprendre les principes fondamentaux consiste à utiliser une analogie des couleurs. Imaginez que vous ayez le scénario suivant:

Configuration initiale de Diffie Hellman Key Exchange

Dans ce diagramme, vous essayez de communiquer avec un écureuil secret que vous n'avez jamais rencontré auparavant, mais un espion peut voir tout ce que vous envoyez. Vous connaissez le chiffrement symétrique et souhaitez l'utiliser, mais vous devez d'abord partager un secret. Heureusement, vous avez tous les deux une clé privée. Malheureusement, vous ne pouvez pas envoyer votre clé privée car l'espion la verra. Donc que fais-tu?

La première chose que vous devez faire est de convenir avec votre partenaire d'une couleur, comme le jaune:

Couleurs partagées de Diffie Hellman Key Exchange

Notez ici que l'espion peut voir la couleur partagée, tout comme vous et l'écureuil secret. La couleur partagée est effectivement Publique. Maintenant, vous et l'écureuil secret combinez votre privé touches avec la couleur partagée:

Couleurs combinées Diffie Hellman Key Exchange

Vos couleurs se combinent pour faire du vert, tandis que les couleurs de l'écureuil secret se combinent pour faire de l'orange. Vous avez tous deux terminé avec la couleur partagée, et maintenant vous devez partager vos couleurs combinées entre elles:

Échange de couleurs combinées dans Diffie Hellman Key Exchange

Vous avez maintenant votre clé privée et la couleur combinée de Secret Squirrel. De même, l'écureuil secret a sa clé privée et votre couleur combinée. Il a été assez rapide pour vous et l'écureuil secret de combiner vos couleurs.

L'espion, cependant, n'a que ces couleurs combinées. Essayer de comprendre votre exact la couleur d'origine est très dure, même compte tenu de la couleur partagée initiale. L'espion devrait aller au magasin et acheter beaucoup de bleus différents pour essayer. Même alors, il serait difficile de savoir s'ils regardaient la bonne teinte de vert après la combinaison! Bref, votre clé privée est toujours privé.

Mais qu'en est-il de vous et de l'écureuil secret? Vous n'avez toujours pas de secret combiné! C'est là que votre clé privée revient. Si vous combinez votre clé privée avec la couleur combinée que vous avez reçue de l'écureuil secret, vous vous retrouverez tous les deux avec la même couleur:

Secret partagé à l'aide de l'échange de clés Diffie Hellman

Maintenant, vous et l'écureuil secret avez la même couleur secrète partagée. Vous avez maintenant réussi à partager un secret sécurisé avec un parfait inconnu. Cela est étonnamment précis quant au fonctionnement de la cryptographie à clé publique. Un autre nom commun pour cette séquence d'événements est le Échange de clés Diffie-Hellman. L'échange de clés se compose des parties suivantes:

  • La clé privée is your private color from the examples.
  • The public key is the combined color that you shared.

The private key is something you always keep private, while the public key can be shared with anyone. These concepts map directly to the real world of Python HTTPS applications. Now that the server and the client have a shared secret, you can use your old pal symmetric encryption to encrypt all further messages!

When you’re communicating over a secure website, like this one, your browser and the server set up a secure communication using these same principles:

  1. Your browser requests information from the server.
  2. Your browser and the server exchange public keys.
  3. Your browser and the server generate a shared private key.
  4. Your browser and the server encrypt and decrypt messages using this shared key through symmetric encryption.

Luckily for you, you don’t need to implement any of these details. There are lots of built-in and third-party libraries that can help you keep your client and server communications secure.

What Is HTTPS Like in the Real World?

Given all this information about encryption, let’s zoom out a bit and talk about how Python HTTPS applications actually work in the real world. Encryption is only half of the story. When visiting a secure website, there are two major components needed:

  1. Chiffrement converts plaintext to ciphertext and back.
  2. Authentication verifies that a person or thing is who they say they are.

You’ve heard extensively about how encryption works, but what about authentication? To understand authentication in the real world, you’ll need to know about Public Key Infrastructure. PKI introduces another important concept into the security ecosystem, called certificates.

Certificates are like passports for the Internet. Like most things in the computer world, they are just chunks of data in a file. Generally speaking, certificates include the following information:

  • Issued To: identifies who owns the certificate
  • Issued By: identifies who issued the certificate
  • Validity Period: identifies the time frame for which the certificate is valid

Just like passports, certificates are only really useful if they’re generated and recognized by some authority. It’s impractical for your browser to know about every single certificate of every site you visit on the Internet. Instead, PKI relies on a concept known as Certificate Authorities (CA).

Certificate Authorities are responsible for issuing certificates. They are considered a trusted third party (TTP) in PKI. Essentially, these entities act as valid authorities for a certificate. Suppose you’d like to visit another country, and you have a passport with all your information on it. How do the immigration officers in the foreign country know that your passport contains valid information?

If you were to fill out all the information yourself and sign it, then each immigration officer in each country you want to visit would need to know you personally and be able to attest that the information there was indeed correct.

Another way to handle this is to send all your information into a Trusted Third Party (TTP). The TTP would do a thorough investigation of the information you provided, verify your claims, and then sign your passport. This turns out to be much more practical because the immigration officers only need to know the trusted third parties.

The TTP scenario is how certificates are handled in practice. The process goes something like this:

  1. Create a Certificate Signing Request (CSR): This is like filling out the information for your visa.
  2. Send the CSR to a Trusted Third Party (TTP): This is like sending your information into a visa application office.
  3. Verify your information: Somehow, the TTP needs to verify the information you provided. As an example, see how Amazon validates ownership.
  4. Generate a Public Key: The TTP signs your CSR. This is equivalent to the TTP signing your visa.
  5. Issue the verified Public Key: This is equivalent to you receiving your visa in the mail.

Note that the CSR is tied cryptographically to your private key. As such, all three pieces of information—public key, private key, and certificate authority—are related in one way or another. This creates what is known as a chain of trust, so you now have a valid certificate that can be used to verify your identity.

Most often, this is only the responsibility of website owners. A website owner will follow all these steps. At the end of this process, their certificate says the following:

From time UNE to time B je suis X selon Oui

This sentence is all that a certificate really tells you. The variables can be filled in as follows:

  • UNE is the valid start date and time.
  • B is the valid end date and time.
  • X is the name of the server.
  • Oui is the name of the Certificate Authority.

Fundamentally, this is all a certificate describes. In other words, having a certificate doesn’t necessarily mean that you are who you say you are, just that you got Oui à agree that you are who you say you are. This is where the “trusted” part of trusted third parties come in.

TTPs need to be shared between clients and servers in order for everyone to be happy about the HTTPS handshake. Your browser comes with lots of Certificate Authorities automatically installed. To see them, take the following steps:

  • Chrome: Aller à Settings > Advanced > Privacy and security > Manage certificates > Authorities.
  • Firefox: Aller à Settings > Preferences > Privacy & Security > View Certificates > Authorities.

This covers the infrastructure required to create Python HTTPS applications in the real world. In the next section, you’ll apply these concepts to your own code. You’ll walk through the most common examples and become your own Certificate Authority for the Secret Squirrels!

What Does a Python HTTPS Application Look Like?

Now that you have an understanding of the basic parts required for a making a Python HTTPS application, it’s time to tie all the pieces together one-by-one to your application from before. This will ensure that your communication between server and client is secure.

It’s possible to set up the entire PKI infrastructure on your own machine, and this is exactly what you’ll be doing in this section. It’s not as hard as it sounds, so don’t worry! Becoming a real Certificate Authority is significantly harder than taking the steps below, but what you’ll read is, more or less, all you’d need to run your own CA.

Becoming a Certificate Authority

A Certificate Authority is nothing more than a very important public and private key pair. To become a CA, you just need to generate a public and private key pair.

Your initial public and private key pair will be a self-signed certificate. You’re generating the initial secret, so if you’re actually going to become a CA, then it’s incredibly important that this private key is safe. If someone gets access to the CA’s public and private key pair, then they can generate a completely valid certificate, and there’s nothing you can do to detect the problem except to stop trusting your CA.

With that warning out of the way, you can generate the certificate in no time. For starters, you’ll need to generate a private key. Paste the following into a file called pki_helpers.py:

    1 # pki_helpers.py
    2 de cryptography.hazmat.backends import default_backend
    3 de cryptography.hazmat.primitives import serialization
    4 de cryptography.hazmat.primitives.asymmetric import rsa
    5 
    6 def generate_private_key(filename: str, passphrase: str):
    sept     private_key = rsa.generate_private_key(
    8         public_exponent=65537, key_size=2048, backend=default_backend()
    9     )
dix 
11     utf8_pass = passphrase.encode("utf-8")
12     algorithm = serialization.BestAvailableEncryption(utf8_pass)
13 
14     avec ouvert(filename, "wb") comme keyfile:
15         keyfile.écrire(
16             private_key.private_bytes(
17                 encoding=serialization.Encoding.PEM,
18                 format=serialization.PrivateFormat.TraditionalOpenSSL,
19                 encryption_algorithm=algorithm,
20             )
21         )
22 
23     revenir private_key

generate_private_key() generates a private key using RSA. Here’s a breakdown of the code:

  • Lines 2 to 4 import the libraries required for the function to work.
  • Lines 7 to 9 use RSA to generate a private key. The magic numbers 65537 et 2048 are just two possible values. You can read more about why or just trust that these numbers are useful.
  • Lines 11 to 12 set up the encryption algorithm to be used on your private key.
  • Lines 14 to 21 write your private key to disk at the specified filename. This file is encrypted using the password provided.

The next step in becoming your own CA is to generate a self-signed public key. You can bypass the certificate signing request (CSR) and immediately build a public key. Paste the following into pki_helpers.py:

    1 # pki_helpers.py
    2 de datetime import datetime, timedelta
    3 de cryptography import x509
    4 de cryptography.x509.oid import NameOID
    5 de cryptography.hazmat.primitives import hashes
    6 
    sept def generate_public_key(private_key, filename, **kwargs):
    8     subject = x509.Nom(
    9         [[[[
dix             x509.NameAttribute(NameOID.COUNTRY_NAME, kwargs[[[["country"]),
11             x509.NameAttribute(
12                 NameOID.STATE_OR_PROVINCE_NAME, kwargs[[[["state"]
13             ),
14             x509.NameAttribute(NameOID.LOCALITY_NAME, kwargs[[[["locality"]),
15             x509.NameAttribute(NameOID.ORGANIZATION_NAME, kwargs[[[["org"]),
16             x509.NameAttribute(NameOID.COMMON_NAME, kwargs[[[["hostname"]),
17         ]
18     )
19 
20     # Because this is self signed, the issuer is always the subject
21     issuer = subject
22 
23     # This certificate is valid from now until 30 days
24     valid_from = datetime.utcnow()
25     valid_to = valid_from + timedelta(days=30)
26 
27     # Used to build the certificate
28     builder = (
29         x509.CertificateBuilder()
30         .subject_name(subject)
31         .issuer_name(issuer)
32         .public_key(private_key.public_key())
33         .serial_number(x509.random_serial_number())
34         .not_valid_before(valid_from)
35         .not_valid_after(valid_to)
36     )
37 
38     # Sign the certificate with the private key
39     public_key = builder.sign(
40         private_key, hashes.SHA256(), default_backend()
41     )
42 
43     avec ouvert(filename, "wb") comme certfile:
44         certfile.écrire(public_key.public_bytes(serialization.Encoding.PEM))
45 
46     revenir public_key

Here you have a new function generate_public_key() that will generate a self-signed public key. Here’s how this code works:

  • Lines 2 to 5 are imports required for the function to work.
  • Lines 8 to 18 build up information about the subject of the certificate.
  • Line 21 uses the same issuer and subject since this is a self-signed certificate.
  • Lines 24 to 25 indicate the time range during which this public key is valid. In this case, it’s 30 days.
  • Lines 28 to 36 add all required information to a public key builder object, which then needs to be signed.
  • Lines 38 to 41 sign the public key with the private key.
  • Lines 43 to 44 write the public key out to filename.

Using these two functions, you can generate your private and public key pair quite quickly in Python:

>>>

>>> de pki_helpers import generate_private_key, generate_public_key
>>> private_key = generate_private_key("ca-private-key.pem", "secret_password")
>>> private_key

>>> generate_public_key(
...   private_key,
...   filename="ca-public-key.pem",
...   pays="US",
...   Etat="Maryland",
...   locality="Baltimore",
...   org="My CA Company",
...   nom d'hôte="my-ca.com",
... )
<Certificate(subject=, ...)>

After importing your helper functions from pki_helpers, you first generate your private key and save it to the file ca-private-key.pem. You then pass that private key into generate_public_key() to generate your public key. In your directory you should now have two files:

$ ls ca*
ca-private-key.pem ca-public-key.pem

Toutes nos félicitations! You now have the ability to be a Certificate Authority.

Trusting Your Server

The first step to your server becoming trusted is for you to generate a Certificate Signing Request (CSR). In the real world, the CSR would be sent to an actual Certificate Authority like Verisign or Let’s Encrypt. In this example, you’ll use the CA you just created.

Paste the code for generating a CSR into the pki_helpers.py file from above:

    1 # pki_helpers.py
    2 def generate_csr(private_key, filename, **kwargs):
    3     subject = x509.Nom(
    4         [[[[
    5             x509.NameAttribute(NameOID.COUNTRY_NAME, kwargs[[[["country"]),
    6             x509.NameAttribute(
    sept                 NameOID.STATE_OR_PROVINCE_NAME, kwargs[[[["state"]
    8             ),
    9             x509.NameAttribute(NameOID.LOCALITY_NAME, kwargs[[[["locality"]),
dix             x509.NameAttribute(NameOID.ORGANIZATION_NAME, kwargs[[[["org"]),
11             x509.NameAttribute(NameOID.COMMON_NAME, kwargs[[[["hostname"]),
12         ]
13     )
14 
15     # Generate any alternative dns names
16     alt_names = []
17     pour Nom dans kwargs.get("alt_names", []):
18         alt_names.append(x509.DNSName(Nom))
19     san = x509.SubjectAlternativeName(alt_names)
20 
21     builder = (
22         x509.CertificateSigningRequestBuilder()
23         .subject_name(subject)
24         .add_extension(san, critical=False)
25     )
26 
27     csr = builder.sign(private_key, hashes.SHA256(), default_backend())
28 
29     avec ouvert(filename, "wb") comme csrfile:
30         csrfile.écrire(csr.public_bytes(serialization.Encoding.PEM))
31 
32     revenir csr

For the most part this code is identical to how you generated your original public key. The main differences are outlined below:

  • Lines 16 to 19 set up alternate DNS names, which will be valid for your certificate.
  • Lines 21 to 25 generate a different builder object, but the same fundamental principle applies as before. You’re building all the required attributes for your CSR.
  • Line 27 signs your CSR with a private key.
  • Lines 29 to 30 write your CSR to disk in PEM format.

You’ll notice that, in order to create a CSR, you’ll need a private key first. Luckily, you can use the same generate_private_key() from when you created your CA’s private key. Using the above function and the previous methods defined, you can do the following:

>>>

>>> de pki_helpers import generate_csr, generate_private_key
>>> server_private_key = generate_private_key(
...   "server-private-key.pem", "serverpassword"
... )
>>> server_private_key

>>> generate_csr(
...   server_private_key,
...   filename="server-csr.pem",
...   pays="US",
...   Etat="Maryland",
...   locality="Baltimore",
...   org="My Company",
...   alt_names=[[[["localhost"],
...   nom d'hôte="my-site.com",
... )

After you run these steps in a console, you should end up with two new files:

  1. server-private-key.pem: your server’s private key
  2. server-csr.pem: your server’s CSR

You can view your new CSR and private key from the console:

$ ls server*.pem
server-csr.pem  server-private-key.pem

With these two documents in hand, you can now begin the process of signing your keys. Typically, lots of verification would happen in this step. In the real world, the CA would make sure that you owned my-site.com and ask you to prove it in various ways.

Since you are the CA in this case, you can forego that headache create your very own verified public key. To do that, you’ll add another function to your pki_helpers.py file:

# pki_helpers.py
def sign_csr(csr, ca_public_key, ca_private_key, new_filename):
    valid_from = datetime.utcnow()
    valid_until = valid_from + timedelta(days=30)

    builder = (
        x509.CertificateBuilder()
        .subject_name(csr.subject)
        .issuer_name(ca_public_key.subject)
        .public_key(csr.public_key())
        .serial_number(x509.random_serial_number())
        .not_valid_before(valid_from)
        .not_valid_after(valid_until)
    )

    pour extension dans csr.extensions:
        builder = builder.add_extension(extension.value, extension.critical)

    public_key = builder.sign(
        private_key=ca_private_key,
        algorithm=hashes.SHA256(),
        backend=default_backend(),
    )

    avec ouvert(new_filename, "wb") comme keyfile:
        keyfile.écrire(public_key.public_bytes(serialization.Encoding.PEM))

This code looks very similar to generate_public_key() du generate_ca.py fichier. In fact, they’re nearly identical. The major differences are as follows:

  • Lines 8 to 9 base the subject name on the CSR, while the issuer is based on the Certificate Authority.
  • Line 10 gets the public key from the CSR this time.
  • Lines 16 to 17 copy any extensions that were set on the CSR.
  • Line 20 signs the public key with the CA’s private key.

The next step is to fire up the Python console and use sign_csr(). You’ll need to load your CSR and your CA’s private and public key. Begin by loading your CSR:

>>>

>>> de cryptography import x509
>>> de cryptography.hazmat.backends import default_backend
>>> csr_file = ouvert("server-csr.pem", "rb")
>>> csr = x509.load_pem_x509_csr(csr_file.read(), default_backend())
>>> csr

In this section of code, you’re opening up your server-csr.pem file and using x509.load_pem_x509_csr() to create your csr object. Next up, you’ll need to load your CA’s public key:

>>>

>>> ca_public_key_file = ouvert("ca-public-key.pem", "rb")
>>> ca_public_key = x509.load_pem_x509_certificate(
...   ca_public_key_file.read(), default_backend()
... )
>>> ca_public_key
<Certificate(subject=, ...)>

Once again, you’ve created a ca_public_key object which can be used by sign_csr(). le x509 module had the handy load_pem_x509_certificate() to help. The final step is to load your CA’s private key:

>>>

>>> de getpass import getpass
>>> de cryptography.hazmat.primitives import serialization
>>> ca_private_key_file = ouvert("ca-private-key.pem", "rb")
>>> ca_private_key = serialization.load_pem_private_key(
...   ca_private_key_file.read(),
...   getpass().encode("utf-8"),
...   default_backend(),
... )
Mot de passe:
>>> private_key

This code will load up your private key. Recall from earlier that your private key was encrypted using the password you specified. With these three components, you can now sign your CSR and generate a verified public key:

>>>

>>> de pki_helpers import sign_csr
>>> sign_csr(csr, ca_public_key, ca_private_key, "server-public-key.pem")

After running this, you should have three server key files in your directory:

$ ls server*.pem
server-csr.pem  server-private-key.pem  server-public-key.pem

Whew! That was quite a lot of work. The good news is that now that you have your private and public key pair, you don’t have to change any server code to start using it.

Using your original server.py file, run the following command to start your brand new Python HTTPS application:

$ uwsgi 
    --master 
    --https localhost:5683,
            logan-site.com-public-key.pem,
            logan-site.com-private-key.pem 
    --mount /=server:app

Toutes nos félicitations! You now have a Python HTTPS-enabled server running with your very own private-public key pair, which was signed by your very own Certificate Authority!

Now, all that’s left to do is query your server. First, you’ll need to make some changes to the client.py code:

# client.py
import os
import requests

def get_secret_message():
    réponse = requests.get("https://localhost:5683")
    impression(F"The secret message is response.text")

si __name__ == "__main__":
    get_secret_message()

The only change from the previous code is from http à https. If you try to run this code, then you’ll be met with an error:

$ python client.py
...
requests.exceptions.SSLError: 
                HTTPSConnectionPool(host='localhost', port=5683): 
                Max retries exceeded with url: / (Caused by 
                SSLError(SSLCertVerificationError(1, 
                "[SSL: CERTIFICATE_VERIFY_FAILED] 
                certificate verify failed: unable to get local issuer 
                certificate (_ssl.c:1076)')))

That’s quite the nasty error message! The important part here is the message certificate verify failed: unable to get local issuer. These words should be more familiar to you now. Essentially, it’s saying the following:

localhost:5683 gave me a certificate. I checked the issuer of the certificate it gave me, and according to all the Certificate Authorities I know about, that issuer is not one of them.

If you attempt to navigate to your website with your browser, then you’ll get a similar message:

Chrome certificate warning

If you want to avoid this message, then you have to tell requests about your Certificate Authority! All you need to do is point requests at the ca-public-key.pem file that you generated earlier:

# client.py
def get_secret_message():
    réponse = requests.get("http://localhost:5683", verify="ca-public-key.pem")
    impression(F"The secret message is response.text")

After doing that, you should be able to run the following successfully:

$ python client.py
The secret message is fluffy tail

Agréable! You’ve made a fully-functioning Python HTTPS server and queried it successfully. You and the Secret Squirrels now have messages that you can trade back and forth happily and securely!

Conclusion

In this tutorial, you’ve learned some of the core underpinnings of secure communications on the Internet today. Now that you understand these building blocks, you’ll become a better and more secure developer.

Throughout this tutorial, you’ve gained an understanding of several topics:

  • Cryptography
  • HTTPS and TLS
  • Public Key Infrastructure
  • Certificates

If this information has you interested, then you’re in luck! You’ve barely scratched the surface of all the nuances involved in every layer. The security world is constantly evolving, and new techniques and vulnerabilities are always being discovered. If you still have questions, then feel free to reach out in the comments section below or on Twitter.