RE:NODE

Безопасность10 мин чтения

Discord-боты для админов игрового сервера

Какие интеграции с Discord реально используют игровые серверы, как дать боту доступ к консоли, не отдавая Discord ваш RCON, и небольшой админ-бот на slash-командах.

0 прочтений

Discord-бот, который может выполнять команды на вашем игровом сервере, - это удалённая консоль, паролем к которой служит «нужная роль в Discord». Это может быть вполне хорошей архитектурой - команда и так живёт в Discord, а кикнуть грифера с телефона действительно полезно, - но только если бот выполняет короткий белый список команд, а не всё, что ему напишут, проверяет роли при каждой команде, имеет минимальные права в Discord, с которыми он может работать, логирует каждое использование и держит свой токен и пароль RCON вне досягаемости. Для одностороннего трафика вроде статуса и оповещений вебхук проще и безопаснее любого бота.

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

Вебхук, интеграция или собственный бот#

Выбирайте наименее мощный инструмент, который справляется с задачей.

ЗадачаИнструментМожет ли он изменить сервер?
Статус, оповещения, объявления о входеВебхукНет
Мост чата между игрой и DiscordИнтеграция на стороне игрыТолько в пределах чата
Консоль в канале DiscordИнтеграция на стороне игрыДа, всё
Заявки в белый список, кики, несколько командАдмин-бот с белым списком командТолько то, что вы разрешили
Модерация самого DiscordDiscord AutoMod, бот-модераторНет, только Discord

Вебхук умеет только публиковать. У него нет учётных данных от вашего игрового сервера, поэтому худшее, что может сделать утёкший URL вебхука, - заспамить один канал. Это делает его правильным выбором для всего одностороннего: эмбедов со статусом, оповещений о крашах, уведомлений о перезапуске, объявлений о банах.

Бот - это постоянно работающая программа, подключённая к Discord с токеном, и она может делать всё, что позволяют её код и её права. Как только она получает возможность говорить с консолью игрового сервера, её безопасность становится так же важна, как безопасность вашего пароля RCON.

Интеграции, которые обычно используют игровые серверы#

У большинства популярных игр есть проверенная интеграция, и использовать её обычно лучше, чем писать свою.

  • Minecraft - DiscordSRV. Плагин на сервере, который соединяет игровой чат с каналом Discord, связывает аккаунты Discord и Minecraft, синхронизирует роли и может зеркалировать консоль в канал, где сообщения выполняются как команды. Над последней функцией стоит хорошо подумать. Настройка описана в статье DiscordSRV для Minecraft.
  • FiveM - txAdmin. В txAdmin есть Discord-бот, который может публиковать постоянный эмбед со статусом сервера и обрабатывать заявки в белый список: игроки запрашивают доступ из Discord, а команда одобряет их в txAdmin. О самом txAdmin - в статье сервер FiveM и txAdmin, а о доступе по ролям - в статье права Discord и белый список в FiveM.
  • Игры на Source и CS2. Плагины SourceMod и CounterStrikeSharp обычно публикуют жалобы, баны и чат в Discord через вебхуки; сами действия администраторов остаются в игре.
  • Rust, DayZ, Arma и другие игры с RCON. Админ-инструменты и RCON-сервисы подключаются к серверу по RCON и часто имеют свои функции для Discord: килфиды, уведомления о банах, списки игроков. Они хранят ваш пароль RCON, поэтому заслуживают такой же проверки, как бот, написанный вами.
  • Универсальные боты статуса. Боты, которые опрашивают публичный порт статуса сервера и показывают, кто онлайн. Им не нужно ничего секретного, потому что эта информация публична. Что именно они читают, объяснено в статье query-порты и A2S.

Почему консольный бот - это RCON с другим замком#

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

TCP portчерез RCON или плагинКонсоль панелиаккаунт + 2FARCON-клиентодин общий парольБот Discordроль в DiscordКонсоль сервера
Три замка на одной консоли

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

Конкретные риски:

  • Повышение ролей внутри Discord. Любой с правом «Manage Roles» может выдать себе любую роль ниже собственной высшей роли. Если роль для консоли стоит низко в списке, добраться до неё может больше людей, чем вы думаете.
  • Зеркалированные каналы консоли. Канал, где каждое сообщение выполняется как консольная команда и который может читать и писать какая-то роль, - самая опасная из возможных конфигураций. К тому же он показывает вывод консоли, который в Minecraft содержит IP-адреса игроков при каждом входе.
  • Кража токена бота. Токен в публичном репозитории, вставленный куда-то конфиг или взломанный хостинг дают вору бота со всеми его правами в вашем Discord и всем, что он может сделать с вашим сервером. Discord сбрасывает токены, которые обнаруживает в публичных репозиториях GitHub, - это говорит о том, как часто такое случается.
  • Непроверенный ввод. Бот, который передаёт в консоль любой текст, введённый пользователем, позволяет склеивать команды и выполнять произвольные, даже если вы собирались разрешить только kick.

