IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

La "bonne" syntaxe d'insertion ?


Sujet :

Python

  1. #1
    Membre confirmé Avatar de memento80
    Homme Profil pro
    Boulot : ne rentre pas dans une case
    Inscrit en
    Novembre 2004
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Boulot : ne rentre pas dans une case
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2004
    Messages : 163
    Par défaut La "bonne" syntaxe d'insertion ?
    Bonsoir,

    J'ai une petite question toute bête qui vient de me prendre quelques looongues dizaines de minutes de recherche un peu partout et pour laquelle je n'ai pas trouvé de réponse franche ou qui fonctionne.

    Quelle est la meilleure syntaxe pour insérer dans une base de données mysql ?

    Pourquoi cette question bête ?
    Jusqu'à présent j'utilisais la syntaxe suivante :
    curs.execute("INSERT INTO table1(col1, col2, col3) VALUES({0}, '{1}', '{2}')".format(id, "CAT1", "Monsieur {0} ne veut pas aller travailler aujourd hui.".format(nomMonsieur)))

    mais dans mon programme, le résultat de la variable 'nomMonsieur' vient d'une base de données et je suis embêté depuis que je suis tombé dans le cas d'un nom avec un apostrophe.

    Depuis, j'ai un peu plus regardé en détail les différentes possibilités pour insérer mon 'nomMonsieur' avec son apostrophe mais je n'ai pas trouvé la méthode adéquat.
    De plus, j'ai pu lire à droite à gauche que ce genre de syntaxe pouvait créer des failles de sécurité permettant des injections sql...

    Brrrr... Ca fait peur.

    Du coup, je doute.... et je pose cette question.

    Merci d'avance pour vos réponses.

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Salut,

    Le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    curs.execute("INSERT INTO table1(col1, col2, col3) VALUES({0}, '{1}', '{2}')".format(id, "CAT1", "Monsieur {0} ne veut pas aller travailler aujourd hui.".format(nomMonsieur)))
    construit une chaîne de caractères qui sera expédiée au driver de la BDD.

    Cela pourrait "ouvrir" des portes à des "SQL injection attack" si la requête peut être "modifiée". Dans votre cas, cela ne modifiera qu'une valeur, çà ne devrait pas être bien grave.

    Le vrai défaut est que cette forme oblige à mettre en forme les paramètres (des objets Python) pour pouvoir construire la chaine de caractères (une représentation sous forme de str de ces objets): si nomMonsieur contient des "'", il y aura collision avec le format '{2}'.

    La solution est de passer par l'utilisation de requêtes auxquelles on passera des variables qui seront des tuples contenant les objets Python attendus.
    On pourra écrire:
    curs.execute(statement, (id, "CAT1", nomMonsieur))
    et laisser "execute" se débrouiller pour faire la conversion objet Python <=> type qui va bien côté BDD.

    Après la question est comment écrire "statement" pour que çà le fasse.
    La DB API Python autorise/documente plusieurs formats:
    • qmark: Question mark style, e.g. ...WHERE name=?
    • numeric: Numeric, positional style, e.g. ...WHERE name=:1
    • named: Named style, e.g. ...WHERE name=:name
    • format: ANSI C printf format codes, e.g. ...WHERE name=%s
    • pyformat: Python extended format codes, e.g. ...WHERE name=%(name)s


    statement pourrait donc s'écrire:
    - INSERT INTO table1(col1, col2, col3) VALUES(?, ?, ?)
    - INSERT INTO table1(col1, col2, col3) VALUES(%s, %s, %s)
    - INSERT INTO table1(col1, col2, col3) VALUES(:col1, :col2, :col3)
    - ...

    Mais le driver MySQL que vous utilisez pourra supporter tout ou partie de ces "formats" => lire la documentation et les exemples associés.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre confirmé Avatar de memento80
    Homme Profil pro
    Boulot : ne rentre pas dans une case
    Inscrit en
    Novembre 2004
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Boulot : ne rentre pas dans une case
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2004
    Messages : 163
    Par défaut
    Déjà merci wiztricks pour cette réponse claire et bien détaillée.

    Malheureusement, les différentes syntaxes n'ont pas l'air de fonctionner sur Mysql... ou alors je me débrouille comme un pied (ce qui est fortement plausible aussi).

    Si le risque est limité dans mon cas de figure avec les "SQL injection attack", alors j'en suis arrivé à trouver une autre solution pour pouvoir insérer mes apostrophes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    curs.execute("INSERT INTO table1(col1, col2, col3) VALUES({0}, '{1}', '{2}')".format(id, "CAT1", "Monsieur {0} ne veut pas aller travailler aujourd'hui.".format(nomMonsieur).replace('\'', '\'\'')))
    L'apostrophe est donc remplacé par deux apostrophes avant l'insertion en base de données pour échapper mon caractère.
    NB : j'ai même rajouté l'apostrophe à "aujourd'hui" du coup.

    Je trouve cette solution un peu "bof" mais je n'ai rien de mieux pour l'instant..

    Voila, s'il existe mieux, je prends.

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Salut,

    Malheureusement, les différentes syntaxes n'ont pas l'air de fonctionner sur Mysql... ou alors je me débrouille comme un pied (ce qui est fortement plausible aussi).
    Sans préciser pas le driver MySQL utilisé et ni montrer ce que vous faites pour obtenir une requêtes paramétrable, vous n'aidez pas beaucoup les lecteurs du forum à vous aider.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre confirmé Avatar de memento80
    Homme Profil pro
    Boulot : ne rentre pas dans une case
    Inscrit en
    Novembre 2004
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Boulot : ne rentre pas dans une case
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2004
    Messages : 163
    Par défaut
    Euh.. oui certes.
    Autant je me débrouille un peu en Python, autant en MySql, c'est un peu laborieux.. (autodidacte, on doit louper surement plein de choses)
    Du coup, je ne saisis pas très bien ce que tu entends par "driver MySql" ?..

    J'ai la version (mysql5.5.16).. mais le driver... ?

    Pour ce qui est de la requête paramétrable, j'ai effectivement adapté le code donné dans tes exemples et MySql me l'a rejeté avec un message du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?, ?, ?)' at line 1")
    J'ai écrasé l'exemple que j'avais (mmm.. c'est un peu délicat de le refaire car j'ai modifié plein d'autres choses depuis) mais si je le refais ça serait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    curs.execute("INSERT INTO table1(col1, col2, col3) VALUES(?, ?, ?)", (id, "CAT1", "Monsieur {0} ne veut pas aller travailler aujourd hui.".format(nomMonsieur)))
    Si nécessaire si ce n'est pas clair, je peux essayer de refaire un exemple/test "sur-mesure".

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Salut,

    Citation Envoyé par memento80 Voir le message
    Du coup, je ne saisis pas très bien ce que tu entends par "driver MySql" ?..

    J'ai la version (mysql5.5.16).. mais le driver... ?
    Python ne parle pas avec MySQL sans qu'on y ajoute un module/bibliothèque/librairie qui le permette. C'est ce que j'appelle le driver (sans doute improprement)


    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Membre confirmé Avatar de memento80
    Homme Profil pro
    Boulot : ne rentre pas dans une case
    Inscrit en
    Novembre 2004
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Boulot : ne rentre pas dans une case
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2004
    Messages : 163
    Par défaut
    Mmm.. Le module MySQLdb ?
    C'est la version 1.2.3 pour Python 3.2.

    Merci pour ton aide.

  8. #8
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Salut,
    Dans les exemples que j'ai pu trouver sur Google, ils ne montrent que le paramétrage "format", i.e.:
    "INSERT INTO table1(col1, col2, col3) VALUES(%s, %s, %s)"
    D'autres peuvent aussi être supportés mais je n'ai pas le temps de construire de quoi tester.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  9. #9
    Membre confirmé Avatar de memento80
    Homme Profil pro
    Boulot : ne rentre pas dans une case
    Inscrit en
    Novembre 2004
    Messages
    163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Boulot : ne rentre pas dans une case
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2004
    Messages : 163
    Par défaut
    Ouep.. Manque de temps aussi pour moi pour faire un exemple sur-mesure.

    Néanmoins, comme ça m'intrigue fortement de savoir pourquoi certaines syntaxes ne fonctionnent pas chez moi, dès que j'aurai un peu plus de temps, je ferai un test sur-mesure et reposterai.

    En attendant, le "problème" n'est pas trop bloquant.
    Merci pour ton aide quand même.

Discussions similaires

  1. [MySQL] transformer une simple quote en double pour un insert !!
    Par st0nky dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 11/01/2006, 16h38

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo