如何在PostgreSQL中匹配模式时转义字符串

时间:2012-04-14 12:01:47

标签: postgresql go sql-like

我想找到文本列以用户给定字符串开头的行,例如SELECT * FROM users WHERE name LIKE 'rob%'但“抢劫”是未经验证的用户输入。如果用户写入包含特殊模式字符(如“rob_”)的字符串,则它将匹配“robert42”和“rob_the_man”。我需要确保字符串字面匹配,我该怎么做?我是否需要在应用程序级别处理转义或者它是一种更美观的方式?

我正在使用PostgreSQL 9.1和go-pgsql进行Go。

4 个答案:

答案 0 :(得分:6)

必须引用_和%字符在LIKE语句中按字面匹配,没有办法绕过它。选择是关于客户端或服务器端(通常使用SQL replace(),见下文)。另外,为了在一般情况下100%正确,有一些事情需要考虑。

默认情况下,在_或%之前使用的引号字符是反斜杠(\),但可以使用LIKE子句后面的ESCAPE子句更改它。 在任何情况下,引号字符必须在模式中重复两次,以便字面上匹配为一个字符。

示例:... WHERE field like 'john^%node1^^node2.uucp@%' ESCAPE '^'将匹配 john%node1 ^ node2.uccp @ ,后跟任何内容。

默认选择反斜杠时出现问题:当standard_conforming_strings为OFF时,它已经用于其他目的(默认情况下PG 9.1默认开启,但之前的版本仍在广泛使用,这是指向考虑)。

此外,如果在用户输入注入方案中LIKE通配符的引用是在客户端完成的,那么除了之外,还会在用户输入上显示正常的字符串引用。

瞥一眼go-pgsql示例告诉它它使用$ N样式的占位符来表示变量...所以这里是尝试以某种方式通用的方式编写它:它与standard_conforming_strings一起使用ON或OFF,使用服务器 - 替换[%_],替代引号字符,引用引号字符,并避免sql注入:

   db.Query("SELECT * from USERS where name like replace(replace(replace($1,'^','^^'),'%','^%'),'_','^_') ||'%' ESCAPE '^'",
     variable_user_input);

答案 1 :(得分:3)

要转义下划线以及like表达式中模式中使用的百分比,请使用转义字符:

SELECT * FROM users WHERE name LIKE replace(replace(user_input, '_', '\\_'), '%', '\\%');

答案 2 :(得分:1)

据我所知,LIKE运算符中唯一的特殊字符是百分比和下划线,这些可以使用反斜杠手动转义。它不是很漂亮但它有效。

SELECT * FROM users WHERE name LIKE
regexp_replace('rob', '(%|_)', '\\\1', 'g') || '%';

我觉得奇怪的是PostgreSQL没有附带这样的功能。谁希望他们的用户编写自己的模式?

答案 3 :(得分:0)

最好的答案是你根本不应该将用户输入内插到你的sql中。即使逃避sql仍然很危险。

以下使用go的db / sql库说明了一种更安全的方法。用你postgresql库的等价物替换Prepare和Exec调用。

// The question mark tells the database server that we will provide
// the LIKE parameter later in the Exec call
sql := "SELECT * FROM users where name LIKE ?"
// no need to escape since this won't be interpolated into the sql string.
value := "%" + user_input
// prepare the completely safe sql string.
stmt, err := db.Prepare(sql)
// Now execute that sql with the values for every occurence of the question mark.
result, err := stmt.Exec(value)

这样做的好处是可以安全地使用用户输入,而不必担心它会将sql注入到您运行的语句中。您还可以将准备好的sql重用于多个查询,这在某些情况下可以更有效。