Правильные права с обеих сторон#

Со стороны Discord:

  1. Дайте боту собственную роль только с теми правами, которые он использует. Боту статуса или админ-боту обычно нужно видеть несколько каналов, отправлять сообщения и встраивать ссылки. Не давайте Administrator, Manage Server, Manage Roles и Manage Webhooks, если только они не нужны конкретной функции.
  2. Поставьте роль команды, которая управляет ботом, высоко в списке ролей и ограничьте круг тех, у кого есть Manage Roles, чтобы её нельзя было выдать себе самому.
  3. Используйте переопределения прав каналов, чтобы админ-команды бота работали только в канале команды.
  4. Требуйте двухфакторную аутентификацию для модерации в настройках безопасности сервера Discord - тогда Discord требует 2FA у аккаунтов, использующих права модерации.
  5. Используйте slash-команды с правами по умолчанию, чтобы команда была скрыта от людей без нужного права в Discord, если вы намеренно не измените это.

Со стороны игры:

  1. Дайте боту собственный пароль RCON, если игра это позволяет, или хотя бы пароль, отличный от того, которым пользуется команда, и меняйте его, когда бот переходит в другие руки.
  2. Используйте в боте белый список команд, а не чёрный. list, kick, whitelist add - нормально. Всё, что принимает в консоль произвольный текст (обычное исключение - say), требует проверки ввода.
  3. В играх с системой прав запускайте бота под ограниченной учётной записью. Плагины Minecraft вроде DiscordSRV умеют ограничивать консольные команды из Discord белым списком в своём конфиге; пользуйтесь этим, а не открытым доступом к консоли.
  4. Логируйте каждую команду, которую выполняет бот, вместе с пользователем Discord, который её запросил, в канал, который команда может читать, но не редактировать.

Подробнее о стороне RCON, в том числе о том, в каких играх его вообще можно ограничить, - в статье безопасный RCON.

Небольшой админ-бот, которому можно доверять#

Если вам нужно несколько админ-команд из Discord, а в вашей игре стандартный RCON в стиле Source (Minecraft, Rust в legacy-режиме, игры на Source и многие другие), бота такого размера достаточно, и его легко проверить. Он использует discord.py 2.x и пакет rcon из PyPI.

bot.py
import osimport discordfrom discord import app_commandsfrom rcon.source import rconGUILD = discord.Object(id=int(os.environ["GUILD_ID"]))LOG_CHANNEL = int(os.environ["LOG_CHANNEL_ID"])STAFF_ROLE = "Server Staff"ALLOWED = {"list", "kick", "whitelist"}client = discord.Client(intents=discord.Intents.default())tree = app_commands.CommandTree(client)async def run(*args: str) -> str:    return await rcon(*args, host=os.environ["RCON_HOST"],                      port=int(os.environ["RCON_PORT"]),                      passwd=os.environ["RCON_PASSWORD"])@tree.command(name="server", description="Run an allowed server command", guild=GUILD)@app_commands.default_permissions(kick_members=True)@app_commands.checks.has_role(STAFF_ROLE)async def server(interaction: discord.Interaction, command: str):    parts = command.split()    if not parts or parts[0] not in ALLOWED:        await interaction.response.send_message("Not allowed.", ephemeral=True)        return    await interaction.response.defer(ephemeral=True)    result = await run(*parts)    await interaction.followup.send(f"```\n{result[:1800]}\n```", ephemeral=True)    log = client.get_channel(LOG_CHANNEL)    if log:        await log.send(f"{interaction.user} ran `{command}`")@tree.errorasync def on_error(interaction: discord.Interaction, error):    if isinstance(error, app_commands.MissingRole):        await interaction.response.send_message("Staff only.", ephemeral=True)@client.eventasync def on_ready():    await tree.sync(guild=GUILD)client.run(os.environ["DISCORD_TOKEN"])

Что делает его достаточно безопасным:

  • Только slash-команды. Он никогда не читает обычные сообщения, поэтому ему не нужен привилегированный intent на содержимое сообщений, и никто не может вызвать его, просто написав что-то в канале.
  • Две проверки. default_permissions скрывает команду от участников без права Kick Members, а has_role отказывает всем без роли команды, даже если администратор сервера изменит видимость команды.
  • Белый список по первому слову. Выполняться могут только list, kick и whitelist. Добавляйте команды по одной и осознанно.
  • Аргументы передаются отдельно. Команда разбивается на слова и отправляется отдельными аргументами, а не вставляется в консоль одной строкой.
  • Каждое использование логируется в канал вместе с тем, кто выполнил команду.
  • Никаких секретов в коде. Токен, пароль RCON и ID берутся из переменных окружения.

