Geekflare est soutenu par son public. Nous pouvons percevoir des commissions d'affiliation sur les liens d'achat présents sur ce site.
En Développement Dernière mise à jour : 16 septembre 2023
Partager sur :
Invicti Web Application Security Scanner - la seule solution qui offre une vérification automatique des vulnérabilités avec Proof-Based Scanning™.

Nous allons apprendre à sécuriser une API REST à l'aide de jetons web JSON afin d'empêcher les utilisateurs et les applications tierces d'en abuser.

Nous allons créer un service de base de données en utilisant SQLite et permettre aux utilisateurs d'y accéder via une API REST en utilisant des méthodes HTTP telles que POST et PUT.

En outre, nous apprendrons pourquoi les jetons web JSON sont un moyen approprié de protéger l'API de repos au lieu de l'authentification digest et de l'authentification de base. Avant de poursuivre, il convient de comprendre les termes JSON web tokens, REST API et Flask framework.

Jetons Web JSON

Jeton web JSON, également connu sous le nom de JWTJSON est le moyen sûr de transférer des jetons aléatoires entre deux parties ou entités. JSON se compose généralement des trois parties suivantes.

  • Charge utile
  • En-tête
  • Signature

JSON utilise deux types de structures lors du transfert de données ou d'informations entre deux parties.

  • En série
  • Désérialisé

La forme sérialisée est utilisée lors du transfert de données vers le réseau par le biais de chaque requête et réponse, tandis que la forme désérialisée est utilisée lors de la lecture et de l'écriture de données sur le jeton web.

Dans la forme sérialisée, il y a trois composants.

  • En-tête
  • Charge utile
  • Signature

L'en-tête définit les informations cryptographiques relatives aux jetons. Par exemple :

  • Est-il signé ou non signé ? JWT?
  • Définir les techniques algorithmiques

Le formulaire désérialisé, contrairement au formulaire sérialisé, contient deux composants.

  • Charge utile
  • En-tête

API REST

L'API (interface de programmation d'applications) permet la communication entre deux applications pour récupérer ou soumettre des données. Il existe deux types d'API : l'API web et l'API système.

Dans cet article, nous ne nous intéresserons qu'à l'API web. Il existe deux types d'API web.

  • Demande - Réponse API : Rest, GraphQL, appel de procédure à distance (RPC)
  • API pilotée par les événements : WebHooks, Web Sockets, HTTP Streaming

L'API REST appartient à la catégorie demande-réponse. Elle utilise des méthodes HTTP telles que GET, POST et PUT pour effectuer les opérations de l'API.

Un exemple classique est celui d'un utilisateur qui envoie une méthode GET au service web pour demander ou récupérer une ressource spécifique ou une collection de ressources. Le serveur renvoie alors la ressource spécifique ou la collection de ressources à l'utilisateur qui l'a demandée.

Cadre de travail Flask

Flask est un framework basé sur Python. Il s'agit d'un micro-cadre utilisé par les développeurs python pour construire des API de repos. Il est appelé micro-cadre parce qu'il permet aux développeurs, par exemple, d'ajouter une authentification personnalisée et tout autre système de backend basé sur les préférences.

Commençons par la mise en œuvre. Mon système est configuré comme suit.

  • Ubuntu comme système d'exploitation
  • Python 2.7+
  • Facteur

Configurer un environnement virtuel à l'aide de virtualenv

Nous devons mettre en place un environnement virtuel pour nous assurer que certains paquets n'entreront pas en conflit avec les paquets du système. Utilisons l'environnement virtualenv pour créer un nouvel environnement virtuel.

En supposant que vous ayez le pip disponible sur votre système, exécutez la commande suivante via pip à installer.

pip install virtualenv

Si vous n'avez pas pip sur votre machine, suivez les instructions suivantes la documentation pour installer pip sur votre système.

Ensuite, nous allons créer un répertoire pour stocker notre environnement virtuel. Utilisez le répertoire mkdir La commande ci-dessous permet de créer un répertoire

mkdir flaskproject

Changez pour le flaskproject à l'aide de la commande suivante

cd flaskproject

A l'intérieur de la flaskproject utiliser le fichier virtualenv pour créer un environnement virtuel comme indiqué ci-dessous :

virtualenv flaskapi

Après avoir utilisé le virtualenv pour créer l'environnement virtuel, exécutez l'outil cd pour passer à l'option flaskapi comme environnement virtuel et l'activer à l'aide de la commande ci-dessous.

source bin/activate

Exécuter toutes les tâches liées à ce projet dans l'environnement virtuel.

Installer des paquets à l'aide de pip

Il est maintenant temps d'installer des paquets tels que le framework flask et PyJWT que nous utiliserons pour construire l'API de repos et d'autres paquets nécessaires pour notre projet d'API.

Créer un requirements.txt avec les paquets suivants.

