web-dev-qa-db-ja.com

準備済みステートメントを使用した可変列名

準備されたステートメントを使用して返された列名を指定する方法があるのか​​どうか疑問に思いました。

MySQLとJavaを使用しています。

私がそれを試すとき:

String columnNames="d,e,f"; //Actually from the user...
String name = "some_table"; //From user...
String query = "SELECT a,b,c,? FROM " + name + " WHERE d=?";//...
stmt = conn.prepareStatement(query);
stmt.setString(1, columnNames);
stmt.setString(2, "x");

このタイプのステートメントを取得します(実行直前に印刷します)。

SELECT a,b,c,'d,e,f' FROM some_table WHERE d='x'

しかし、私は見たいです:

SELECT a,b,c,d,e,f FROM some_table WHERE d='x'

here で説明したように、テーブル名に対してこれを行うことはできませんが、列名に対してそれを行う方法があるかどうか疑問に思っていました。

存在しない場合は、入力をサニタイズしてSQLインジェクションの脆弱性につながらないようにする必要があります。

37
KLee1

これは、不適切なDB設計を示しています。ユーザーは列名について知る必要はありません。これらの「列名」を保持する実際のDB列を作成し、代わりにデータを格納します。

いずれにしても、列名をPreparedStatement値として設定することはできません。列valuesのみをPreparedStatement値として設定できます

この方向に進みたい場合は、列名をサニタイズして( SQLインジェクション を回避するため)、SQL文字列を自分で連結/構築する必要があります。個別の列名を引用し、 String#replace() を使用して列名内の同じ引用符をエスケープします。

34
BalusC

許可された列名のホワイトリストを準備します。 「クエリ」を使用してホワイトリストを検索し、列名があるかどうかを確認します。そうでない場合は、クエリを拒否します。

15
wgl

準備されたステートメントの要点は、ユーザーがエスケープされていないクエリビットを入力できないようにすることであるため、このケースは機能しないと思います。したがって、常にテキストを引用またはエスケープします。

クエリ構造に安全に影響を与えたい場合は、Javaでこの入力をサニタイズする必要があります。

2
G__

Statement InterfaceのSQLインジェクションのデメリットを利点として使用します。例:

st=conn.createStatement();
String columnName="name";
rs=st.executeQuery("select "+ columnName+" from ad_org ");
0
public void MethodName(String strFieldName1, String strFieldName2, String strTableName)
{
//Code to connect with database
String strSQLQuery=String.format("select %s, %s from %s", strFieldName, strFieldName2, strTableName);
st=conn.createStatement();
rs=st.executeQuery(strSQLQuery);
//rest code
}
0
Grbh Niti