{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a698dfac",
   "metadata": {},
   "source": [
    "# 22-32 · Параметризация против инъекции\n",
    "\n",
    "Практика к разделу [«Основы безопасности веб-приложений»](../../site/chapters/glava-22/22-32-bezopasnost.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2a551b8",
   "metadata": {},
   "source": [
    "## Цель\n",
    "\n",
    "На настоящем sqlite3 сравнить опасную сборку запроса через f-строку с безопасным параметризованным запросом — и увидеть, к чему приводит SQL-инъекция, если её не остановить."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "661f7c2d",
   "metadata": {},
   "source": [
    "## Рабочий пример — уязвимый вариант\n",
    "\n",
    "Используем одноинструкционную инъекцию, которую принимает обычный `sqlite3.execute()`. Составную атаку с `DROP TABLE` этот метод отклонил бы, но это ограничение Python-драйвера не делает SQL из f-строки безопасным."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "284d1333",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sqlite3\n",
    "\n",
    "baza = sqlite3.connect(\":memory:\")\n",
    "baza.execute(\"CREATE TABLE tasks (id INTEGER PRIMARY KEY, title TEXT NOT NULL)\")\n",
    "zadachi = [(\"Купить хлеб\",), (\"Написать тесты\",), (\"Позвонить врачу\",)]\n",
    "baza.executemany(\"INSERT INTO tasks (title) VALUES (?)\", zadachi)\n",
    "baza.commit()\n",
    "\n",
    "vvod_polzovatelya = \"' OR '1'='1\"\n",
    "\n",
    "# ТАК ДЕЛАТЬ НЕЛЬЗЯ — показано специально, чтобы увидеть последствия:\n",
    "opasny_zapros = f\"SELECT * FROM tasks WHERE title = '{vvod_polzovatelya}'\"\n",
    "rezultat_opasny = baza.execute(opasny_zapros).fetchall()\n",
    "\n",
    "print(\"Введённый фильтр:\", repr(vvod_polzovatelya))\n",
    "print(\"Строки, возвращённые уязвимым запросом:\", rezultat_opasny)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "daec72f1",
   "metadata": {},
   "source": [
    "## Проверка результата — фильтр обойдён"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "815634a9",
   "metadata": {},
   "outputs": [],
   "source": [
    "vse_stroki = baza.execute(\"SELECT * FROM tasks ORDER BY id\").fetchall()\n",
    "assert rezultat_opasny == vse_stroki\n",
    "assert len(rezultat_opasny) == len(zadachi) == 3\n",
    "print(f\"Фильтр обойдён: запрос вернул все {len(rezultat_opasny)} строки вместо точного совпадения.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6224352b",
   "metadata": {},
   "source": [
    "## Эксперимент — параметризованный запрос безопасен"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b2ed903",
   "metadata": {},
   "outputs": [],
   "source": [
    "baza2 = sqlite3.connect(\":memory:\")\n",
    "baza2.execute(\"CREATE TABLE tasks (id INTEGER PRIMARY KEY, title TEXT NOT NULL)\")\n",
    "baza2.executemany(\"INSERT INTO tasks (title) VALUES (?)\", zadachi)\n",
    "baza2.commit()\n",
    "\n",
    "vvod_kak_dannye = \"' OR '1'='1\"\n",
    "rezultat = baza2.execute(\"SELECT * FROM tasks WHERE title = ?\", (vvod_kak_dannye,)).fetchall()\n",
    "\n",
    "vse_stroki2 = baza2.execute(\"SELECT * FROM tasks ORDER BY id\").fetchall()\n",
    "print(\"Строки по точному совпадению:\", rezultat)\n",
    "print(\"Все строки по-прежнему в таблице:\", vse_stroki2)\n",
    "\n",
    "assert rezultat == []\n",
    "assert len(vse_stroki2) == len(zadachi) == 3\n",
    "print(\"Верно: параметризованный запрос обработал вредоносный текст как обычное значение и не позволил обойти фильтр.\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Cartesian Python 3.14",
   "language": "python",
   "name": "cartesian-python314"
  },
  "language_info": {
   "name": "python",
   "version": "3.14.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
