[英]How to prevent SQL injection when dealing with dynamic table/column names?
我正在使用 jdbc PreparedStatement 進行數據插入。
Statement stmt = conn.prepareStatement(
"INESRT INTO" + tablename+ "("+columnString+") VALUES (?,?,?)");
tablename和columnString是動態生成的。
我試圖參數化 tablename 和 columnString,但它們只會解析為諸如 'tablename' 之類的東西,這將違反語法。
我在網上找到了建議我查找數據庫以檢查有效的表名/列字符串,並將其緩存在某處(可能是哈希集)以用於另一個查詢,但我正在尋找更好的性能/快速破解來解決問題,也許是一個可以解決問題的字符串驗證器/正則表達式。
有沒有人遇到過這個問題,你是如何解決的?
我不是一個 java 人,所以,只是一個理論。
您可以格式化動態添加的標識符或將它們列入白名單。
第二種選擇要好得多。 因為
columnString
,打造特權升級是小菜一碟。因此,事先在您的代碼中列出所有可能(和允許)的變體,然后根據它驗證輸入的值,將是最好的。
從columnString
- 由單獨的列名組成。 因此,為了保護它,必須對照白名單驗證每個單獨的列名稱,然后從它們組裝一個最終的columnString
。
創建一個為您生成 sql 字符串的方法:
private static final String template = "insert into %s (%s) values (%s)";
private String buildStmt(String tblName, String ... colNames) {
StringJoiner colNamesJoiner = new StringJoiner(",");
StringJoiner paramsJoiner = new StringJoiner(",");
Arrays.stream(colNames).forEach(colName -> {
colNamesJoiner.add(colName);
paramsJoiner.add("?");
});
return String.format(template, tblName, colNamesJoiner.toString(), paramsJoiner.toString());
}
然后用它...
Statement stmt = conn.prepareStatement(buildStmt(tablename, [your column names]));
作為對@Anders 回答的詳細說明,不要直接使用輸入參數作為名稱,而是保留一個將一組允許的輸入映射到實際表名的屬性文件(或數據庫表)。
這樣,任何無效的名稱都不會導致有效的 SQL(並且可以在生成任何 SQL 之前被捕獲)並且實際名稱在應用程序之外永遠不會知道,因此更難猜測什么是有效的 SQL 語句。
我認為,最好的方法是從數據庫或其他非用戶輸入中獲取表名和列名,然后在准備好的語句中使用參數。
我們可以應用多種解決方案。
1) 白名單輸入驗證
String tableName;
switch(PARAM):
case "Value1": tableName = "fooTable";
break;
case "Value2": tableName = "barTable";
break;
...
default : throw new InputValidationException("unexpected value provided for table name");
2) 將您的動態 columnName(s) 或 tableName(s) 與特殊字符綁定,如下所示
例如:
從`tableName`中選擇`columnName`;
從“tableName”中選擇“columnName”;
或者
從 [tableName] 中選擇 [columnName];
注意:在執行此操作之前,您應該使用此特殊字符(`、"、[、])清理您的數據
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.