Рубрики
Без рубрики

Инъекция SQL в Java и как ее легко предотвратить

Что такое SQL-инъекция? Инъекция SQL является одной из 10 основных уязвимостей веб-приложений. Проще говоря, SQL-инъекция означает введение/вставку SQL

Автор оригинала: Pankaj Kumar.

Что такое SQL-инъекция?

Инъекция SQL является одной из 10 лучших уязвимостей веб-приложений. Проще говоря, SQL-инъекция означает ввод/вставку SQL-кода в запрос с помощью введенных пользователем данных. Это может произойти в любых приложениях, использующих реляционные базы данных, такие как Oracle, MySQL, PostgreSQL и SQL Server.

Чтобы выполнить SQL-инъекцию, злоумышленник сначала пытается найти в приложении место, куда он может встроить SQL-код вместе с данными. Это может быть страница входа любого веб-приложения или любого другого места. Поэтому, когда приложение получает данные, встроенные в SQL-код, SQL-код будет выполнен вместе с запросом приложения.

Влияние SQL-инъекции

  • Злоумышленник может получить несанкционированный доступ к вашему приложению и украсть данные.
  • Они могут изменять, удалять данные в вашей базе данных и отключать ваше приложение.
  • Хакер также может получить контроль над системой, в которой работает сервер базы данных, выполнив системные команды, относящиеся к конкретной базе данных.

Как Работает SQL-Инъекция?

Предположим, у нас есть таблица базы данных с именем tbluser , в которой хранятся данные пользователей приложений. Идентификатор пользователя является основным столбцом таблицы. У нас есть функциональность в приложении, которая позволяет вам получать информацию через идентификатор пользователя. Значение идентификатора пользователя получено из запроса пользователя.

Давайте взглянем на приведенный ниже пример кода.

String userId = {get data from end user}; 
String sqlQuery = "select * from tbluser where userId = " + userId;

1. Допустимый Пользовательский Ввод

Когда приведенный выше запрос выполняется с действительными данными, т. е. значением идентификатора пользователя 132, он будет выглядеть следующим образом.

Входные данные: 132

Выполненный запрос: выберите * из tbluser, где

Результат: Запрос вернет данные пользователя, имеющего идентификатор пользователя 132. В этом случае никакой SQL-инъекции не происходит.

2. Хакерский Ввод Данных Пользователем

Хакер может изменять запросы пользователей с помощью таких инструментов, как Postman, cURL и т. Д. для отправки SQL-кода в виде данных и таким образом в обход любых проверок на стороне пользовательского интерфейса.

Входные данные: 2 или

Выполненный запрос: выберите * из tbluser, где или

Результат: Теперь в приведенном выше запросе есть два условия с SQL ИЛИ выражением.

  • Идентификатор пользователя=2 : Эта часть будет соответствовать строкам таблицы со значением идентификатора пользователя “2”.
  • 1=1 : Эта часть всегда будет оцениваться как истинная. Таким образом, запрос вернет все строки таблицы.

Типы SQL-инъекций

Давайте рассмотрим четыре типа SQL-инъекций.

1. SQL-инъекция на основе логических значений

Приведенный выше пример представляет собой случай SQL-инъекции на основе логических значений. Он использует логическое выражение, которое принимает значение true или false. Его можно использовать для получения дополнительной информации из базы данных. Например;

Входные данные: 2 или

SQL-запрос: выберите имя, фамилию из tbl_employee, где EmpID= 2 или

2. Инъекция SQL На основе Объединения

Оператор SQL union объединяет данные из двух разных запросов с одинаковым количеством столбцов. В этом случае оператор объединения используется для получения данных из других таблиц.

Входные данные: 2. выберите имя пользователя, пароль от tbluser

Запрос: Выберите имя, фамилию из tbl_employee, где EmpID= 2. Выберите имя пользователя, пароль из tbluser

Используя SQL-инъекцию на основе объединения, злоумышленник может получить учетные данные пользователя.

3. Инъекция SQL на основе времени

В SQL-инъекции на основе времени в запрос вводятся специальные функции , которые могут приостанавливать выполнение на определенное время. Эта атака замедляет работу сервера базы данных. Это может привести к сбою в работе вашего приложения, повлияв на производительность сервера баз данных. Например, В MySQL:

Входные данные: 2 + СПЯЩИЙ РЕЖИМ(5)

Запрос: выберите emp_id, имя, фамилию из tbl_employee, где + SLEEP(5)

В приведенном выше примере выполнение запроса будет приостановлено на 5 секунд.

4. Инъекция SQL на основе ошибок

В этом варианте злоумышленник пытается получить такую информацию, как код ошибки и сообщение из базы данных. Злоумышленник вводит SQL, которые синтаксически неверны, поэтому сервер базы данных вернет код ошибки и сообщения, которые можно использовать для получения информации о базе данных и системе.

Пример внедрения Java SQL

Мы будем использовать простое веб-приложение Java для демонстрации внедрения SQL. У нас есть Login.html , которая представляет собой базовую страницу входа в систему, которая принимает имя пользователя и пароль от пользователя и отправляет их в LoginServlet .

Сервер входа в систему получает имя пользователя и пароль из запроса и проверяет их на соответствие значениям базы данных. Если аутентификация прошла успешно, сервлет перенаправляет пользователя на домашнюю страницу, в противном случае он вернет ошибку.

