在PostgreSQL中插入带单引号的文本


432

我有一张桌子test(id,name)

我需要插入值,如: user's log'my user'customer's

 insert into test values (1,'user's log');
 insert into test values (2,''my users'');
 insert into test values (3,'customer's');

如果我运行以上任何语句,都会收到错误消息。

如果有任何方法可以正确执行此操作,请分享。我不要任何准备好的陈述。

是否可以使用sql转义机制?


1
使用逃避客户端库提供的任何值。有关更多信息,您必须说出如何访问数据库。
理查德·赫克斯顿

@Richard Huxton数据库由Java访问。
MAHI 2012年

2
因此,请使用标准的jdbc占位符。或解释为什么这不是最佳选择。
理查德·赫克斯顿

@Richard Huxton我并不是说这不是最佳选择,我正在搜索它们是否在sql中存在任何转义方法。
MAHI 2012年

好吧,请参阅下面的@Claudix回复,但是显然,值文字将需要根据其类型进行不同的转义postgresql.org/docs/current/static/datatype.html
Richard Huxton 2012年

Answers:


763

字符串文字

'通过将单引号加倍-> ''来转义单引号是标准方法,当然可以:

'user's log'     -- incorrect syntax (unbalanced quote)
'user''s log'

在旧版本中,或者如果您仍然使用standard_conforming_strings = off或运行,或者通常情况下,如果在字符串前面加上E声明Posix转义字符串语法,则还可以使用反斜杠进行转义\

E'user\'s log'

反斜杠本身会被另一个反斜杠转义。但这通常不是可取的。
如果必须处理多个单引号或多个转义符,则可以避免在PostgreSQL中用美元引号引起来的字符串引用地狱:

'escape '' with '''''
$$escape ' with ''$$

为了进一步避免美元报价之间的混淆,请为每对报价添加唯一的令牌:

$token$escape ' with ''$token$

可以嵌套任何数量的级别:

$token2$Inner string: $token1$escape ' with ''$token1$ is nested$token2$

如果$字符在客户端软件中应具有特殊含义,请注意。您可能还必须转义它。标准PostgreSQL客户端(例如psql或pgAdmin)不是这种情况。

这对于编写plpgsql函数或临时SQL命令非常有用。但是,当可以进行用户输入时,它不能减轻使用准备好的语句或其他方法来防止在应用程序中进行SQL注入的需要。@Craig的答案还有更多。更多细节:

Postgres内部的值

在处理数据库内部的值时,有几个有用的函数可以正确地引用字符串:


1
还值得注意的是,某些PgJDBC版本在美元报价方面存在问题-特别是,它可能无法忽略以美元报价的字符串中的语句终止符(;)。
Craig Ringer 2014年

1
此相关答案包含有关JDBC问题的详细信息。
Erwin Brandstetter 2014年

1
并且,如果您要在程序语言等情况下在插入时避免从文本列中进行操作,则可以使用quote_literal(column_name)字符串函数。
alexglue 2014年

1
$ token $很棒。谢谢。
mythicalcoder

@ErwinBrandstetter,重新“可以嵌套任意数量的级别”:但是SELECT $outer$OUT$inner$INNER$inner$ER$outer$;证明第二级嵌套在这里不起作用。
filiprem

46

这真是个坏世界,因为您的问题暗示您可能在应用程序中存在大量的SQL注入漏洞。

您应该使用参数化语句。对于Java,请使用PreparedStatement占位符。您说您不想使用参数化的语句,但是您没有解释为什么,坦率地说,不使用它们必须是一个很好的理由,因为它们是解决您正在尝试的问题的最简单,最安全的方法解决。

请参阅防止Java中的SQL注入。不要成为Bobby的下一个受害者。

PgJDBC中没有用于字符串引用和转义的公共函数。部分原因是它可能使它看起来像一个好主意。

内置的报价功能quote_literalquote_identPostgreSQL中,但它们对于PL/PgSQL函数使用EXECUTE。这些天quote_literal主要是由废弃EXECUTE ... USING,这是参数化的版本,因为它是更安全更方便。您不能将它们用于此处说明的目的,因为它们是服务器端功能。


想象一下,如果您');DROP SCHEMA public;--从恶意用户那里获得了价值,将会发生什么。您将产生:

insert into test values (1,'');DROP SCHEMA public;--');

它分为两个语句和一个被忽略的注释:

insert into test values (1,'');
DROP SCHEMA public;
--');

糟糕,您的数据库就在那里。


我倾向于同意一个例外-“ where”子句(尽管他说“ insert”),其值列表是“ in”子句(或一堆“ or”)的一部分。我想您可以计算列表的大小,并使用“ in”子句将文本生成到准备好的语句中,但是在该用例中它变得很奇怪。
Roboprog 2014年

@Roboprog可以使用某些客户端驱动程序= ANY(?)和一个数组参数。
克雷格·林格2014年

12
我经常使用像这样的文字插入来引导数据以及DDL。让我们只尝试回答问题,而不是像“ýou'做错了”之类的回答
ThatDataGuy

1
@ThatDataGuy的评论很公平,但是OP在此问题中添加了一条评论,说database is accessed by java这确实可以直接解决该问题。让来到这里的人们意识到潜在的危险也非常重要,尤其是考虑到SQL注入是导致软件漏洞的第一大原因。一旦意识到了问题,人们就可以对何时无关紧要做出明智的决定,例如您的自举用例。
达沃斯

究竟。人们还会大量复制和粘贴代码。从停止每天在生产代码中看到SQL注入漏洞的那一天起,我将停止向人们发出警告。
克雷格·林格

26

根据PostgreSQL文档(4.1.2.1。字符串常量)

 To include a single-quote character within a string constant, write two 
 adjacent single quotes, e.g. 'Dianne''s horse'.

另请参见standard_conforming_strings参数,该参数控制是否使用反斜杠转义。


感谢您的答复,但我必须使用此函数手动转义每个字符,如果它们存在执行此操作的任何内置函数?
MAHI 2012年

3
@MAHI如果有这样的功能,它将在PgJDBC中,而不是在PostgreSQL中,因为必须在客户端进行转义。没有这样的文档化的公共职能,因为这是一个糟糕的主意。您应该使用参数化的语句,这样就无需执行任何可能不可靠的转义操作。
Craig Ringer 2012年

13

在postgresql中,如果您想在其中插入值,'则必须为此付出额外的努力'

 insert into test values (1,'user''s log');
 insert into test values (2,'''my users''');
 insert into test values (3,'customer''s');

如果您有带引号的字符串,则可以显示三重引号
winkbrace

up,因为它是一个简单的解决方案
ktaria


2

如果您需要在Pg中完成工作:

to_json(value)

https://www.postgresql.org/docs/9.3/static/functions-json.html#FUNCTIONS-JSON-TABLE


这个问题与JSON有什么关系?
Erwin Brandstetter

1
@ErwinBrandstetter,对不起,我可能要离开了..但是它转义了字符串中的引号
hatenine 17/12/19

1
完全是另一回事。您可以使用format()quote_literal()quote_nullable()转义引号。请参阅:stackoverflow.com/a/25143945/939860
Erwin Brandstetter

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.