Kraken
  • 🐙Привет!
    • 👋Добро пожаловать!
  • ✏️Крупицы знаний
    • 🌚Общие статьи
      • Как установить Kali Linux
      • Как поставить виртуальную Kali Linux
      • Что такое CVE
      • Обзор популярных алгоритмов хеширования
      • Модель OSI
      • Какие есть алгоритмы шифрования
      • Что такое TCP/IP
      • HSTS
      • Что такое хеширование и как его используют в ИБ
      • Скрипт для проверки данных SSL-сертификата
      • Шифруем файлы на Kali Linux с помощью OpenSSL
      • Как работает WPA2
      • О протоколе FTP
      • Что такое CVSS
      • Что такое политика одного источника (SOP)
      • О Cross-Origin Resource Sharing (CORS)
      • О Content Security Policy (CSP)
      • Что такое Bash
      • Веб-сокеты
      • MITRE ATT&CK
      • Начало в OSINT
      • Особенности и подходы к тестированию мобильных приложений
      • Что такое REST
      • Что такое API
      • Сравнение безопасности среды iOS и Android
      • CSS в ИБ
    • 🎪Карьера
      • Какие бывают роли у пентестеров и в чем их смысл
      • Какие есть виды пентеста
      • Что входит в пентест
      • Какие есть области знаний в веб-пентесте
      • Главные ошибки новичков в ИБ
    • 😰Уязвимости
      • Об атаке Pastejaking
      • Об уязвимости KRACK
      • Об уязвимости Regex DoS
      • Об атаке MITM
      • Что такое уязвимость нулевого дня
      • Атака на протокол STP
      • Защита протокола STP
      • Clickjacking
      • База при атаке на Wi-Fi
      • Атаки по сторонним каналам
      • DNS ребайндинг
    • ⚙️Инструменты
      • Лучшие сканеры открытых портов и инструменты проверки портов
      • Что такое OWASP ZAP и как он помогает защитить приложения?
      • О фреймворке WiFi Exploitation Framework (WEF)
      • WeBaCoo — поддерживаем доступ к взломанному веб-серверу
      • Socialscan — проверяем использование электронной почты и имен пользователей в соцсетях
      • Обзор инструментов Red Team
      • 11 инструментов для сканирования уязвимостей
      • Подборка инструментов для автоматизации атак на JWT
      • О Bulk_Extractor
      • О Unicornscan
      • О Maryam
      • О Picocrypt, утилите для шифрования данных
      • Анализируем трафик с ZUI (Zed User Interface)
      • Об инструменте SkipFish
      • Как получить уведомления на почту о входе по SSH
      • О сканере OpenSCAP
      • О Censys — инструменте для поиска уязвимых поддоменов
      • О Scanless — инструменте для анонимного сканирования открытых портов
      • О SearchSploit — инструменте для поиска эксплойтов
      • Выбираем менеджер паролей
      • О Maltego
      • Устанавливаем и используем Snyk CLI в Windows
      • Проверяем безопасность Docker-образов с помощью Trivy
      • Об инструменте SpiderFoot
      • Сканируем сети с помощью скриптов Bash
      • О фреймворке Volatility на Windows
      • Определяем тип WAF с помощью WafW00f
      • Об инструменте ReNgine
      • О Foremost — инструменте для восстановления данных
      • Chisel — инструмент для проброса портов
      • O Yersinia
      • Об Acunetix
      • O Netcat
      • O Samba
      • O John the Ripper
      • О Common User Passwords Profiler (CUPP)
      • О RainbowCrack
      • Shodan
      • MobSF
      • Netsparker
      • Fortify
      • Veracode
      • Rapid7 InsightVM
      • Aircrack-ng
  • 🛠️ИНСТРУМЕНТЫ
    • ⌨️Беспроводные атаки
      • Aircrack-Ng
    • 🔑Атаки на пароли
      • Crunch
      • John
      • CUPP
      • Hashcat
      • Hydra
    • 👁️Сбор Информации
      • Masscan
      • Dnsenum
      • Parsero
      • Nmap
  • 👨‍💻Пентест
    • Методология
    • 🖥️Аппаратный/Физический доступ
      • Физические атаки
      • Побег из КИОСКа
  • 👾MITRE
    • 🗺️Тактики
      • 🏢Предприятия
        • Разведка
      • 📱Мобильные устройства
      • 🏭ICS
    • 💀CTI
      • ☠️Группы
        • admin@338
        • Ajax Security Team
        • ALLANITE
        • Andariel
  • 📟Справочник по безопасной разработке
    • 👨‍🔬CLIENT SIDE
      • Cross-Site Scripting [XSS]
      • Cross-Site Request Forgery [CSRF]
      • Clickjacking
      • Open Redirects
    • 🖥️SERVER SIDE
      • SQL Injections [SQLi]
      • XML External Entity Injection [XXE]
      • OS Command Injection [Command Execution]
      • File Upload
      • Server-Side Request Forgery [SSRF]
      • Host Header Injection
      • Аутентификация
      • Directory Traversal
      • Template Injection [SSTI]
    • API
  • 🐝OWASP
    • Cross Site Scripting (XSS)