Login.html Код :




    
        Sql Injection Demo
    
    
    
Username
Password

LoginServlet.java Код :

package com.journaldev.examples;
import java.io.IOException;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (Exception e) {}
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        boolean success = false;
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // Unsafe query which uses string concatenation
        String query = "select * from tbluser where username='" + username + "' and password = '" + password + "'";
        Connection conn = null;
        Statement stmt = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/user", "root", "root");
            stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(query);
            if (rs.next()) {
                // Login Successful if match is found
                success = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                stmt.close();
                conn.close();
            } catch (Exception e) {}
        }
        if (success) {
            response.sendRedirect("home.html");
        } else {
            response.sendRedirect("login.html?error=1");
        }
    }
}

Запросы к базе данных [MySQL]:

create database user;

create table tbluser(username varchar(32) primary key, password varchar(32));

insert into tbluser (username,password) values ('john','secret');
insert into tbluser (username,password) values ('mike','pass10');

1. При вводе действительного имени пользователя и пароля со страницы входа в систему

Введите имя пользователя : джон

Введите имя пользователя : секретно

Запрос : выберите * из tbluser, где и

Результат : Имя пользователя и пароль существуют в базе данных, поэтому аутентификация прошла успешно. Пользователь будет перенаправлен на домашнюю страницу.

2. Получение несанкционированного доступа к системе с помощью SQL-инъекции

Введите имя пользователя : фиктивный

Введите пароль : ‘или ‘1’=’1

Запрос : выберите * из tbluser, где и пароль = ” или “1”=”1″

Результат : Введенные имя пользователя и пароль не существуют в базе данных, но аутентификация прошла успешно. Почему?

Это связано с внедрением SQL, так как мы ввели ‘ или ‘1’=’1 в качестве пароля. В запросе есть 3 условия.

  1. имя пользователя=’фиктивный’ : Это будет оценено как ложное, так как в таблице нет пользователя с фиктивным именем пользователя.
  2. пароль = “ : Это будет оценено как ложь, так как в таблице нет пустого пароля.
  3. ‘1’=’1′ : Он будет оценен как true, так как это статическое сравнение строк.

Теперь, объединив все 3 условия, т. е. false и false или true => Конечный результат будет true .

В приведенном выше сценарии мы использовали логическое выражение для выполнения SQL-инъекции. Есть несколько других способов сделать SQL-инъекцию. В следующем разделе мы рассмотрим способы предотвращения внедрения SQL в наше Java-приложение.

Предотвращение внедрения SQL в Java-код

Самое простое решение-использовать PreparedStatement вместо Оператора для выполнения запроса.

Вместо объединения имени пользователя и пароля в запросе мы предоставляем их для запроса с помощью методов настройки Preparedstatement.

Теперь значение имени пользователя и пароля, полученные из запроса, обрабатываются только как данные, поэтому никаких SQL-инъекций не произойдет.

Давайте посмотрим на измененный код сервлета.

String query = "select * from tbluser where username=? and password = ?";
Connection conn = null;
PreparedStatement stmt = null;
try {
    conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/user", "root", "root");
    stmt = conn.prepareStatement(query);
    stmt.setString(1, username);
    stmt.setString(2, password);
    ResultSet rs = stmt.executeQuery();
    if (rs.next()) {
        // Login Successful if match is found
        success = true;
    }
    rs.close();
} catch (Exception e) {
    e.printStackTrace();
} finally {
    try {
        stmt.close();
        conn.close();
    } catch (Exception e) {
    }
}

Давайте разберемся, что происходит в данном случае.

Запрос : выберите * из tbluser, где имя пользователя = ? и пароль = ?

Знак вопроса (?) в приведенном выше запросе называется позиционным параметром. В приведенном выше запросе есть 2 позиционных параметра. Мы не объединяем имя пользователя и пароль для запроса. Мы используем методы, доступные в Подготовленном заявлении , для предоставления пользовательского ввода.

Мы установили первый параметр с помощью stmt.setString(1, имя пользователя) , а второй параметр с помощью stmt.setString(2, пароль) . Базовый API JDBC заботится об очистке значений, чтобы избежать внедрения SQL.

Рекомендации по предотвращению внедрения SQL

  1. Проверьте данные, прежде чем использовать их в запросе.
  2. Не используйте общие слова в качестве имени таблицы или столбца. Например, многие приложения используют tbluser или tblaccount для хранения пользовательских данных. Электронная почта, имя, фамилия-это общие имена столбцов.
  3. Не объединяйте данные напрямую ( полученные в качестве пользовательского ввода) для создания SQL-запросов.
  4. Используйте такие фреймворки, как Спящий режим и Spring Data JPA для уровня данных приложения.
  5. Используйте позиционные параметры в запросе. Если вы используете обычный JDBC , то используйте PreparedStatement для выполнения запроса.
  6. Ограничьте доступ приложения к базе данных с помощью разрешений и разрешений.
  7. Не возвращайте чувствительный код ошибки и сообщение конечному пользователю.
  8. Сделайте надлежащий обзор кода, чтобы ни один разработчик случайно не написал небезопасный SQL-код.
  9. Используйте такие инструменты, как SQLMap , чтобы находить и устранять уязвимости SQL – инъекций в вашем приложении.

Это все для инъекции Java SQL, я надеюсь, что здесь не пропущено ничего важного.

Вы можете скачать пример проекта веб-приложения java по ссылке ниже.