2010-08-01 88 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