2010-08-01 59 views
15

这个字符串:蟒蛇加 “E” 串

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

总是被扩展为:

CREATE USER E'someuser' PASSWORD E'somepassword' 

谁能告诉我为什么?

编辑: 上面展开的字符串是我的数据库让我回到错误消息中的字符串。我使用psycopg2来访问我的postgres数据库。真实代码如下所示:

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

可以充分代码与用户和PW声明? – 2010-08-01 13:43:58

+4

这必须由'user'和'pw'类型的__str__'函数的行为引起。 – Philipp 2010-08-01 13:45:11

+1

是字符串文字之后的*逗号*吗?如果是这样,表达式只是一个嵌套元组,并且什么都不会扩展。请显示真实的代码。 – Philipp 2010-08-01 14:21:44

回答

8

不仅E,而且引号似乎来自任何类型的用户和pw都有。 %s只是做str()做的事情,可能会回到repr(),两者都有相应的方法__str____repr__。此外,这不是产生你的结果的代码(我假设有一个%,但现在只看到一个逗号)。请用实际的代码,类型和值扩展你的问题。

附录:考虑到它看起来像SQL,我猜测你会看到escape string constants,可能是由数据库接口模块或库正确生成的。

+0

你说得对。我正在使用Psycopg2,这是我的数据库给我的错误字符串。我现在要把实际的代码放在问题中。 – Kai 2010-08-01 15:12:41

+0

它会出现问题,%s用于数据字段,并且[CREATE USER](http://www.postgresql.org/docs/8.2/interactive/sql-createrole.html)中的用户名似乎是一个标识符 - 所以一个字符串文字不会在那里工作。 Psycopg2似乎没有任何这种标识符的验证或引用功能。 – 2010-08-01 15:56:36

+1

[相关psycopg讨论。](http://lists.initd.org/pipermail/psycopg/2009-March/thread.html#6344) – 2010-08-01 16:02:27

10

由于OP的编辑透露他使用PostgreSQL,the docs它是相关的,他们说:

的PostgreSQL还接受“逃离” 字符串常量,这是一个 扩展到SQL标准。 转义字符串常量由 指定,例如在开头的单个 报价(例如,英文字母)之前写入字母E(大写或小写 )。 E'foo”。

换句话说,psycopg正确生成的字符串转义字符串常量(因此,作为文档也说:

在转义字符串,反斜杠 字符()开始一个C样 反斜杠转义序列,其中 反斜线和 下面的字符(或多个)的组合代表一个特殊 字节值。

(它正好也是非原始Python字符串文字的转义约定)。

OP的错误显然与此无关,除了研究PostgreSQL的优秀文档的出色想法之外,在这种情况下,他不应该担心这种形式的E'...' ;-)。

+1

我只是我自己阅读。所以这个字符串是正确的,但为什么我的postgres服务器在E语法错误的时候给它回来了? – Kai 2010-08-01 16:18:10

+0

@凯,也许你使用的是PgSQL的过时版本?或者@Yann对另一个答案的评论是正确的,你需要一个标识符,在'CREATE USER'中不需要引用字符串(在这种情况下,你必须通过字符串操作在'execute'之前插入它,避免逃跑 - 一定要**非常彻底地对付SQL注入攻击!!! - )。 – 2010-08-01 16:28:11

+0

看起来Yann的评论是正确的。不要这样,但目前我不需要在这些语句中处理用户生成的值。所以我会使用标准的Python字符串操作。不过,我不喜欢它;) – Kai 2010-08-01 16:41:40

2

之前尝试喜欢的东西:

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

请确保您阅读:http://www.initd.org/psycopg/docs/usage.html

基本上问题是,如果你是接受用户输入(我假设,从而有人在用户进入& PW )你可能会开放SQL注入。

由于PsyCopg2指出:

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

由于已经确定,Postgres的(或Psycopg2)似乎并没有提供一个很好的答案逃逸标识符。在我看来,解决这个问题的最好方法是提供一个“白名单”过滤方法。

ie:确定'user'和'pw'中允许使用哪些字符。 (也许是A-ZA-Z0-9_)。小心你不要包含转义字符('或;等),或者如果你这样做,你逃避了这些值。

+0

Postgres具有用于引用标识符的'quote_ident()'函数https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-QUOTE-LITERAL - 示例 – raphael 2016-08-18 21:26:51

16

要通过标识符从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' 

这一工程也传递条件子句像order by通过psycopg使用AsIs到PostgreSQL:

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

太糟糕了,它打败了查询参数化的要点: '>>> cursor.mogrify('CREATE USER%s PASSWORD%s',(AsIs('someuser'),AsIs('somepassword; drop table users ;')))' ''CREATE USER someuser PASSWORD somepassword; drop table users;'' 它应该用类似于'input_table'.replace('_','').isalnum()'进行验证。 (当心,未经测试。) – 2015-12-28 16:34:24

+0

@MichałPawłowski:是的,'AsIs'不应该用于用户输入的数据。和你一样,使用任何未经过彻底测试的解决方案都是如此,是一种灾难。 – 2015-12-28 17:30:37