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 2012

@Richard Huxtonデータベースはjavaによってアクセスされます。
MAHI 2012

2
したがって、標準のjdbcプレースホルダーを使用してください。または、それが最善の選択ではない理由を説明してください。
Richard Huxton 2012

@Richard Huxton私はそれが最良の選択ではないと言っていません。SQLにエスケープするメソッドが存在するかどうかを探しています。
MAHI 2012

さて、以下の@Claudixの返信を参照してください。ただし、値リテラルは、そのタイプに応じて異なるエスケープが必要になることは明らかですpostgresql.org/docs/current/static/datatype.html
Richard Huxton

回答:


763

文字列リテラル

'二重引用符で単一引用符をエスケープする-> ''は標準的な方法であり、もちろん機能します。

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

古いバージョンで、または引き続き実行するstandard_conforming_strings = off場合、または一般的に、Posixエスケープ文字列構文Eを宣言するために文字列を前に付ける場合は、バックスラッシュでエスケープすることもできます\

E'user\'s log'

バックスラッシュ自体は別のバックスラッシュでエスケープされます。しかし、それは一般的には好ましくありません。
多くの単一引用符またはエスケープの複数のレイヤーを処理する必要がある場合は、ドル引用符で囲まれた文字列でPostgreSQLの地獄を引用することを回避できます

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

ドル引用符間の混乱をさらに回避するには、各ペアに一意のトークンを追加します。

$token$escape ' with ''$token$

これは、任意の数のレベルをネストできます。

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

$キャラクターがクライアントソフトウェアで特別な意味を持つ必要がある場合は注意してください。さらにそれをエスケープする必要があるかもしれません。これは、psqlやpgAdminなどの標準のPostgreSQLクライアントには当てはまりません。

これは、plpgsql関数やアドホックSQLコマンドを記述する場合に非常に役立ちます。ただし、ユーザー入力が可能な場合に、アプリケーションでSQLインジェクションから保護するために準備済みステートメントやその他の方法を使用する必要性を軽減することはできません。@Craigの回答にはそれ以上のものがあります。詳細:

Postgres内の値

データベース内の値を処理する場合、文字列を適切に引用するための便利な関数がいくつかあります。

  • quote_literal()またはquote_nullable() -後者NULLはnull入力の文字列を出力します。(有効なSQL 識別子を取得するために必要な場所で文字列quote_ident()二重引用符で囲む必要もあります。)
  • format()形式指定子%Lを使用すると、と同等になりquote_nullable()ます。
    お気に入り:format('%L', string_var)
  • concat()またはconcat_ws()、ネストされた一重引用符やバックスラッシュをエスケープしないため、通常は適切ではありません

1
また、PgJDBCのバージョンによっては、ドル引用符に関する問題があることにも注意してください。特に、ドル引用符で囲まれた文字列内のステートメント終了文字(;)は無視できない場合があります。
クレイグリンガー

1
この関連する回答には、JDBC に関する問題の詳細があります。
Erwin Brandstetter 2014

1
また、手続き型言語の場合など、挿入時にテキスト列からs'tringをエスケープする場合は、quote_literal(column_name)文字列関数を使用できます。
alexglue 14

1
$ token $は素晴らしいです。ありがとう。
mythicalcoder

@ ErwinBrandstetter、re「任意の数のレベルをネストできる」:ただしSELECT $outer$OUT$inner$INNER$inner$ER$outer$;、2番目のレベルのネストがここでは機能しないことを証明します。
filiprem

46

あなたの質問はおそらくあなたのアプリケーションにギャップのあるSQLインジェクションホールがあることを示唆しているので、これは非常に多くの悪い世界です。

パラメータ化されたステートメントを使用する必要があります。Javaの場合はPreparedStatement、プレースホルダーとともに使用ます。あなたはパラメータ化されたステートメントを使用したくないと言いますが、理由を説明しません、そして率直に言って、それらがあなたがしようとしている問題を修正する最も簡単で安全な方法であるため、それらを使用しない非常に良い理由でなければなりません解決する。

JavaでのSQLインジェクションの防止を参照してください。ボビーの次の犠牲者にならないでください。

PgJDBCには、文字列の引用とエスケープのためのパブリック関数はありません。それはそれが良いアイデアのように見えるかもしれないという理由もあります。

あります組み込み関数を引用quote_literalし、quote_identPostgreSQLでは、彼らはのためにあるPL/PgSQL使用機能しますEXECUTE。最近では、パラメータquote_literal化されたバージョンEXECUTE ... USINGあるによって、ほとんど安全なっています。これらはサーバー側の関数であるため、ここで説明する目的には使用できません。


');DROP SCHEMA public;--悪意のあるユーザーから価値を得た場合を想像してみてください。あなたは作り出すでしょう:

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

これは、2つのステートメントと、無視されるコメントに分解されます。

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

おっと、あなたのデータベースがあります。


私は1つの例外-「in」節(または「or」の束)の一部として値のリストを含む「where」節(「挿入」と言います)に同意する傾向があります。リストのサイズを数え、 "in"句を使用して準備済みステートメントにテキストを生成できると思いますが、その使用例では奇妙です。
Roboprog 2014年

@Roboprog使用できる一部のクライアントドライバー= ANY(?)と配列パラメーター。
クレイグリンガー

12
このようなリテラル挿入を、DDLと一緒にデータのブートストラップによく使用しました。「ýou's do it it bad '」のような応答よりも質問に答えてみましょう
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そのような関数があった場合、エスケープはクライアント側で行う必要があるため、PostgreSQL自体ではなくPgJDBCにあります。それはひどい考えので、そのような文書化されたパブリック関数はありません。パラメータ化されたステートメントを使用する必要があるため、信頼性の低い可能性のあるエスケープを行う必要はありません。
クレイグリンガー

13

postgresqlで値を挿入したい場合'は、このために追加する必要があります'

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

引用符で囲まれた文字列がある場合に三重引用符を表示することへの
賛成票

up、それは単純な解決策なので
ktaria


2

Pg内で作業を行う必要がある場合:

to_json(value)

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


この質問はJSONとどのように関連していますか?
Erwin Brandstetter 2017

1
@ErwinBrandstetter、申し訳ありませんが、オフになっている可能性があります。ただし、文字列内の引用符をエスケープします
はてな

1
それはまったく別の問題です。あなたは使用する可能性があるformat()quote_literal()またはquote_nullable()引用符をエスケープため。参照:stackoverflow.com/a/25143945/939860
Erwin Brandstetter 2017

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.