2010-08-01 13 views
15

Esta cadena:pitón añade "E" de la cadena

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

siempre se sale ampliado para:

CREATE USER E'someuser' PASSWORD E'somepassword' 

¿Puede alguien decirme por qué?

Edit: La cadena expandida anterior es la cadena que mi base de datos me devuelve en el mensaje de error. Estoy usando psycopg2 para acceder a mi base de datos postgres. El código real se ve así:

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

¿Puede dar código completo con el usuario y PW declaraciones? –

+4

Esto debe ser causado por el comportamiento de la función '__str__' del tipo de' user' y 'pw'. – Philipp

+1

¿Es eso una * coma * después de la cadena literal? Si es así, la expresión es simplemente una tupla anidada, y nunca se expande nada. Por favor muestra el código real. – Philipp

Respuesta

8

No sólo la E, pero las cotizaciones parecen provenir de cualquier tipo de usuario y PW Have. % s simplemente hace lo que hace str(), que puede recurrir a repr(), los cuales tienen los métodos correspondientes __str__ y __repr__. Además, ese no es el código que genera el resultado (suponía que hay un%, pero ahora solo veo una coma). Por favor expanda su pregunta con el código, los tipos y los valores reales.

Adición: Teniendo en cuenta que se parece a SQL, me atrevo a adivinar que está viendo escape string constants, probablemente generado correctamente por su módulo de interfaz de base de datos o biblioteca.

+0

Tienes razón. Estoy usando Psycopg2 y esta es la cadena que mi base de datos me devuelve como un error. Voy a poner el código actual en la pregunta ahora. – Kai

+0

Parece que el problema es que% s se usa para campos de datos, y un nombre de usuario en [CREAR USUARIO] (http://www.postgresql.org/docs/8.2/interactive/sql-createrole.html) parece ser un identificador, por lo que un literal de cadena no funcionará allí. Psycopg2 no parece tener ninguna función de validación o cotización para tales identificadores. –

+1

[Discusión psicológica relevante.] (Http://lists.initd.org/pipermail/psycopg/2009-March/thread.html#6344) –

10

Como edición de la OP revela que está usando PostgreSQL, the docs para ello son relevantes, y dicen:

PostgreSQL también acepta "escape" constantes de cadena, que son una extensión al estándar SQL. Una constante de cadena de escape se especifica mediante escribiendo la letra E (mayúscula o minúscula ) justo antes de la primera cita de apertura , p. E'foo '.

En otras palabras, psycopg está generando correctamente las constantes de cadena de escape para sus cadenas (de modo que, como los documentos también dicen:

Dentro de una cadena de escape, una barra invertida carácter() comienza una C -como secuencia de escape barra invertida, en la que la combinación de barra invertida y siguiente carácter (s) representa un valor de byte especial .

(que a su vez son también las convenciones de escape de los literales de cadena de Python no brutos).

El error del OP claramente no tiene nada que ver con eso, y, además de la excelente idea de estudiar los documentos excelentes de PostgreSQL, no debería preocuparse por ese formulario E'...' en este caso ;-).

+1

Acabo de leer eso por mi cuenta Entonces, la cadena es correcta, pero ¿por qué mi servidor postgres me la devuelve con un error de sintaxis en el E? – Kai

+0

@Kai, ¿tal vez está usando una versión obsoleta de PgSQL? O tal vez los comentarios de @ Yann sobre la otra respuesta son correctos y necesitas un identificador, _not_ una cadena citada en absoluto, en 'CREATE USER' (en cuyo caso tendrás que insertarlo por manipulación de cadena, antes de' execute', para evitar el escape, asegúrese de ** verificar ** muy bien contra los ataques de inyecciones SQL, por supuesto !!! -). –

+0

Parece que el comentario de Yann es correcto. No me gusta esto, pero por el momento no necesito manejar los valores generados por el usuario en estas declaraciones. Así que solo usaré las manipulaciones de cadenas de python estándar. Aún así, no me gusta;) – Kai

2

Antes de intentar algo como:

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

Por favor lea: http://www.initd.org/psycopg/docs/usage.html

Básicamente el problema es que si se acepta la entrada del usuario (supongo que con el fin de que alguien está entrando en el usuario & PW) es probable que estés abierto a la inyección de SQL.

Como psycopg2 afirma:

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

Como ha sido identificado, no parece Postgres (o psycopg2) para proporcionar una buena respuesta a los identificadores escapan. En mi opinión, la mejor manera de resolver esto es proporcionar un método de filtro de 'lista blanca'.

ie: Identifique qué caracteres están permitidos en un 'usuario' y un 'pw'. (tal vez A-Za-z0-9_). Tenga cuidado de no incluir caracteres de escape ('o;, etc.) o si lo hace, de que escape a estos valores.

+0

Postgres tiene la función 'quote_ident()' para citar identificadores https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-QUOTE-LITERAL -EXAMPLE – raphael

16

Para pasar identificadores a PostgreSQL a través del uso psycopg AsIs del módulo

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' 

extensions que funciona también para el paso de condiciones de cláusulas como 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

Lástima que anule el punto de parametrización de consultas: '>>> cursor.mogrify ('CREATE USER% s PASSWORD% s', (AsIs ('someuser'), AsIs ('somepassword; drop table users ; '))) ' '' CREATE USER someuser PASSWORD somepassword; drop table users; '' Debe ser validado con algo como: ''table_table'.replace ('_', '') .isalnum()'. (Cuidado, no probado.) –

+0

@ MichałPawłowski: Sí, 'AsIs' no debe usarse para los datos ingresados ​​por el usuario. Y usar cualquier solución no probada, como la suya, para hacerlo, es una receta para el desastre. –