L3_NC
.pdfКак бороться?: Stored Procedure
String custname = request.getParameter("customerName");
// This should REALLY be validated
try {
CallableStatement cs = connection.prepareCall(
"{call sp_getAccountBalance(?)}");
cs.setString(1, custname);
ResultSet results = cs.executeQuery();
//… result set handling
}catch (SQLException se) {
//… logging and error handling
}
© 2013 NetCracker Technology Corporation Confidential |
21 |
Как бороться?: экранировать ВСЕ параметры
Encoder oe = new OracleEncoder();
String query = "SELECT user_id FROM user_data WHERE user_name = '"
+oe.encode( req.getParameter("userID")) + "' and user_password = '"
+oe.encode( req.getParameter("pwd")) +"'";
© 2013 NetCracker Technology Corporation Confidential |
22 |
Литература по теме
•http://www.unixwiz.net/techtips/sql-injection.html
•http://www.slideshare.net/billkarwin/sql-injection-myths-and-fallacies
•https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
© 2013 NetCracker Technology Corporation Confidential |
23 |
Что-то пошло не так…
одиночные запросы
© 2013 NetCracker Technology Corporation Confidential |
24 |
Приём №1
•Используйте оператор вывода для вывода запроса в том виде, в котором его получает СУБД.
•System.out.println(sqlWithParams);
•В Java для Prepared Statements в большинстве случаев нельзя получить SQL код
Encoderпослеoe подстановки= new OracleEncoder();параметров
String• Еслиqueryвсе-таки= "SELECTне повезлоuser: _id FROM user_data WHERE user_name = '"
‒ Приём №2: настройте журналирование со стороны БД (google:”site:usertackoverflow.com %DB
+ oe.encode( req.getParameter("userID")) + "' and _password = '"
name% log query”)
+ oe.encode( req.getParameter("pwd")) +"'";
‒ посмотрите на log4jdbc, DBAppender
‒ напишите свой велосипед (http://stackoverflow.com/questions/2382532/how-can-i-get-the- sql-of-a-preparedstatement )
http://www.opennet.ru/docs/RUS/sql_error/ |
25 |
© 2013 NetCracker Technology Corporation Confidential |
Приём №2
•Используйте журналирование, если вам нужно определить какой именно запрос вызывает неправильное поведение вашего приложения.
•Oracle http://docs.oracle.com/cd/E23943_01/bi.1111/e10541/logging.htm#CEGBIGIJ
•Postgre SQL http://www.microhowto.info/howto/log_all_queries_to_a_postgresql_server.html
•MySQL http://dev.mysql.com/doc/refman/5.1/en/query-log.html
•%DB name% google:”site:stackoverflow.com %DB name% log query”)
© 2013 NetCracker Technology Corporation Confidential |
26 |
Когда проблемый запрос найден…
1. Запустите запрос из консоли.
mysql> select count(*) as b from t3 order by b,a; +---+
| b | +---+ | 2 | | 2 | +---+
mysql> select count(*) as b from t3; +---+
| b | +---+ | 2 | +---+
1 row in set (0.01 sec)
Баг в MySQL 5.1.38
© 2013 NetCracker Technology Corporation Confidential |
27 |
Когда проблемый запрос найден
• Пробуйте изменить SQL таким образом, чтобы результат был правильным. Пользуйтесь поисковыми системами для нахождения workaround.
• Посмотрите план выполнения.
mysql> select a.id as a_id, b.id from a a left join b b on a.id = b.a_id where a.id = 1;
+------ |
|
+------ |
|
+ |
| a_id | id |
|
| |
||
+------ |
|
+------ |
|
+ |
| |
1 |
| |
1 |
| |
| |
1 | |
2 | |
||
| |
1 |
| |
3 |
| |
+------ |
|
+------ |
|
+ |
mysql> select a.id as a_id, count(distinct b.id) as cnt from a a left join b b on a.id = b.a_id where a.id = 1 group by a.id with rollup limit 100;
+------+-----+ | a_id | cnt |
+------ |
+ |
----- |
+ |
| |
1 | |
8 |
| |
| NULL | |
8 |
| |
|
+------ |
+----- |
|
+ |
С индексом на b.id
Без индекса на b.id
http://bugs.mysql.com/bug.php?id=47650
+------+-----+ | a_id | cnt |
+------ |
+ |
-----+ |
| |
1 | |
3 | |
| NULL | |
3 | |
|
+------ |
+----- |
+ |
© 2013 NetCracker Technology Corporation Confidential |
28 |
UPSERT + PostgreSQL
1.CREATE TABLE tbl( KEY int, val int);
2.INSERT INTO tbl(KEY,val)
3.SELECT DISTINCT(KEY), 0
4. |
FROM unnest('{0,1,2,3,4,5}'::int[]) AS KEY |
5. |
WHERE KEY NOT IN ( |
6. |
UPDATE tbl SET val = val+1 |
7. |
WHERE KEY = |
|
any('{0,1,2,3,4,5}'::int[]) |
8. |
returning KEY ); |
ERROR: syntax error at OR near "tbl“ Строка 6: UPDATE tbl SET val = val+1
http://stackoverflow.com/questions/7191902/cannot-select-from-update-returning-clause- in-postgres
© 2013 NetCracker Technology Corporation Confidential |
29 |
Когда проблемый запрос найден …
•Если запрос DML – преобразуйте его в SELECT-запрос чтобы выяснить какие строки будут изменены.
mysql> create table t1(f1 int); mysql> create table t2(f2 int); mysql> insert into t1 values(1); Query OK, 1 row affected (0.01 sec)
mysql> |
select * from t1; |
|
+------ |
|
+ |
| f1 |
|
| |
+------ |
|
+ |
| |
1 |
| |
+------ |
|
+ |
mysql> delete from t1, t2 using t1, t2; Query OK, 0 rows affected (0.00 sec)
© 2013 NetCracker Technology Corporation Confidential |
30 |