Skip to content

4 Куки и сессии в Flask

Вопросы: 1) Куки в Flask 2) Сессии в Flask 3) Хранение сессий в куках и на сервере 4) Введение в кэширование

1) Куки

Куки (cookies) — это небольшие фрагменты данных, которые сервер отправляет клиенту (обычно браузеру). Клиент сохраняет эти данные и отправляет их обратно на сервер при последующих запросах. Куки часто используются для хранения информации о состоянии сессии, предпочтений пользователя или других данных, которые должны быть доступны между запросами.


Основные концепции

  1. Что такое куки?
  2. Куки — это текстовые данные, которые хранятся на стороне клиента.
  3. Они передаются между клиентом и сервером через HTTP-заголовки.
  4. Пример использования: аутентификация, отслеживание состояния сессии, персонализация контента.

  5. Как куки работают?

  6. Сервер отправляет клиенту HTTP-заголовок Set-Cookie с данными.
  7. Клиент сохраняет эти данные и отправляет их обратно на сервер через заголовок Cookie при каждом запросе.
    +----------------+          Set-Cookie: key=value         +----------------+
    |                | -------------------------------------> |                |
    |    Server      |                                         |    Client      |
    |                | <------------------------------------- |                |
    +----------------+            Cookie: key=value           +----------------+
  1. Ограничения куков:
  2. Размер одного куки ограничен (обычно до 4 КБ).
  3. Куки могут быть удалены клиентом или истечь по времени.
  4. Куки не являются безопасным способом хранения чувствительных данных (например, паролей).

Работа с куками в Flask

Flask предоставляет простой интерфейс для работы с куками через объект request и метод response.set_cookie().

1. Чтение куков

Для чтения куков используется объект request.cookies, который является словарем.

from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def index():
    # Получаем значение куки 'username'
    username = request.cookies.get('username', 'Гость')
    return f'Привет, {username}!'
  • request.cookies.get('username') пытается получить значение куки с именем username.
  • Если куки отсутствуют, возвращается значение по умолчанию ('Гость').

2. Установка куков

Чтобы установить куки, нужно использовать метод set_cookie() объекта ответа (Response).

from flask import Flask, make_response

app = Flask(__name__)

@app.route('/set_cookie')
def set_cookie():
    # Создаем объект ответа
    response = make_response('Куки установлены!')
    # Устанавливаем куки
    response.set_cookie('username', 'Alice', max_age=60*5)  # Куки живет 5 минут
    return response
  • make_response() создает объект ответа.
  • Метод set_cookie() принимает имя куки, его значение и дополнительные параметры:
  • max_age: время жизни куки в секундах.
  • expires: дата истечения срока действия куки.
  • path: путь, для которого куки будет действителен.
  • httponly: если True, куки недоступен из JavaScript.
  • secure: если True, куки отправляется только по HTTPS.

3. Удаление куков

Чтобы удалить куки, можно установить его с истекшим сроком действия.

@app.route('/delete_cookie')
def delete_cookie():
    response = make_response('Куки удалены!')
    response.set_cookie('username', '', expires=0)  # Установка пустого значения и истекшей даты
    return response

4. Использование куков для сессии

Сессия (от латинского sessio, от английского session – заседание) – это временной промежуток, охватывающий период использования Интернет-ресурса с момента, когда пользователь кликнул и перешел по начальному URL (ссылке) и до самого закрытия последней.

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

from flask import Flask, session, redirect, url_for

app = Flask(__name__)
app.secret_key = 'supersecretkey'  # Секретный ключ для шифрования сессии

@app.route('/login')
def login():
    session['user_id'] = 123  # Сохраняем ID пользователя в сессии
    return 'Вы вошли в систему!'

@app.route('/logout')
def logout():
    session.pop('user_id', None)  # Удаляем ID пользователя из сессии
    return 'Вы вышли из системы!'

@app.route('/profile')
def profile():
    user_id = session.get('user_id')
    if user_id:
        return f'Профиль пользователя с ID {user_id}'
    else:
        return redirect(url_for('login'))
  • session — это словарь, который автоматически сохраняет данные в зашифрованном виде в куки.
  • Для работы с сессией необходимо установить app.secret_key.

Безопасность куков