Powered by GitBook
On this page
  • 1. Введение:
  • 2. Типичный уязвимый код:
  • 3. Смягчение последствий:
  • 3.1. Подготовленные условия:
  • 3.2. Хранимые процедуры:
  • 3.3. Проверка ввода:
  • 3.4. Исключение вводимых данных пользователем:
  • 4. Выводы:
  1. Справочник по безопасной разработке
  2. SERVER SIDE

SQL Injections [SQLi]

1. Введение:

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

  1. Прекратить писать динамические запросы для своих приложений.

  2. Фильтровать и экранировать вводимые пользователем данные.

Представленные здесь приемы технически применимы к большинству других языков программирования и/или типов баз данных.

2. Типичный уязвимый код:

function authenticate(req, res, next) {
    var email = req.query.email,
        password = req.query.password,
        sqlRequest = new sql.Request(),
        sqlQuery = "select * from users where (email='" 
        + "' and password = '" + password + "')";
    
    sqlRequest.query(sqlQuery)
        .then(function (recordset) {
            if (recordset.length == 1) {
                loggedIn = true;
                // Auth successful
            } else {
                // Auth failure
            }
        })
        .catch(next);
}
def authenticate(request):
    email = request.POST['email']
    password = request.POST['password']
    sql = "select * from users where (email ='" 
        + email 
        + "' and password ='" + password + "')"
    
    cursor = connection.cursor()
    cursor.execute(sql)
    row = cursor.fetchone()
    if row:
        loggedIn = "Auth successful"
    else:
        loggedIn = "Auth failure"
    return HttpResponse("Logged In Status: " + loggedIn)
<?php
$email = $POST['email'];
$password = $POST['password'];

$stmt = mysql_query("SELECT * FROM users WHERE (email='$email' 
                    AND password='$password') LIMIT 0,1"
                    );

$count = mysql_fetch_array($stmt);
if($count > 0) {
    session_start();
    // Auth successful
}
else
{
    // Auth failure
}
?>

sqlQuery Выполняет SQL-запрос без какой-либо проверки ввода. (т. е. не проверяется наличие легальных символов, минимальная/максимальная длина строки или удаление "вредоносных" символов).

Злоумышленник может ввести необработанный синтаксис SQL в поля ввода имени пользователя и пароля, чтобы изменить значение SQL-запроса, отвечающего за аутентификацию, что приведет к обходу механизма аутентификации приложения. Примером такого обхода может быть запрос: ' or 1=1)#

3. Смягчение последствий:

Атаки SQL Injection, к сожалению, очень распространены, и это объясняется двумя факторами:

  1. значительной распространенностью уязвимостей SQL Injection и

  2. Привлекательность цели (т.е. база данных обычно содержит все интересные/критичные данные для вашего приложения).

Довольно стыдно, что до сих пор существует так много успешных SQLi, потому что на самом деле очень просто избежать этого типа уязвимостей. В этой статье вы узнаете о 4 самых надежных методах разработки надежного и безопасного приложения.

3.1. Подготовленные условия:

Использование подготовленных операторов с привязкой к переменным (они же параметризованные запросы) - это то, как все разработчики должны писать свои запросы с самого начала. Они просты в написании и более понятны, чем динамические запросы. Параметризованные запросы заставляют разработчика сначала определить весь SQL-код, а затем передать каждый параметр в запрос. Такой стиль кодирования позволяет базе данных различать код и данные, независимо от того, что вводит пользователь.

Подготовленные операторы гарантируют, что злоумышленник не сможет изменить смысл запроса, даже если SQL-команды будут вставлены злоумышленником. В приведенном ниже безопасном примере, если бы злоумышленник ввел сообщение электронной почты bobi@mail.com' или '1'='1, параметризованный запрос не был бы уязвимым и вместо этого искал бы имя пользователя, которое буквально соответствовало бы всей строке bobi@mail.com' или '1'='1.

function authenticate(req, res, next) {
    var email = req.query.email,
        password = req.query.password,
        ps = new sql.PreparedStatement(),
        sqlQuery = "select * from users where (email = @email and " 
                 + "password = @password)";
    
    ps.input('email', sql.VarChar(50));
    ps.input('password', sql.VarChar(50));
    ps.prepare(sqlQuery)
    .then(function () {
        return ps.execute({email: email, password: password})
        then(function (recordset) {
            if (recordset.length == 1) {
                loggedIn = true;
                // Auth successful
    
            } else {
                // Auth failure
            }
        })
    })
    .catch(next);
};
def authenticate(request):
    email = request.POST['email']
    password = request.POST['password']
    
    cursor = connection.cursor()
    cursor.execute("select * from users where(email = %s and password = %s)"
    , [email, password])
    row = cursor.fetchone()
    if row:
        loggedIn = "Auth successful"
    else:
        loggedIn = "Auth failure"
    return HttpResponse("Logged In Status: " + loggedIn)
