Quels sont ses composants (en gros) ?
C’est quoi une variable Python ?
personnage.py
C’est quoi un objet Python ?
Nous voulons sauvegarder un arbre 🌳
Séparation des responsabilités
Utilisation d’une bibliothèque dédiée
pip install psycopg2-binary
connection
: permet d’établir la connexion avec la base
Pas super intéressant à faire, le code est donné
db_connection.py
import os
import dotenv
import psycopg2
from psycopg2.extras import RealDictCursor
from utils.singleton import Singleton
class DBConnection(metaclass=Singleton):
"""
Classe de connexion à la base de données
Elle permet de n'ouvrir qu'une seule et unique connexion
"""
def __init__(self):
"""Ouverture de la connexion"""
dotenv.load_dotenv()
self.__connection = psycopg2.connect(
host=os.environ["POSTGRES_HOST"],
port=os.environ["POSTGRES_PORT"],
database=os.environ["POSTGRES_DATABASE"],
user=os.environ["POSTGRES_USER"],
password=os.environ["POSTGRES_PASSWORD"],
options=f"-c search_path={os.environ['POSTGRES_SCHEMA']}",
cursor_factory=RealDictCursor,
)
@property
def connection(self):
return self.__connection
cursor
: encapsule la requête
cursor.execute("<une requête SQL>")
: permet de faire une requête
cursor.fetchone()/fetchall()/fetchmany()
: Récupération des résultats
def dao_function(self, arg1, arg2, ...):
# Récupération de la connexion à la base
with DBConnection().connection as connection:
# Création d'un curseur pour faire une requête
with connection.cursor() as cursor:
# On envoie au serveur la requête SQL
cursor.execute(
"<une_requete_sql_à_trous>",
remplisage_des_trous)
# On récupère le résultat de la requête
res = cursor.fetchone() # ou fetchall()/fetchmany()
# Si la requête renvoie quelque chose
if res:
something = "<res mis en forme>"
return something
def create(self, livre) -> Livre:
"""Pour créer un livre en base"""
with DBConnection().connection as conn:
with conn.cursor() as cursor:
cursor.execute(
"INSERT INTO livre (isbm, titre, auteur) "
" VALUES (%(isbm)s, %(titre)s, %(auteur)s) "
" RETURNING id_livre; ",
{"isbm": livre.isbm,
"titre": livre.titre,
"auteur": livre.auteur},
)
livre.id = cursor.fetchone()["id_livre"]
return livre
def find_all(self) -> list[Livre]:
"""Pour récupérer tous les livres en base"""
with DBConnection().connection as conn:
with conn.cursor() as cursor:
cursor.execute(
"SELECT id_livre, "
" isbm, "
" titre, "
" auteur "
" FROM livre ; "
)
livre_bdd = cursor.fetchall()
liste_livres = []
if livre_bdd:
for livre in livre_bdd:
liste_livres.append(
Livre(
id=livre["id_livre"],
isbm=livre["isbm"],
titre=livre["titre"],
auteur=livre["auteur"],
)
)
return liste_livres
def find_by_isbm(self, isbm) -> Livre:
"""Pour récupérer un livre depuis son isbm"""
with DBConnection().connection as conn:
with conn.cursor() as cursor:
cursor.execute(
"SELECT * "
" FROM livre "
" WHERE isbm = %(isbm)s ",
{"isbm": isbm}
livre_bdd = cursor.fetchone()
livre = None
if livre_bdd:
livre = Livre(
id=livre_bdd["id_livre"],
isbm=livre_bdd["isbm"],
titre=livre_bdd["titre"],
auteur=livre_bdd["auteur"],
)
return livre
Seules les personnes autorisées doivent avoir accès aux informations qui leur sont destinées (notions de droits ou permissions).
Tout accès indésirable doit être empêché.
Mécanismes associés :
Les utilisateurs doivent prouver leur identité en répondant à un “challenge”.
Mécanismes associés :
Les données doivent être celles que l’on attend, et ne doivent pas être altérées de façons fortuites, illicites ou malveillantes.
Mécanismes associés :
L’accès aux ressources du système d’information doit être permanent et sans faille durant les plages d’utilisation prévues.
Mécanismes associés :
Garantit que les accès et tentatives d’accès aux éléments considérés sont tracés et que ces traces sont conservées et exploitables.
Mécanisme associé :
Aucun utilisateur ne doit pouvoir contester les opérations qu’il a réalisées dans le cadre de ses actions autorisées et aucun tiers ne doit pouvoir s’attribuer les actions d’un autre utilisateur.
Mécanismes associés :
De vos utilisateurs
Source : https://xkcd.com/
Consiste à saisir du SQL pour exécuter une autre requête que celle prévue.
Problèmes :
Requête d’authentification
Vous saisissez
Vous saisissez
' OR 1=1; --
Vous saisissez
'; DROP TABLE user CASCADE; --
La bibliothèque que vous utiliserez ne fait que de l’échappement de caractères spéciaux 😨
Consiste à injecter du code provoquant des actions sur le navigateur. Cela peut permettre :
Tip
Les bibliothèques web le font souvent pour vous !
Authentification sans persister les mots de passe !!!!
Au lieu de hacher et stocker le mdp vous stockez et hachez le mdp ET un élément lié à l’utilisateur de manière déterministe (le sel).
Maintenant même si 2 personnes ont le même mdp, elles auront des hash différents.
Comment résoudre ce problème ?
Quel problème ??