При работе с куками важно соблюдать следующие рекомендации: 1. Используйте httponly и secure: - httponly=True предотвращает доступ к куки через JavaScript. - secure=True гарантирует, что куки будут отправляться только по HTTPS.

  1. Шифруйте чувствительные данные:
  2. Никогда не храните пароли или другие важные данные в куки в открытом виде.
  3. Используйте механизмы сессии Flask для безопасного хранения данных.

  4. Устанавливайте корректное время жизни:

  5. Не делайте куки вечными, если это не требуется.

2) Сессии в Flask

Введение

Сессии (sessions) — это механизм для хранения данных как на стороне сервера, так и клиекта, связанных с конкретным пользователем. В отличие от куков, которые хранятся на стороне клиента, данные сессии обычно шифруются и сохраняются в защищенном виде

Что такое сессии?

  • Сессия — это временное хранилище данных, которое существует только во время взаимодействия пользователя с приложением.
  • Данные сессии уникальны для каждого пользователя и используются для хранения информации, например:
  • ID пользователя после входа в систему.
  • Настройки или предпочтения пользователя.
  • Корзина покупок в интернет-магазине.

Как работают сессии в Flask?

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

    +----------------+          Куки с ID сессии         +----------------+
    |                | --------------------------------> |                |
    |    Server      |                                    |    Client      |
    |                | <-------------------------------- |                |
    +----------------+       Запрос с ID сессии         +----------------+

Процесс работы: 1. Сервер создает данные сессии и шифрует их. 2. Зашифрованные данные отправляются клиенту в виде куки. 3. Клиент отправляет куки обратно при каждом запросе. 4. Сервер расшифровывает куки и восстанавливает данные сессии.


Работа с сессиями в Flask

Инициализация сессии

Для работы с сессиями в Flask необходимо установить секретный ключ (secret_key). Этот ключ используется для шифрования данных сессии.

from flask import Flask, session

app = Flask(__name__)
app.secret_key = 'supersecretkey'  # Установка секретного ключа
  • app.secret_key — это строка, которая используется для шифрования данных сессии. Она должна быть сложной и уникальной.

Создание и чтение данных сессии

Для работы с данными сессии используется объект session, который ведет себя как словарь.

from flask import Flask, session, redirect, url_for

app = Flask(__name__)
app.secret_key = 'supersecretkey'

@app.route('/login')
def login():
    # Сохраняем данные в сессии
    session['user_id'] = 123
    session['username'] = 'Alice'
    return 'Вы вошли в систему!'

@app.route('/profile')
def profile():
    # Читаем данные из сессии
    user_id = session.get('user_id')
    username = session.get('username')
    if user_id and username:
        return f'Профиль пользователя {username} (ID: {user_id})'
    else:
        return redirect(url_for('login'))
  • session['key'] = value — сохраняет данные в сессии.
  • session.get('key') — читает данные из сессии. Если ключа нет, возвращается None.

Удаление данных сессии

Чтобы удалить данные из сессии, можно использовать метод pop().

@app.route('/logout')
def logout():
    # Удаляем данные из сессии
    session.pop('user_id', None)
    session.pop('username', None)
    return 'Вы вышли из системы!'
  • session.pop('key', None) удаляет ключ из сессии, если он существует. Если ключа нет, возвращается значение по умолчанию (None).

Проверка состояния сессии

Часто нужно проверить, авторизован ли пользователь, прежде чем предоставлять доступ к определенным страницам.

@app.route('/dashboard')
def dashboard():
    if 'user_id' in session:
        return 'Добро пожаловать в панель управления!'
    else:
        return redirect(url_for('login'))
  • Проверка наличия ключа в сессии (if 'key' in session) позволяет определить, есть ли у пользователя доступ.

Безопасные сессии

1. Использование секретного ключа

  • Секретный ключ (secret_key) должен быть уникальным и сложным.
  • Никогда не используйте простые строки, такие как '12345', в качестве секретного ключа.
  • Храните секретный ключ в переменных окружения или конфигурационных файлах.

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

import os

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY', 'default_secret_key')