<?php
$email = $POST['email'];
$password = $POST['password'];

$stmt = $db->prepare("SELECT * FROM users WHERE 
                    (email=:email AND password=:password) LIMIT 0,1"
                    );
$stmt->bindParam(':email', $email);
$stmt->bindParam(':password', $password);
$stmt->execute();

$count = mysql_fetch_array($stmt);
if($count > 0) {
    session_start();
    // Auth successful
}
else
{
    // Auth failure
}
?>

3.2. Хранимые процедуры:

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

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

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

Вот краткий пример того, как может быть реализована хранимая процедура на языке SQL.

CREATE PROCEDURE SafeAuth(@username varchar(50),  @password varchar(50))
AS
BEGIN
DECLARE @sql varchar(150)
    SELECT Username,Password FROM dbo.Login
    WHERE Userame=@username AND Password=@password
end

Примечание: "Реализовано безопасно" означает, что хранимая процедура не содержит небезопасной динамической генерации SQL. Разработчики обычно не генерируют динамический SQL внутри хранимых процедур. Однако это может быть сделано, но этого следует избегать. Если этого нельзя избежать, хранимая процедура должна использовать проверку ввода или правильное экранирование, как описано в этой статье, чтобы убедиться, что все вводимые пользователем данные хранимой процедуры не могут быть использованы для внедрения SQL-кода в динамически генерируемый запрос.

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

3.3. Проверка ввода:

Существует два типа проверки ввода: синтаксическая и семантическая.

Синтаксическая проверка обеспечивает синтаксическую корректность структурированных полей. (например, SSN, дата, символ валюты и т. д.).

Семантическая валидация обеспечивает корректность вводимых значений в конкретном бизнес-контексте. (например, дата начала до даты окончания, цена в пределах приписанного диапазона и т. д.)

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

Однако важно отметить, что любая проверка ввода JavaScript, выполняемая на стороне клиента, может быть обойдена злоумышленником, отключившим JavaScript или использующим веб-прокси. Убедитесь, что любая проверка ввода, выполняемая на стороне клиента, выполняется и на стороне сервера.

  • Валидаторы типов данных, имеющиеся во фреймворках веб-приложений (например, Django Validators, Apache Commons Validators и др.).

  • Валидация по JSON Schema и XML Schema (XSD) для ввода данных в этих форматах.

  • Преобразование типов (например, Integer.parseInt() в Java, int() в Python) со строгой обработкой исключений.

  • Проверка минимального и максимального диапазона значений для числовых параметров и дат, проверка минимальной и максимальной длины для строк.

  • Массив допустимых значений для небольших наборов строковых параметров (например, дней недели).

  • Регулярные выражения для любых других структурированных данных, охватывающие всю входную строку (^...$) и не использующие подстановочный знак "любой символ" (например, . или \S). Разработка регулярных выражений может быть сложной, поэтому при разработке такой проверки рекомендуется руководствоваться комплексным ресурсом.

3.4. Исключение вводимых данных пользователем:

Этот метод следует использовать только в крайнем случае, когда ни один из вышеперечисленных способов не подходит. Вероятно, лучшим выбором будет проверка ввода, поскольку данная методология хрупка и мы не можем гарантировать, что она предотвратит все SQLi во всех ситуациях.

Представьте себе следующий сценарий: каждая СУБД поддерживает одну или несколько схем экранирования символов, специфичных для определенных типов запросов. Если вы будете экранировать все вводимые пользователем символы, используя соответствующую схему экранирования для используемой базы данных, СУБД не будет путать их с SQL-кодом, написанным разработчиком, что позволит избежать возможных уязвимостей SQL-инъекций.

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

var SqlString = require('sqlstring');

var userId = 1;
var sql = SqlString.format('SELECT * FROM users WHERE id = ?', [userId]);
console.log(sql); // SELECT * FROM users WHERE id = 1
from psycopg2 import sql
# here one cam make use of database adapters, such as psycopg2
def authenticate(request):
    email = request.POST['email']
    password = request.POST['password']
    with connection.cursor() as cursor:
        stmt = sql.SQL("""
            select 
                * 
            from 
                users 
            where
                (email = {email} and password = {password})
            """).format(
                email = sql.Identifier(email),
                password = sql.Literal(password),
        )
        cursor.execute(stmt)
        row = cursor.fetchone()
    
        if row:
            loggedIn = "Auth successful"
        else:
            loggedIn = "Auth failure"
        return HttpResponse("Logged In Status: " + loggedIn)
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute(array('name' => $name));
foreach ($stmt as $row) {
    // do something with $row
    // PDO is the universal option; if you connect to databases other than MySQL
    // you can use driver-specific options.
}

4. Выводы:

SQLI НЕ ДОЛЖЕН СУЩЕСТВОВАТЬ! Так говорят все. И они правы! Если бы каждый разработчик:

  • Подготовил SQL-запросы.

  • Валидировал и экранировал пользовательский ввод.

  • Писал чистый эффективный код.( =D )

Last updated 1 year ago

📟
🖥️