2010-08-01 4 views
15

Cette chaîne:python ajoute "E" à chaîne

"CREATE USER %s PASSWORD %s", (user, pw) 

obtient toujours étendu à:

CREATE USER E'someuser' PASSWORD E'somepassword' 

Quelqu'un peut-il me dire pourquoi?

Modifier: La chaîne développée ci-dessus est la chaîne que ma base de données me renvoie dans le message d'erreur. J'utilise psycopg2 pour accéder à ma base de données postgres. Le vrai code ressemble à ceci:

conn=psycopg2.connect(user=adminuser, password=adminpass, host=host) 
cur = conn.cursor() 

#user and pw are simple standard python strings the function gets as parameter 
cur.execute("CREATE USER %s PASSWORD %s", (user, pw)) 
conn.commit() 
+7

Pouvez-vous donner le code complet avec l'utilisateur et pw déclarations? –

+4

Cela doit être dû au comportement de la fonction '__str__' du type' user' et 'pw'. – Philipp

+1

Est-ce une * virgule * après la chaîne littérale? Si c'est le cas, l'expression est simplement un tuple imbriqué, et rien ne se développe jamais. S'il vous plaît montrer le vrai code. – Philipp

Répondre

8

Non seulement le E mais les citations semblent provenir de tout type d'utilisateur et de pw. % s fait simplement ce que str() fait, qui peut revenir à repr(), les deux ayant des méthodes correspondantes __str__ et __repr__. En outre, ce n'est pas le code qui génère votre résultat (je supposais qu'il y avait un%, mais maintenant voir seulement une virgule). Veuillez développer votre question avec le code, les types et les valeurs réels.

Addendum: Considérant qu'il ressemble à SQL, je risque de deviner que vous voyez escape string constants, probablement généré correctement par votre module d'interface de base de données ou bibliothèque.

+0

Vous avez raison. J'utilise Psycopg2 et c'est la chaîne que ma base de données me renvoie comme une erreur. Je vais mettre le code actuel dans la question maintenant. – Kai

+0

Il semblerait que le problème est que% s est utilisé pour les champs de données, et un nom d'utilisateur dans [CREATE USER] (http://www.postgresql.org/docs/8.2/interactive/sql-createrole.html) semble être un identifiant - une chaîne littérale ne fonctionnera donc pas ici. Psycopg2 ne semble pas avoir de fonctions de validation ou de création de guillemets pour ces identifiants. –

+1

[Discussion psycopg pertinente.] (Http://lists.initd.org/pipermail/psycopg/2009-March/thread.html#6344) –

10

En tant que modification de l'OP révèle qu'il utilise PostgreSQL, the docs pour sont pertinents, et ils disent:

PostgreSQL accepte aussi « échapper » constantes de chaîne, qui sont une extension à la norme SQL. Une constante de chaîne d'échappement est spécifiée par en écrivant la lettre E (case supérieure ou inférieure) juste avant la première citation , par ex. E'foo '.

En d'autres termes, psycopg est la génération correctement les constantes de chaîne d'échappement pour vos cordes (de sorte que, comme les docs disent aussi:

Au sein d'une chaîne d'échappement, une barre oblique inverse caractère() commence un C -comme séquence d'échappement barre oblique inverse, dans lequel la combinaison de barre oblique inverse et caractère suivant (s) représente une valeur d'octet spécial.

(qui, en l'occurrence, sont aussi les conventions d'échappement des littéraux de chaîne Python non-raw).

L'erreur de l'OP n'a clairement rien à voir avec cela, et, outre l'excellente idée d'étudier les excellents docs de PostgreSQL, il ne devrait pas s'inquiéter de cette forme E'...' dans ce cas ;-).

+1

Je viens de lis cela par moi-même. Donc la chaîne est correcte, mais pourquoi mon serveur postgres me la renvoie-t-elle avec une erreur de syntaxe à l'E? – Kai

+0

@Kai, peut-être que vous utilisez une version obsolète de PgSQL? Ou peut-être que les commentaires de @ Yann sur l'autre réponse sont justes et vous avez besoin d'un identificateur, pas du tout une chaîne entre guillemets, dans CREATE USER (dans ce cas, vous devrez l'insérer par manipulation de chaîne, avant le 'execute', pour éviter l'échappement - assurez-vous de ** vérifier ** très bien contre les attaques par injections SQL bien sûr !!! -). –

+0

On dirait que le commentaire de Yann est juste. Je n'aime pas ça mais pour l'instant je n'ai pas besoin de gérer les valeurs générées par l'utilisateur dans ces instructions. Donc, je vais juste utiliser les manipulations de chaîne de python standard. Pourtant, je ne l'aime pas;) – Kai

2

Avant d'essayer quelque chose comme:

statement = "CREATE USER %s PASSWORD %s" % (user, pw) 

S'il vous plaît vous assurer de lire: http://www.initd.org/psycopg/docs/usage.html

Fondamentalement, le problème est que si vous acceptez l'entrée d'utilisateur (je suppose donc que quelqu'un entre dans l'utilisateur & pw) vous vous exposez probablement à l'injection SQL.

Comme psycopg2 déclare:

Warning Never, never, NEVER use Python string concatenation (+) or string parameters interpolation (%) to pass variables to a SQL query string. Not even at gunpoint. 

Comme il a été identifié, Postgres (ou psycopg2) ne semble pas fournir une bonne réponse à s'échapper identifiants. À mon avis, la meilleure façon de résoudre cela est de fournir une méthode de filtrage «liste blanche».

Par exemple: Identifiez les caractères autorisés dans un 'utilisateur' et un 'pw'. (peut-être A-Za-z0-9_). Veillez à ne pas inclure de caractères d'échappement ('ou,, etc.) ou, si vous le faites, à éviter ces valeurs.

+0

Postgres a la fonction 'quote_ident()' pour les citations d'identifiants https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-QUOTE-LITERAL -EXAMPLE – raphael

16

Pour transmettre des identifiants à PostGreSQL par l'utilisation psycopg AsIs à partir du module extensions

from psycopg2.extensions import AsIs 
import psycopg2 
connection = psycopg2.connect(database='db', user='user') 
cur = connection.cursor() 
cur.mogrify(
    'CREATE USER %s PASSWORD %s', (AsIs('someuser'), AsIs('somepassword')) 
    ) 
'CREATE USER someuser PASSWORD somepassword' 

Cela fonctionne aussi pour les conditions passage aux clauses comme order by:

cur.mogrify(
    'select * from t order by %s', (AsIs('some_column, another column desc'),) 
    ) 
'select * from t order by some_column, another column desc' 
+0

Dommage qu'il vainc le point de paramétrage de la requête: '>>> cursor.mogrify ('CREATE USER% s MOT DE PASSE% s', (AsIs ('someuser'), AsIs ('somepassword; ; '))) ' '' CRÉER UN UTILISATEUR MOT DE PASSE un mot de passe; drop table users '' Il devrait être validé avec quelque chose comme: ''input_table'.replace (' _ ',' ') .isalnum()'. (Attention, non testé.) –

+0

@ MichałPawłowski: Oui, "AsIs" ne doit pas être utilisé pour les données saisies par l'utilisateur. Et l'utilisation de toute solution non testée de manière approfondie, comme le vôtre, le faire, est une recette pour le désastre. –