Защита от атак

  • HTTPS: Убедитесь, что ваше приложение работает через HTTPS, чтобы защитить данные сессии от перехвата.
  • Параметр httponly: По умолчанию Flask устанавливает флаг httponly=True для куков сессии, что предотвращает доступ к ним через JavaScript.
  • Параметр secure: Если сайт работает через HTTPS, убедитесь, что куки сессии отправляются только по защищенному соединению.
from flask import Flask, session

app = Flask(__name__)
app.config.update(
    SESSION_COOKIE_SECURE=True,  # Куки отправляются только по HTTPS
    SESSION_COOKIE_HTTPONLY=True  # Куки недоступны из JavaScript
)

Время жизни сессии

По умолчанию сессии в Flask являются временными и живут до закрытия браузера. Если вам нужно продлить время жизни сессии, используйте параметр permanent.

from datetime import timedelta

@app.route('/login_permanent')
def login_permanent():
    session.permanent = True  # Устанавливаем постоянную сессию
    app.permanent_session_lifetime = timedelta(minutes=30)  # Время жизни сессии
    session['user_id'] = 123
    return 'Вы вошли в систему на 30 минут!'

Объяснение: - session.permanent = True делает сессию постоянной. - app.permanent_session_lifetime задает время жизни сессии.


3) Хранение сессий в куках и на сервере

Существует два основных способа хранения данных сессии: 1. Хранение в куках (client-side sessions): Данные сессии шифруются и хранятся на стороне клиента. 2. Хранение на сервере (server-side sessions): Данные сессии хранятся на сервере, а клиенту отправляется только уникальный идентификатор.


Хранение сессий в куках (Client-Side Sessions)

Описание

  • Данные сессии шифруются и отправляются клиенту в виде куки.
  • Клиент отправляет эти данные обратно при каждом запросе.
  • Flask использует этот подход по умолчанию.

Преимущества

  • Простота: Нет необходимости настраивать дополнительное хранилище на сервере.
  • Масштабируемость: Сервер не хранит данные сессии, что упрощает горизонтальное масштабирование.
  • Быстродействие: Нет необходимости обращаться к базе данных или другому хранилищу для чтения данных сессии.

Недостатки

  • Ограничение размера: Размер куков ограничен (обычно до 4 КБ).
  • Безопасность: Если секретный ключ скомпрометирован, злоумышленник может расшифровать данные сессии.
  • Производительность: Шифрование и дешифрование данных добавляет накладные расходы.

Когда использовать

  • Для небольших объемов данных (например, ID пользователя или настроек).
  • В простых приложениях, где не требуется сложное управление состоянием.
  • При разработке приложений, которые должны легко масштабироваться.

Пример на Flask

from flask import Flask, session, redirect, url_for

app = Flask(__name__)
app.secret_key = 'supersecretkey'  # Установка секретного ключа

@app.route('/login')
def login():
    # Сохраняем данные в сессии
    session['user_id'] = 123
    session['username'] = 'Alice'
    return 'Вы вошли в систему!'

@app.route('/profile')
def profile():
    # Читаем данные из сессии
    user_id = session.get('user_id')
    username = session.get('username')
    if user_id and username:
        return f'Профиль пользователя {username} (ID: {user_id})'
    else:
        return redirect(url_for('login'))

@app.route('/logout')
def logout():
    # Удаляем данные из сессии
    session.pop('user_id', None)
    session.pop('username', None)
    return 'Вы вышли из системы!'

Хранение сессий на сервере (Server-Side Sessions)

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

Преимущества

  • Безопасность: Даже если злоумышленник получит доступ к идентификатору сессии, он не сможет прочитать данные.
  • Гибкость: Можно хранить большие объемы данных.
  • Контроль: Сервер полностью контролирует данные сессии.

Недостатки

  • Сложность: Требуется настройка дополнительного хранилища.
  • Масштабируемость: При использовании одного сервера данные сессии могут быть недоступны при переходе на другой сервер (решается через распределенные хранилища, такие как Redis).
  • Производительность: Чтение и запись данных требуют обращения к хранилищу.

Когда использовать

  • Для приложений с большими объемами данных сессии.
  • В приложениях, где важна безопасность (например, банковские системы).
  • При работе с распределенными системами, где используется общее хранилище сессий.

Пример на Flask с использованием Redis

