ORM_Quote
Prépare une valeur (chaîne, Date, DateHeure, Heure) en vue de son insertion dans une requête SQL : encadrement par les quotes, échappement des caractères spéciaux, gestion des valeurs NULL, formatage adapté au provider (MySQL · MariaDB · PostgreSQL). Protection contre l'injection SQL intégrée.
📋 Description
ORM_Quote est une procédure surchargée qui prépare une valeur quel que soit son type pour insertion sûre dans une requête SQL. Elle existe en quatre variantes selon le type d'entrée — chaîne, Date, DateHeure, Heure — toutes retournant une chaîne directement injectable dans le texte d'une requête.
L'appel à ORM_Quote est la pratique recommandée chaque fois qu'une valeur est concaténée dans une requête SQL en dehors des méthodes ORM standard (qui appliquent le quoting automatiquement). C'est notamment indispensable pour les valeurs venant de saisies utilisateur, de fichiers externes, ou d'API tierces.
1. Construire une clause WHERE manuellement avec des valeurs venues de l'utilisateur ou d'un calcul. Le quoting protège contre l'injection SQL et garantit le formatage correct.
2. Insérer une date / datetime / heure dans une requête. Le formatage est adapté au provider cible (MySQL · MariaDB · PostgreSQL) sans avoir à connaître les spécificités de chaque moteur.
3. Gérer correctement les valeurs NULL. Si la valeur est vide et que la colonne accepte NULL, la procédure retourne le mot-clé SQL NULL (sans quotes) au lieu d'une chaîne vide quotée.
Le formatage produit par ORM_Quote est compatible avec MySQL, MariaDB et PostgreSQL. Le provider courant est détecté automatiquement par le framework. Le code applicatif reste identique quel que soit le moteur cible.
🔑 Signatures
La procédure existe en quatre variantes selon le type de la valeur à quoter. La résolution est automatique via la surcharge WLangage : il suffit de passer la valeur, le framework choisit la signature qui correspond.
Variante 1 — Chaîne
LOCAL sChaine est une chaîne,
LOCAL nTaille est un entier = 0,
LOCAL bNullable est un booléen = Faux,
LOCAL bModeStrict est un booléen = Vrai
) : chaîne
| Paramètre | Type | Défaut | Rôle |
|---|---|---|---|
sChaine | chaîne | — | Valeur à quoter pour insertion SQL. |
nTaille | entier | 0 | Taille maximale de la chaîne après quoting. 0 = pas de limite. Utile pour respecter les contraintes de longueur d'une colonne SQL. |
bNullable | booléen | Faux | Voir §04. |
bModeStrict | booléen | Vrai | Active la détection de patterns d'injection SQL sur la chaîne — voir §03. |
Variante 2 — Date
LOCAL dDate est une Date,
LOCAL bNullable est un booléen = Vrai,
LOCAL bModeStrict est un booléen = Vrai
) : chaîne
| Paramètre | Type | Défaut | Rôle |
|---|---|---|---|
dDate | Date | — | Date à quoter pour insertion SQL. |
bNullable | booléen | Vrai | Voir §04. |
bModeStrict | booléen | Vrai | Active la détection de dates aberrantes (sentinelles, plage déraisonnable) — voir §04. |
Variante 3 — DateHeure
LOCAL dhDate est une DateHeure,
LOCAL bNullable est un booléen = Vrai,
LOCAL bModeStrict est un booléen = Vrai
) : chaîne
| Paramètre | Type | Défaut | Rôle |
|---|---|---|---|
dhDate | DateHeure | — | Date et heure à quoter pour insertion SQL. |
bNullable | booléen | Vrai | Voir §04. |
bModeStrict | booléen | Vrai | Active la détection de dates aberrantes sur la partie date — voir §04. |
Variante 4 — Heure
LOCAL hHeure est une Heure,
LOCAL bNullable est un booléen = Vrai
) : chaîne
| Paramètre | Type | Défaut | Rôle |
|---|---|---|---|
hHeure | Heure | — | Heure à quoter pour insertion SQL. |
bNullable | booléen | Vrai | Voir §04. |
🛡️ Protection contre l'injection SQL
L'injection SQL est l'une des vulnérabilités applicatives les plus classiques. Elle survient quand une valeur fournie par l'utilisateur (ou venant d'une source externe non maîtrisée) est concaténée directement dans le texte d'une requête SQL sans contrôle. Un attaquant peut alors faire exécuter au moteur SQL des instructions qui n'étaient pas prévues par le développeur.
Le risque illustré
Voici le grand classique : une recherche par nom où le code concatène brutalement la saisie utilisateur dans la requête.
Variantes plus graves : un attaquant peut combiner cette technique avec UNION SELECT pour exfiltrer des données d'autres tables, ou avec ; pour enchaîner des instructions destructrices (DROP TABLE, DELETE...). Toutes ces attaques exploitent le même défaut initial : la valeur utilisateur n'a pas été quotée.
La protection apportée par ORM_Quote
En faisant transiter la valeur par ORM_Quote avec bModeStrict = Vrai (valeur par défaut), on bénéficie de plusieurs protections cumulées :
| Protection | Effet |
|---|---|
| Encadrement par les quotes SQL | La valeur est entourée de '...' de manière correcte, l'appelant n'a pas à les écrire lui-même. |
| Échappement des caractères spéciaux | Les apostrophes, antislashs et autres caractères dangereux dans la valeur sont échappés selon les règles du provider, empêchant la « casse » de la chaîne. |
| Détection de patterns d'injection | En mode strict, la procédure détecte les signatures connues d'attaques SQL (voir catégories ci-dessous) et neutralise la requête sans exécuter l'attaque. |
| Détection de séquences suspectes | Séquences de quotes multiples consécutives, octets nuls, caractères de contrôle anormaux dans la valeur sont également détectés et neutralisés. |
| Compatibilité provider | Les règles d'échappement diffèrent légèrement entre MySQL/MariaDB et PostgreSQL — la procédure applique celles du provider courant. |
Catégories de patterns détectés
Le mode strict couvre les principales familles de techniques d'injection SQL connues :
| Catégorie | Type d'attaque visé |
|---|---|
| Commandes destructrices | Tentatives d'exécution d'instructions de modification de schéma ou de données massives. |
| Bypass d'authentification | Manipulation des conditions logiques pour contourner les contrôles d'accès. |
| Injections UNION | Extraction de données depuis d'autres tables via concaténation de jeux de résultats. |
| Stacked queries | Enchaînement de plusieurs instructions dans une même requête. |
| Commentaires SQL | Terminaison prématurée d'une requête par insertion de marqueurs de commentaire. |
| Time-based blind | Attaques par mesure de temps de réponse (fonctions de pause). |
| Boolean-based blind | Attaques par observation de la véracité de conditions logiques. |
| Information disclosure | Tentatives d'accès aux métadonnées système. |
| File access | Tentatives de lecture ou écriture de fichiers via le moteur SQL. |
Que se passe-t-il quand un pattern est détecté ?
Le retour de ORM_Quote est alors la chaîne Null (sans quotes). Concaténée dans la requête finale, cette valeur est interprétée par le moteur SQL comme le mot-clé NULL. La requête s'exécute donc sans erreur SQL, mais la comparaison à NULL retourne toujours UNKNOWN en SQL — qui se comporte comme faux dans une clause WHERE. Conséquence : la requête retourne 0 ligne.
L'attaquant ne reçoit aucun message d'erreur exploitable — la requête semble simplement n'avoir rien trouvé, comme si les critères de recherche n'avaient produit aucun résultat. Ce comportement évite de divulguer l'existence du mécanisme de détection à un attaquant qui pourrait alors essayer de le contourner. La trace de la tentative est en revanche enregistrée côté serveur pour que l'exploitation puisse en être informée.
L'exemple précédent, sécurisé
Toute valeur qui n'est pas une constante littérale écrite directement dans le code source doit transiter par ORM_Quote avant d'être concaténée dans une requête SQL. Cela inclut, sans s'y limiter : saisies utilisateur (champs IHM, paramètres GET/POST), données venant d'un fichier externe (CSV, JSON, XML), réponses d'API tierces, contenu d'un presse-papiers, données venant d'une autre base que celle du framework.
Les méthodes standard de l'ORM (mth_ChargerSelonClauseWhere, mth_Enregistrer, mth_EffacerSelonID, etc.) appliquent ORM_Quote automatiquement sur les valeurs des membres mappés — le quoting manuel n'est nécessaire que dans le code applicatif qui construit du SQL en dehors de ces méthodes.
🧭 Comportement et NULL
Paramètre bNullable
Contrôle le traitement des valeurs vides : si Vrai, elles sont converties en NULL SQL (mot-clé sans quotes). Si Faux, la valeur est traitée littéralement comme une chaîne vide quotée.
Les valeurs par défaut diffèrent selon la variante :
| Variante | Défaut bNullable | Justification |
|---|---|---|
| Chaîne | Faux | Une chaîne vide est souvent une valeur métier valide (« nom optionnel non renseigné » par exemple). |
| Date | Vrai | Une date vide est généralement une absence de valeur, à représenter par NULL en base. |
| DateHeure | Vrai | Idem — une DateHeure vide signale typiquement une donnée non encore saisie. |
| Heure | Vrai | Idem. |
Paramètre bModeStrict
Active les contrôles de validation. Le comportement diffère selon la variante :
| Variante | Effet de bModeStrict = Vrai |
|---|---|
| Chaîne | Détection des patterns d'injection SQL connus (voir §03). |
| Date / DateHeure | Détection des dates aberrantes (années sentinelles, plage déraisonnable). |
| Heure | Non applicable (paramètre absent de la signature). |
Conserver la valeur par défaut (Vrai) sauf besoin spécifique justifié.
Validation des dates en mode strict
Pour les variantes Date et DateHeure, le mode strict détecte les dates dont la valeur est plausible techniquement mais aberrante dans un contexte applicatif normal :
| Catégorie | Description |
|---|---|
| Années sentinelles | Valeurs souvent utilisées pour signaler « infini » ou tester les contrôles de saisie. |
| Plage trop ancienne | Dates antérieures à un seuil considéré comme déraisonnable pour la plupart des applications métier. |
| Plage trop future | Dates trop éloignées dans le futur pour avoir une signification métier réaliste. |
Quand une date est jugée aberrante, le retour est "Null" (chaîne) — comportement identique à celui décrit pour la chaîne en cas de pattern détecté.
Pour les variantes Date, DateHeure et Heure : une valeur structurellement invalide (par exemple 32 février, ou une Heure mal formée) provoque un retour "NULL" quel que soit l'état de bNullable. Le paramètre bNullable ne s'applique qu'aux dates / heures valides mais vides.
📤 Valeur de retour
Les quatre variantes retournent une chaîne directement injectable dans le texte d'une requête SQL.
| Cas | Forme du retour |
|---|---|
| Chaîne non vide | 'valeur échappée' |
Chaîne vide, bNullable = Faux | '' (chaîne vide quotée) |
Chaîne vide, bNullable = Vrai | NULL (mot-clé SQL) |
| Chaîne avec pattern d'injection détecté en mode strict | Null (chaîne sans quotes — voir §03) |
Date renseignée | 'AAAA-MM-JJ' |
DateHeure renseignée | 'AAAA-MM-JJ HH:MM:SS' |
Heure renseignée | 'HH:MM:SS' |
Date / DateHeure / Heure vide ou invalide | NULL (mot-clé SQL — voir §04) |
Date / DateHeure aberrante en mode strict | Null (chaîne sans quotes) |
Les quotes SQL sont déjà incluses dans la chaîne retournée. Lors de la concaténation dans une requête, ne pas en rajouter manuellement : "WHERE NOM = " + ORM_Quote(sNom) et non "WHERE NOM = '" + ORM_Quote(sNom) + "'". Cette règle vaut aussi pour NULL : la chaîne "NULL" est retournée sans quotes, prête à être concaténée telle quelle.
💡 Exemples
Mode 1 — clause WHERE avec valeur chaîne
Mode 2 — clause WHERE avec date
Mode 3 — gestion d'une valeur potentiellement vide (NULL)
Mode 4 — protection injection SQL avec saisie utilisateur
Mode 5 — combinaison avec une clause IN générée par mth_ValeursDistinctes