0Pricing
Python Academy · Урок

Параметризованные запросы

Предотвращайте SQL-инъекции

«Параметризованные запросы» — бесплатный урок Python Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Python Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Python Academy содержит 4 уроков всего.

Опасность формирования строк

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

Никогда не делайте этого с непроверенными данными.

name = 'Alice'
# Unsafe pattern - do NOT do this
query = "SELECT * FROM users WHERE name = '" + name + "'"
print(query)

Как выглядит инъекция

Представьте вредоносное значение. Его объединение со строкой полностью меняет смысл запроса.

name = "x' OR '1'='1"
query = "SELECT * FROM users WHERE name = '" + name + "'"
print(query)
print('The OR clause makes every row match!')

Заполнители приходят на помощь

Безопасный способ — использовать параметризованные запросы. Используйте ? в качестве заполнителя и передавайте значения в виде кортежа. Драйвер безопасно экранирует их.

import sqlite3
conn = sqlite3.connect(':memory:')
cur = conn.cursor()
cur.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)')
cur.execute('INSERT INTO users (name) VALUES (?)', ('Alice',))
cur.execute('SELECT * FROM users')
print(cur.fetchall())
conn.close()

Несколько заполнителей

Используйте один ? для каждого значения. Передавайте значения в кортеже в том же порядке, в котором они встречаются.

import sqlite3
conn = sqlite3.connect(':memory:')
cur = conn.cursor()
cur.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)')
cur.execute('INSERT INTO users (name, age) VALUES (?, ?)', ('Bob', 25))
cur.execute('SELECT * FROM users')
print(cur.fetchall())
conn.close()

Кортежи с одним значением

В кортеже из одного элемента нужна завершающая запятая: ('Alice',). Без неё Python воспринимает круглые скобки лишь как группировку.

good = ('Alice',)
bad = ('Alice')
print(type(good), type(bad))

Попытка инъекции заблокирована

При использовании заполнителей вредоносное значение обрабатывается как обычные данные, а не как SQL-код. Оно просто не соответствует ни одной строке.

import sqlite3
conn = sqlite3.connect(':memory:')
cur = conn.cursor()
cur.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)')
cur.execute('INSERT INTO users (name) VALUES (?)', ('Alice',))
evil = "x' OR '1'='1"
cur.execute('SELECT * FROM users WHERE name = ?', (evil,))
print('Rows matched:', cur.fetchall())
conn.close()

Именованные заполнители

SQLite также поддерживает именованные заполнители с синтаксисом :name. Передавайте словарь значений.

import sqlite3
conn = sqlite3.connect(':memory:')
cur = conn.cursor()
cur.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)')
cur.execute('INSERT INTO users (name, age) VALUES (:n, :a)', {'n': 'Carol', 'a': 40})
cur.execute('SELECT * FROM users')
print(cur.fetchall())
conn.close()

Параметры в WHERE

Заполнители работают в любом предложении, принимающем значение, включая WHERE.

import sqlite3
conn = sqlite3.connect(':memory:')
cur = conn.cursor()
cur.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)')
cur.execute('INSERT INTO users (name, age) VALUES (?, ?)', ('Alice', 30))
cur.execute('INSERT INTO users (name, age) VALUES (?, ?)', ('Bob', 25))
cur.execute('SELECT name FROM users WHERE age > ?', (28,))
print(cur.fetchall())
conn.close()

executemany

Чтобы добавить много строк, используйте executemany() со списком кортежей. Это быстрее и по-прежнему безопасно.

import sqlite3
conn = sqlite3.connect(':memory:')
cur = conn.cursor()
cur.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)')
rows = [('Alice',), ('Bob',), ('Carol',)]
cur.executemany('INSERT INTO users (name) VALUES (?)', rows)
cur.execute('SELECT COUNT(*) FROM users')
print(cur.fetchone())
conn.close()

Заполнители не предназначены для идентификаторов

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

import sqlite3
conn = sqlite3.connect(':memory:')
cur = conn.cursor()
cur.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)')
allowed = {'name', 'id'}
col = 'name'
if col in allowed:
    cur.execute('SELECT ' + col + ' FROM users')
    print('Safe column query ran')
conn.close()

Повторно используемая функция добавления

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

import sqlite3
conn = sqlite3.connect(':memory:')
cur = conn.cursor()
cur.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)')

def add_user(cursor, name):
    cursor.execute('INSERT INTO users (name) VALUES (?)', (name,))

add_user(cur, 'Dave')
cur.execute('SELECT * FROM users')
print(cur.fetchall())
conn.close()

Быстрая проверка

Проверьте свои знания о безопасных запросах.

Итоги

Вы научились писать запросы, защищённые от инъекций.

  • Никогда не объединяйте непроверенные входные данные с SQL-кодом
  • Используйте заполнители ? с кортежем значений
  • Именованные заполнители :name принимают словарь
  • executemany() безопасно добавляет много строк
  • Заполнители предназначены для значений, а не для идентификаторов

Часто задаваемые вопросы

Урок «Параметризованные запросы» бесплатный?

Да — полный текст урока «Параметризованные запросы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Python Academy, подпишись на CoddyKit PRO. Курс Python Academy содержит 4 уроков всего.

Чему я научусь в уроке «Параметризованные запросы»?

Предотвращайте SQL-инъекции Ты практикуешь Python Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Python Academy?

Предыдущий опыт не требуется. Python Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Параметризованные запросы»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Python Academy?

Да. Каждый урок Python Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Подключение и создание таблиц
  2. Insert, Select, Update, Delete
  3. Параметризованные запросы
  4. Транзакции и менеджеры контекста
← Назад к Python Academy