Для хранения сессий на сервере можно использовать расширение Flask-Session, которое поддерживает различные хранилища, включая Redis.

pip install Flask-Session redis
from flask import Flask, session, redirect, url_for
from flask_session import Session
import redis

app = Flask(__name__)

# Настройка Redis
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_USE_SIGNER'] = True
app.config['SESSION_KEY_PREFIX'] = 'flask_session:'
app.config['SESSION_REDIS'] = redis.from_url('redis://localhost:6379')

# Инициализация Flask-Session
Session(app)

@app.route('/login')
def login():
    # Сохраняем данные в сессии
    session['user_id'] = 123
    session['username'] = 'Alice'
    return 'Вы вошли в систему!'

@app.route('/profile')
def profile():
    # Читаем данные из сессии
    user_id = session.get('user_id')
    username = session.get('username')
    if user_id and username:
        return f'Профиль пользователя {username} (ID: {user_id})'
    else:
        return redirect(url_for('login'))

@app.route('/logout')
def logout():
    # Удаляем данные из сессии
    session.clear()
    return 'Вы вышли из системы!'
  • Flask-Session интегрирует хранилище сессий с Redis.
  • Данные сессии хранятся на сервере, а клиенту отправляется только идентификатор.

Сравнение подходов

Критерий Client-Side Sessions Server-Side Sessions
Хранение данных На стороне клиента (куки) На стороне сервера
Размер данных Ограничен (до 4 КБ) Неограничен
Безопасность Зависит от секретного ключа Высокая
Масштабируемость Простая Сложная (требует Redis)
Производительность Быстрее Медленнее

4) Кеширование в Flask

Кэш (cache) — это временное хранилище данных, которое позволяет быстрее получать информацию, которую приходится часто запрашивать или вычислять.

Представь себе ситуацию:

У вас есть веб-приложение на Flask, которое делает какой-то тяжёлый расчёт или обращается к базе данных каждый раз, когда пользователь открывает страницу. Если этот результат не меняется часто, то зачем выполнять его повторно? Гораздо эффективнее сохранить результат один раз и просто возвращать его, пока он актуален.

Это и есть кеширование.


Зачем использовать кэш в Flask?

  1. Ускорение работы сайта: не нужно каждый раз выполнять одни и те же действия.
  2. Снижение нагрузки на сервер: меньше запросов к БД, меньше вычислений.
  3. Лучшая производительность: пользователи получают данные быстрее.

Как работает кэширование?

Когда мы запрашиваем какую-то информацию: - Сначала проверяем, есть ли она в кэше. - Если есть — возвращаем её оттуда. - Если нет — делаем нужные операции, сохраняем в кэш и уже потом возвращаем.


🔧 Виды кэша в Flask

Flask сам по себе не предоставляет готового механизма кэширования, но с помощью библиотеки Flask-Caching, это становится очень простым.

1. Установка Flask-Caching

pip install Flask-Caching

Типы кэша в Flask-Caching

Можно выбрать, где хранить кэш:

Тип Описание
NullCache Никакого кэша — полезно для тестирования
SimpleCache Хранит в оперативной памяти (подходит для локального тестирования)
FileSystemCache Сохраняет кэш в файлы на диске
RedisCache Использует Redis — мощная система кэширования, хороша в продакшене
MemcachedCache Использует Memcached — тоже популярный вариант

Пример использования Redis:

app.config['CACHE_TYPE'] = 'RedisCache'
app.config['CACHE_REDIS_URL'] = 'redis://localhost:6379/0'

Когда использовать кэш?

Используй кэш, когда: - Результат зависит от медленных операций (например, SQL-запросы, API-вызовы). - Данные редко меняются. - Можно позволить себе немного устаревшие данные.

Не стоит кэшировать: - Персонализированные данные (если они уникальны для каждого пользователя). - Информация, которая обновляется часто. - Админские страницы или формы с POST-запросами.


Очистка кэша

Иногда нужно очистить кэш вручную, например, после изменения данных в БД.

Есть несколько способов:

cache.clear()  # очищает весь кэш

Или очищение конкретного ключа:

cache.delete('my_key')  # удалить определённый ключ

Если используешь memoize, то ключ формируется на основе имени функции и аргументов.


📚 Полезные ссылки