Flask  
datetime 
uuid
Flask-SQLAlchemy
PyJWT

Installez-les avec pip.

pip install -r requirements.txt

Mise en place d'une base de données

Installons SQLite.

apt-get install sqlite3

Créez une base de données nommée la bibliothèque. Dans cette base de données, nous créerons deux tables, à savoir les tables Users et Authors table.

Le tableau Utilisateurs contiendra les utilisateurs enregistrés. Seuls les utilisateurs enregistrés peuvent avoir accès à la table Auteurs.

Le tableau des auteurs stocke les informations relatives aux auteurs ou des détails tels que le nom de l'auteur, le pays de naissance, etc. soumis par les utilisateurs enregistrés.

Créez la base de données à l'aide de la commande suivante :

sqlite3 library.db

Vous pouvez vérifier si vous avez créé avec succès la base de données en utilisant la commande ci-dessous :

.databases

Ouvrez un nouveau terminal et exécutez la commande suivante dans l'environnement virtuel que nous avons créé précédemment.

touch app.py

Collez le code suivant dans le fichier nommé app.py

from flask import Flask, request, jsonify, make_response
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
import uuid
import jwt
import datetime
from functools import wraps

La première ligne du code ci-dessus importe des paquets tels que request et jsonify. Nous utiliserons request pour garder la trace des données au niveau de la demande lors d'une demande et les utiliser jsonify pour produire des réponses dans un JSON format.

À la ligne suivante, nous avons importé SQLAlchemy à partir de flask_sqlalchemy afin d'intégrer les fonctionnalités de SQLAlchemy dans flask.

De werkzeug.security, nous avons importé generate_password_hash pour générer des hachages de mots de passe pour les utilisateurs et check_password_hash pour vérifier le mot de passe de l'utilisateur lors de la comparaison des mots de passe soumis par les utilisateurs avec les mots de passe des utilisateurs stockés dans la base de données.

Enfin, nous avons importé uuid également connus sous le nom d'identificateurs uniques universels pour générer des numéros d'identification aléatoires pour les utilisateurs.

Pourtant, à l'intérieur de la app.py mettez en œuvre les paramètres de configuration de l'API de la bibliothèque en utilisant le code ci-dessous dans le fichier app.py.

Placez le code suivant sous la déclaration d'importation.

app = Flask(__name__)

app.config['SECRET_KEY']='Th1s1ss3cr3t'
app.config['SQLALCHEMY_DATABASE_URI']='sqlite://///home/michael/geekdemos/geekapp/library.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

db = SQLAlchemy(app)

Créez maintenant deux modèles pour les tables Users et Authors comme indiqué ci-dessous. Copiez et collez le code dans le fichier app.py.

Placez le code ci-dessous juste en dessous de ce paramètre de la base de données  db = SQLAlchemy(app)

class Users(db.Model):
     id = db.Column(db.Integer, primary_key=True)
     public_id = db.Column(db.Integer)
     name = db.Column(db.String(50))
     password = db.Column(db.String(50))
     admin = db.Column(db.Boolean)
class Authors(db.Model):
     id = db.Column(db.Integer, primary_key=True)
     name = db.Column(db.String(50), unique=True, nullable=False))
     book = db.Column(db.String(20), unique=True, nullable=False))
     country = db.Column(db.String(50), nullable=False))
     booker_prize = db.Column(db.Boolean)

Générer des tables d'utilisateurs et d'auteurs

Sur le terminal, tapez le code suivant à l'intérieur de l'environnement virtuel pour générer ou créer des tables pour les tables Utilisateurs et Auteurs comme indiqué ci-dessous

from app import db
db.create_all()

Ensuite, ouvrez le app.py dans l'environnement virtuel et créer une autre fonction.

Cette fonction génère des jetons afin de permettre aux seuls utilisateurs enregistrés d'accéder à la table des auteurs et d'y effectuer une série d'opérations API.

Placez ce code sous le modèle de base de données pour le tableau des auteurs

def token_required(f):
   @wraps(f)
   def decorator(*args, **kwargs):

      token = None

      if 'x-access-tokens' in request.headers:
         token = request.headers['x-access-tokens']

      if not token:
         return jsonify({'message': 'a valid token is missing'})

      try:
         data = jwt.decode(token, app.config[SECRET_KEY])
         current_user = Users.query.filter_by(public_id=data['public_id']).first()
      except:
         return jsonify({'message': 'token is invalid'})

        return f(current_user, *args, **kwargs)
   return decorator

Créer des routes pour la table des utilisateurs

Créons maintenant une route permettant aux utilisateurs de s'inscrire à l'API auteurs via un nom d'utilisateur et un mot de passe, comme indiqué ci-dessous.

Ouvrez à nouveau le app.py dans l'environnement virtuel et collez le code suivant sous la fonction token_required(f)

