Главная | Архив новостей | Общение | Площадка | Примеры OpenID
Хостинг Django от «Джино»
Оглавление

Внедрение SQL

SQL инъекция — это стандартная уязвимость, в которой атакующая сторона изменяет параметры веб страницы (такие как GET/POST данный или URL) для внедрения определённых кусков SQL запроса, которые наивное веб приложение выполняет напрямую над своей базой данных. Вероятно, это наиболее опасная и, к сожалению, наиболее часто встречающаяся уязвимость.

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

def user_contacts(request):
    user = request.GET['username']
    sql = "SELECT * FROM user_contacts WHERE username = '%s';" % username
    # execute the SQL here...

Замечание

В данном примере, и в других подобных «не делай так» примерах, мы намеренно опустим большую часть кода, необходимого для работоспособности описываемых функций. Мы не желаем, чтобы кто-нибудь использовал такой код вне контекста данной главы.

И хотя такой код не выглядит опасным, он таковым является.

Во-первых, наша попытка защитить весь наш список адресов электронной почты провалится из-за хитро составленного запроса. Подумайте о том, что может случиться, если атакующий введёт ' OR 'a'='a в поле запроса. В этом случае, будет сконструирован следующий запрос:

SELECT * FROM user_contacts WHERE username = '' OR 'a' = 'a';

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

Однако, существует как минимум ещё одна опасность. Представьте, что может случиться, если атакующий введёт '; DELETE FROM user_contacts WHERE 'a'='a'. Вот так будет выглядеть сконструированный запрос:

SELECT * FROM user_contacts WHERE username = ''; 
DELETE FROM user_contacts WHERE 'a' = 'a';

Ой! А куда делся наш список контактов?

Решение

Несмотря на то, что данная проблема является не очевидной, решение для неё будет простым: никогда не доверяйте пользовательским данным и всегда экранируйте всё, что вы используете при конструировании SQL запроса.

Всё это Django делает на уровне API для работы с базой данных. Он автоматически экранирует все специальные SQL параметры, учитывая соглашение об использовании кавычек для используемого вами сервера баз данных (т.е., PostgreSQL или MySQL).

Например, в данном вызове API:

foo.get_list(bar__exact="' OR 1=1")

Django выполнит соответствующее экранирование и результирующий оператор будет выглядеть так:

SELECT * FROM foos WHERE bar = '\' OR 1=1'

т.е., очень безобидно.

Это поведение характерно для всего API с некоторыми исключениями:

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

from django.db import connection

def user_contacts(request):
    user = request.GET['username']
    sql = "SELECT * FROM user_contacts WHERE username = %s;"
    cursor = connection.cursor()
    cursor.execute(sql, [user])
    # ... do something with the results

Низкоуровневый метод execute() принимает с SQL строку с символами подстановки (%s) и автоматически экранирует и подставляет параметры из списка, переданного вторым аргументом. Вы должны всегда конструировать свои SQL запросы таким способом.

К сожалению, вы не можете свободно использовать привязку переменных. Например, нельзя таким способом определять идентификаторы (т.е., имя таблицы или полей таблиц). Следовательно, если вам потребуется динамически создать список таблиц по, скажем, содержимому переменной POST, вам придётся экранировать их имена в своём коде. Django предоставляет функцию, django.db.backend.quote_name(), которая осуществляет экранирование идентификатора в соответствии с принятой схемой квотирования для текущей базы данных.


Увидели ошибку?
Выделите её мышкой и нажмите
Ctrl-Enter
Обработано:
1049 49 130 71

Версия книги
1.0 2.0
Версия 2.0 в процессе перевода!

Мой луч
Многообразие света

Полезное
Актуальные вакансии, Python работа для python-разработчиков.


Скачать в формате
CHM от 2 сентября

Заказать PDF файл можно через почту, чат, джаббер. Всего 2WMZ. Содержимое точно соответствует содержимому сайта.
Чем чаще заказываете — тем больше перевожу.

Русская группа

на поддержку перевода
Яндекс Яндекс.Деньги Хочу такую же кнопку
Ускорить процесс перевода!
R130494980980
Z425285133788
E112528079659
U327380922061

Книга помогла реализовать:
Проект «Мой луч»
АРМ УФМС.


Мой вебсайт стоит666 337,31 руб

© 2008-2009 Ruslan Popov @ gmail.com Powered by Django 1.1 beta 1 SVN-11114
Главная | Архив новостей | Общение | Площадка | Примеры OpenID