Когда станет понятно, какими командами команда реально пользуется, расширяйте бота отдельными командами - /kick player reason с типизированными параметрами, - а не растущим белым списком для свободного текста.

Как отправлять логи в Discord и не допускать утечек#

Логи в Discord удобны, но это и проблема приватности: каналы Discord легко читать и легко скриншотить.

  • Отправляйте события, а не сырую консоль. «Anna забанила Steve: иксрей» - полезно. Сырое зеркало консоли включает IP-адреса, ошибки плагинов и всё остальное, что выводит сервер.
  • Держите логи команды в каналах команды и проверяйте права. Канал логов, случайно видимый @everyone, - частая причина того, что адреса игроков оказываются в открытом доступе.
  • Соблюдайте ограничения частоты. Discord ограничивает, как быстро бот или вебхук может публиковать сообщения; собирайте строки логов в одно сообщение раз в несколько секунд, а не по сообщению на строку. Обработка 429 описана в статье о вебхуках.
  • Не используйте Discord как архив логов. Настоящие логи остаются на сервере со сроком хранения - об этом статья логи, которые стоит хранить, а почему это важно, объяснено в статье приватность и данные игроков на игровом сервере.

Хостинг бота и его токен#

Боту нужно работать постоянно, а значит, он не должен жить на чьём-то игровом компьютере. Хватит небольшого тарифа для хостинга приложений: бот вроде описанного выше использует заметно меньше памяти, чем есть в самом маленьком тарифе. На RE:NODE линейки Python и Node.js начинаются с 1 ГБ, переменные окружения для токена и паролей задаются на вкладке Startup, а Git deploy может при запуске подтягивать код бота из приватного репозитория GitHub. Пошаговая инструкция - в статье хостинг бота на discord.py, а тарифы - на странице хостинга приложений.

Обращайтесь с токеном как с паролем:

  • Никогда не коммитьте его. Держите его в переменной окружения и добавьте локальный файл .env в .gitignore. Этот подход описан в статье переменные окружения и секреты.
  • Немедленно сбрасывайте его при утечке в портале разработчиков Discord. Старый токен сразу перестаёт работать.
  • Ограничьте круг тех, кто видит хостинг бота. Любой с доступом к файлам или настройкам сервера бота может прочитать его токен. Субпользователям панели можно дать доступ к консоли без доступа к настройкам и файлам.
  • Знайте, кому принадлежит приложение. Бот, принадлежащий личному аккаунту Discord одного члена команды, уйдёт вместе с ним. Команды разработчиков в Discord позволяют нескольким людям управлять приложением без общего аккаунта.

Если что-то пошло не так#

Если бот начал делать то, о чём никто не просил, или вы подозреваете, что его токен или пароль RCON утекли:

  1. Сбросьте токен бота в портале разработчиков.
  2. Смените пароль RCON на игровом сервере и обновите переменную окружения бота.
  3. Проверьте журнал аудита Discord на изменения ролей и прав, а канал логов бота - на незнакомые команды.
  4. Проверьте игровой сервер на записи администраторов, баны, изменения белого списка или файлы, которые вы не создавали. Полный порядок действий - в статье что делать, если ваш сервер взломали.

FAQ#

Безопасно ли пользоваться консольным каналом DiscordSRV?

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

Использовать в боте RCON или игровой плагин?

Плагин может интегрироваться глубже и часто имеет более тонкие права; RCON работает с любой игрой, которая его поддерживает, и держит бота отдельно от сервера. Для небольшого админ-бота RCON с белым списком команд проще проверить.

Можно ли запустить бота на том же тарифе, что и игровой сервер?

Запускайте его отдельно. Бот на собственном небольшом тарифе для приложений продолжает работать, когда игровой сервер перезапускается или падает, - как раз тогда, когда статус и оповещения нужнее всего, - и держит токен бота подальше от людей с доступом к файлам игрового сервера.

Нужен ли мне intent на содержимое сообщений?

Не для slash-команд. Это привилегированный intent, который нужен для чтения текста обычных сообщений. Боту, который использует только slash-команды, он не нужен, и без него бот безопаснее.

Какие права нужны боту статуса?

Просмотр канала, отправка сообщений и встраивание ссылок, а также чтение истории сообщений, если он редактирует собственное сообщение. Ему не нужно ничего, что касается ролей, участников или настроек сервера.


Комментарии

Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.

0/2000