@app.route('/register', methods=['GET', 'POST'])
def signup_user():  
 data = request.get_json()  

 hashed_password = generate_password_hash(data['password'], method='sha256')
 
 new_user = Users(public_id=str(uuid.uuid4()), name=data['name'], password=hashed_password, admin=False) 
 db.session.add(new_user)  
 db.session.commit()    

 return jsonify({'message': 'registered successfully'})

Dans l'environnement virtuel, créez une autre route dans le fichier app.py pour permettre aux utilisateurs enregistrés de se connecter.

Lorsqu'un utilisateur se connecte, un jeton aléatoire est généré pour lui permettre d'accéder à l'API de la bibliothèque.

Collez le code ci-dessous sous la route précédente que nous avons créée.

@app.route('/login', methods=['GET', 'POST'])  
def login_user(): 
 
  auth = request.authorization   

  if not auth or not auth.username or not auth.password:  
     return make_response('could not verify', 401, {'WWW.Authentication': 'Basic realm: "login required"'})    

  user = Users.query.filter_by(name=auth.username).first()   
     
  if check_password_hash(user.password, auth.password):  
     token = jwt.encode({'public_id': user.public_id, 'exp' : datetime.datetime.utcnow() + datetime.timedelta(minutes=30)}, app.config['SECRET_KEY'])  
     return jsonify({'token' : token.decode('UTF-8')}) 

  return make_response('could not verify',  401, {'WWW.Authentication': 'Basic realm: "login required"'})

Toujours dans l'environnement virtuel, créez une autre route dans le fichier app.py pour obtenir ou récupérer tous les utilisateurs enregistrés.

Ce code vérifie la présence de tous les utilisateurs enregistrés dans la table Utilisateurs et renvoie le résultat final au format JSON.

Collez le code ci-dessous sous la route de connexion

@app.route('/users', methods=['GET'])
def get_all_users():  
   
   users = Users.query.all() 

   result = []   

   for user in users:   
       user_data = {}   
       user_data['public_id'] = user.public_id  
       user_data['name'] = user.name 
       user_data['password'] = user.password
       user_data['admin'] = user.admin 
       
       result.append(user_data)   

   return jsonify({'users': result})

Créer des routes pour la table des auteurs 

Créons des itinéraires pour la table Auteurs afin de permettre aux utilisateurs de récupérer tous les auteurs de la base de données, ainsi que de supprimer des auteurs.

Seuls les utilisateurs disposant de jetons valides peuvent effectuer ces opérations API.

Dans le fichier app.py, créez une route permettant aux utilisateurs enregistrés de créer de nouveaux auteurs.

Collez ce code sous la route qui permet à un utilisateur de retrouver tous les utilisateurs enregistrés.

@app.route('/author', methods=['POST', 'GET'])
@token_required
def create_author(current_user):
   
   data = request.get_json() 

   new_authors = Authors(name=data['name'], country=data['country'], book=data['book'], booker_prize=True, user_id=current_user.id)  
   db.session.add(new_authors)   
   db.session.commit()   

   return jsonify({'message' : 'new author created'})

Ensuite, créez une autre route pour permettre à un utilisateur enregistré avec un jeton valide de récupérer tous les auteurs dans la table Authors, comme indiqué ci-dessous.

Collez ce code sous la route qui permet à un utilisateur de créer un nouvel auteur.

@app.route('/authors', methods=['POST', 'GET'])
@token_required
def get_authors(current_user):

    authors = Authors.query.filter_by(user_id=current_user.id).all()

    output = []
    for author in authors:

           author_data = {}
           author_data['name'] = author.name
           author_data['book'] = author.book
           author_data['country'] = author.country
           author_data['booker_prize'] = author.booker_prize
           output.append(author_data)

     return jsonify({'list_of_authors' : output})

Enfin, toujours à l'intérieur du app.py créez une route pour supprimer un auteur spécifié, comme indiqué ci-dessous.

Collez ce code sous la route qui permet à un utilisateur de récupérer une liste d'auteurs.

@app.route('/authors/<author_id>', methods=['DELETE'])
@token_required
def delete_author(current_user, author_id):  
    author = Author.query.filter_by(id=author_id, user_id=current_user.id).first()   
    if not author:   
       return jsonify({'message': 'author does not exist'})   


    db.session.delete(author)  
    db.session.commit()   

    return jsonify({'message': 'Author deleted'})


if  __name__ == '__main__':  
     app.run(debug=True)

Ensuite, enregistrez et fermez le fichier app.py dans l'environnement virtuel.

Tester l'API de la bibliothèque avec Postman

Dans cette section, nous utiliserons l'outil postman pour envoyer une requête aux services de base de données. Si vous n'avez pas d'outil postman sur votre machine, vous pouvez le télécharger et l'installer. ici.

Outre le facteur, nous pouvons utiliser d'autres outils tels que Boucle pour envoyer des demandes au serveur.

Ouvrez un nouveau terminal et tapez ce qui suit :

postman

La commande  postman votre navigateur web affichera la page ci-dessous :

postman_signup

Vous pouvez décider de vous inscrire et de créer un compte gratuit, mais nous allons passer outre et obtenir un accès direct à l'application pour tester l'API de la bibliothèque, comme indiqué ci-dessous :

Tester l'api de la bibliothèque

 

Dans cette section, nous allons permettre à un utilisateur de s'inscrire à l'API de la bibliothèque en fournissant un nom d'utilisateur et un mot de passe unique dans un format JSON à l'aide de la méthode POST en suivant les étapes ci-dessous :

  • Cliquez sur l'onglet "Corps".
  • Sélectionnez ensuite le bouton raw et choisissez le format JSON
  • saisir un nom d'utilisateur et un mot de passe pour s'enregistrer, comme indiqué dans la capture d'écran
  • A côté du bouton d'envoi, insérez l'URL suivante http://127.0.0.1/register
  • Enfin, changez la méthode en POST et appuyez sur le bouton d'envoi.

un utilisateur s'inscrit à une API

Il affichera la sortie suivante, comme indiqué ci-dessous :

Nous avons maintenant enregistré avec succès un utilisateur. Permettons à l'utilisateur qui vient de s'inscrire de se connecter afin de générer un jeton aléatoire temporaire pour accéder à la table des auteurs en suivant les étapes suivantes :

  •  Cliquez sur l'onglet autorisation.
  • Dans la section type, sélectionnez l'authentification de base.
  • Remplissez ensuite le formulaire de nom d'utilisateur et de mot de passe avec le nom d'utilisateur et le mot de passe avec lesquels vous vous êtes enregistré précédemment.
  • Enfin, appuyez sur le bouton d'envoi pour vous connecter et générer un jeton aléatoire.

Une fois que l'utilisateur s'est connecté avec succès, un jeton aléatoire est généré pour l'utilisateur, comme le montre la capture d'écran.

Nous utiliserons le jeton aléatoire généré pour accéder à la table des auteurs.

Dans cette section, nous allons ajouter les informations d'un auteur à la table Authors via la méthode POST en suivant les étapes suivantes :

  • Cliquez sur l'onglet des en-têtes
  • Inclure les en-têtes HTTP suivants, illustrés dans la capture d'écran

  • Ensuite, cliquez sur l'onglet "corps" et entrez les détails du nouvel auteur
  • Appuyez ensuite sur le bouton d'envoi pour ajouter les coordonnées de l'auteur au tableau des auteurs.

Vous pouvez également récupérer les informations relatives aux auteurs dans la table Auteurs en procédant comme suit :

  • Assurez-vous que votre jeton généré se trouve dans la section des en-têtes. Si ce n'est pas le cas, vous devez le remplir avec votre jeton.
  • A côté du bouton d'envoi, entrez cette URL http://127.0.0.1/authors
  • Changez ensuite la méthode HTTP en GET et appuyez sur le bouton d'envoi pour récupérer les détails de l'auteur.

Enfin, vous pouvez supprimer le(s) auteur(s) dans le tableau des auteurs via la commande DELETE en suivant les étapes suivantes :

  • Assurez-vous que votre jeton se trouve toujours dans la section des en-têtes. Vous pouvez vérifier l'onglet des en-têtes pour vous assurer que les informations nécessaires sont en place.
  • A côté du bouton d'envoi, entrez cette URL http://127.0.0.1/sam
  • Appuyez ensuite sur le bouton d'envoi pour supprimer l'utilisateur que vous avez spécifié.

Vous pouvez trouver le code source complet sur Github.  Vous pouvez le cloner et le tester sur votre machine.

  • Michael Aboagye
    Auteur
Merci à nos sponsors
D'autres lectures intéressantes sur le développement
Alimentez votre entreprise
Quelques outils et services pour aider votre entreprise à se développer.
  • Invicti utilise le Proof-Based Scanning™ pour vérifier automatiquement les vulnérabilités identifiées et générer des résultats exploitables en quelques heures seulement.
    Essayez Invicti
  • Web scraping, proxy résidentiel, proxy manager, web unlocker, search engine crawler, et tout ce dont vous avez besoin pour collecter des données web.
    Essayez Brightdata
  • Monday.com est un système d'exploitation tout-en-un qui vous aide à gérer vos projets, vos tâches, votre travail, vos ventes, votre CRM, vos opérations, vos flux de travail et bien plus encore.
    Essayez le lundi
  • Intruder est un scanner de vulnérabilité en ligne qui détecte les faiblesses de votre infrastructure en matière de cybersécurité, afin d'éviter des violations de données coûteuses.
    Essayer l'intrus