Защита сервера MTA:SA — античит, ACL и безопасность
Защита сервера MTA:SA состоит не только из встроенного античита. Безопасный проект должен одновременно контролировать клиентские модификации, серверные события, права ACL, административные аккаунты, Lua-ресурсы, базу данных, сетевые порты и резервные копии.
Даже включённый античит не сможет предотвратить злоупотребление уязвимым Lua-кодом. Если сервер доверяет сумме денег, предмету, координатам или административной команде, полученным от клиента, нарушитель может попытаться вызвать разрешённое событие вручную и передать поддельные значения.
В руководстве рассмотрены настройка античита MTA:SA Server 1.6, защита triggerServerEvent, ограничение частоты событий, проверка новых ресурсов, настройка ACL, защита административных аккаунтов, логирование и восстановление после взлома.
Настройка прав пользователей и ресурсов:
Установка и проверка Lua-ресурсов:
Из чего состоит защита сервера MTA:SA
Надёжная защита строится из нескольких независимых уровней.
Уровень клиента
- встроенный античит MTA;
- минимальная версия клиента;
- контроль изменённых файлов GTA;
- обработка событий античита;
- проверка необычных перемещений;
- ограничение частоты удалённых событий.
Уровень Lua-кода
- проверка каждого аргумента от клиента;
- использование доверенной переменной
client; - проверка расстояния и состояния игрока;
- проверка денег, предметов и полномочий на сервере;
- запрет удалённого вызова служебных событий;
- ограничение частоты действий;
- журналирование подозрительных операций.
Уровень доступа
- отдельные ACL-группы персонала;
- минимальные права ресурсов;
- защита административных аккаунтов по serial;
- отдельные пароли для MTA, VPS и MySQL;
- ограничение webadmin;
- удаление доступа бывших сотрудников.
Уровень инфраструктуры
- сетевой экран;
- обновление операционной системы;
- работа MTA не от имени root;
- SSH-ключи;
- закрытый порт MySQL;
- резервные копии на другом сервере;
- контроль целостности ресурсов.
Отказ одного уровня не должен автоматически давать полный контроль над проектом.
Обновление MTA Server и клиентских версий
Старые серверные сборки могут не содержать новых исправлений безопасности, дополнительных проверок и событий диагностики.
Проверка версии
sver
Перед обновлением
- создайте копию всей серверной папки;
- сохраните
mtaserver.confиacl.xml; - создайте дамп MySQL;
- сохраните внутренние базы MTA;
- проверьте совместимость ресурсов;
- проверьте сторонние модули;
- протестируйте новую версию отдельно.
Не заменяйте автоматически
- рабочую конфигурацию;
- ACL;
- папку ресурсов;
- файлы с паролями;
- внутренние базы;
server-id.keys.
Новые параметры из шаблона mtaserver.conf лучше переносить в рабочий файл вручную после проверки их назначения.
Настройка встроенного античита MTA
Основные параметры находятся в:
mods/deathmatch/mtaserver.conf
Базовый безопасный фрагмент
<allow_gta3_img_mods>none</allow_gta3_img_mods>
<disableac></disableac>
<enablesd>31,32</enablesd>
<hideac>0</hideac>
<minclientversion></minclientversion>
<minclientversion_auto_update>1</minclientversion_auto_update>
<check_duplicate_serials>1</check_duplicate_serials>
<resource_client_file_checks>1</resource_client_file_checks>
Это пример общего направления настройки. Перед заменой значений сравните его с актуальным шаблоном своей серверной версии.
Параметр disableac
<disableac></disableac>
Внутри указывается список отключённых кодов античита через запятую. Пустое значение означает, что администратор не отключил перечисляемые обнаружения.
Не рекомендуется
<disableac>2,3,4,5,6,7,8</disableac>
Массовое отключение проверок уменьшает защиту и затрудняет диагностику.
Когда обнаружение можно временно отключить
- подтверждён конфликт с легальным программным обеспечением;
- проводится тест на закрытом сервере;
- создана собственная обработка через
onPlayerACInfo; - известны последствия отключения;
- изменение задокументировано;
- предусмотрен возврат прежней настройки.
Специальные обнаружения enablesd
<enablesd>31,32</enablesd>
Параметр включает дополнительные обнаружения, связанные с определёнными клиентскими изменениями и средствами автоматизации ввода.
Общие рекомендации
- оставляйте значение из актуального стандартного шаблона;
- не копируйте длинные списки с неизвестного форума;
- тестируйте изменение на обычных клиентах;
- предупреждайте игроков о запрещённых инструментах автоматизации;
- учитывайте специфику Role Play, Race и соревновательных режимов;
- не используйте обнаружение вместо серверного ограничения частоты.
Для защиты от спама команд всё равно необходим серверный rate limit. Автоматизация ввода лишь облегчает атаку, но уязвимость возникает из-за того, что сервер выполняет дорогое действие без ограничения.
Минимальная версия клиента
<minclientversion></minclientversion>
<minclientversion_auto_update>1</minclientversion_auto_update>
Автоматическое обновление минимальной версии помогает постепенно исключать устаревшие клиентские сборки.
Значения автоматического обновления
0— отключено;1— обновление с задержкой;2— немедленное обновление для строгих соревновательных серверов.
Для обычного публичного проекта разумно начинать со стандартного значения 1. Режим 2 может потребовать от игроков быстро перейти на новую сборку.
Ручное ограничение
<minclientversion>1.6.0-9.НЕОБХОДИМАЯ_СБОРКА.0</minclientversion>
Не копируйте демонстрационный номер. Используйте сборку, подтверждённую для установленной версии сервера.
Контроль модифицированных файлов GTA:SA
Запрет изменённого gta3.img
<allow_gta3_img_mods>none</allow_gta3_img_mods>
Изменённые модели и коллизии способны предоставить визуальное или физическое преимущество: убрать объект, изменить размер транспорта или препятствия.
Разрешение только модификаций персонажей
<allow_gta3_img_mods>peds</allow_gta3_img_mods>
Такой вариант подходит не каждому проекту. На соревновательном сервере безопаснее запрещать изменения, способные влиять на восприятие игрового мира.
Разрешение отдельного файла
<client_file
name="data/carmods.dat"
verify="0"
/>
Добавляйте исключение только после понимания, зачем оно необходимо. Не отключайте проверку всех клиентских файлов ради одной сборки GTA.
Вспомогательный ресурс acpanel
В стандартном наборе ресурсов MTA может присутствовать acpanel. Он помогает просматривать состояние дополнительных настроек античита и содержит базовый пример работы с информацией о модифицированных файлах.
Запуск
start acpanel
Перед использованием
- обновите стандартные ресурсы;
- проверьте права ACL;
- ограничьте доступ администраторами;
- изучите код обработчика;
- адаптируйте реакцию под правила проекта;
- не используйте автоматический постоянный ban без проверки.
Для публичного Role Play проекта полезнее сохранять сведения и отправлять уведомление старшему персоналу, чем немедленно применять максимальное наказание при любом нестандартном файле.
Обработка обнаружений античита
Событие onPlayerACInfo можно использовать для собственного журнала обнаружений.
local function formatDetectionList(detections)
local result = {}
if type(detections) ~= "table" then
return "unknown"
end
for _, detectionCode in ipairs(detections) do
result[#result + 1] = tostring(detectionCode)
end
return table.concat(result, ",")
end
addEventHandler("onPlayerACInfo", root,
function(detectedACList, d3d9Size, d3d9MD5, d3d9SHA256)
local playerName = getPlayerName(source)
local playerSerial = getPlayerSerial(source)
outputServerLog(
string.format(
"[ANTI-CHEAT] player=%s serial=%s detections=%s d3d9_size=%s d3d9_sha256=%s",
tostring(playerName),
tostring(playerSerial),
formatDetectionList(detectedACList),
tostring(d3d9Size),
tostring(d3d9SHA256)
)
)
end
)
В журнале полезно сохранять
- дату и время;
- аккаунт и персонажа;
- serial;
- IP-адрес;
- версию клиента;
- коды обнаружений;
- хеш нестандартной библиотеки;
- повторяемость события;
- принятое решение администратора.
Не публикуйте полный технический журнал в открытом доступе.
Защита от спама triggerServerEvent
MTA позволяет контролировать количество клиентских событий за установленный интервал:
<player_triggered_event_interval>1000</player_triggered_event_interval>
<max_player_triggered_events_per_interval>100</max_player_triggered_events_per_interval>
При превышении порога вызывается событие onPlayerTriggerEventThreshold.
Безопасный обработчик журнала
local eventThresholdViolations = {}
addEventHandler("onPlayerTriggerEventThreshold", root,
function(eventName)
local player = source
eventThresholdViolations[player] =
(eventThresholdViolations[player] or 0) + 1
outputServerLog(
string.format(
"[EVENT SPAM] player=%s serial=%s event=%s violations=%d",
getPlayerName(player),
getPlayerSerial(player),
tostring(eventName),
eventThresholdViolations[player]
)
)
if eventThresholdViolations[player] >= 3 then
kickPlayer(
player,
"Server protection",
"Превышен лимит серверных событий"
)
end
end
)
addEventHandler("onPlayerQuit", root,
function()
eventThresholdViolations[source] = nil
end
)
Слишком низкий лимит может затронуть
- сложный интерфейс;
- инвентарь;
- редактор персонажа;
- систему строительства;
- массовое взаимодействие с предметами;
- плохо оптимизированный, но легальный ресурс.
Обнаружение необычной телепортации
<player_teleport_alert>100</player_teleport_alert>
Когда позиция игрока неожиданно изменяется на расстояние больше установленного порога без обычного серверного перемещения, сервер может вызвать onPlayerTeleport.
Журнал события
addEventHandler("onPlayerTeleport", root,
function(previousX, previousY, previousZ, currentX, currentY, currentZ)
outputServerLog(
string.format(
"[TELEPORT ALERT] player=%s serial=%s from=%.2f,%.2f,%.2f to=%.2f,%.2f,%.2f",
getPlayerName(source),
getPlayerSerial(source),
previousX,
previousY,
previousZ,
currentX,
currentY,
currentZ
)
)
end
)
Не выдавайте постоянный ban только по одному уведомлению. Проверьте лаг, падение под карту, перемещение транспортом, работу интерьеров и собственные скрипты телепортации.
Проверка повторяющихся serial
<check_duplicate_serials>1</check_duplicate_serials>
Настройка запрещает одновременное подключение нескольких игроков с одинаковым serial.
Отключение может требоваться для некоторых виртуальных сред, однако на обычном публичном сервере стандартное включённое значение добавляет дополнительную проверку подключений.
Проверка файлов ресурсов
<resource_client_file_checks>1</resource_client_file_checks>
При включённой настройке сервер проверяет клиентские файлы ресурсов с расширениями PNG, TXD и DFF и сообщает о повреждённых или несоответствующих файлах.
Отключение может потребоваться только в специальных случаях, когда ресурс намеренно хранит нестандартные данные под таким расширением.
Защита triggerServerEvent
Клиентский Lua-код находится на компьютере игрока. Поэтому любое разрешённое удалённое событие необходимо считать потенциально вызываемым вручную.
Небезопасное событие
addEvent("shop:buyVehicle", true)
addEventHandler("shop:buyVehicle", root,
function(vehicleModel, price)
takePlayerMoney(source, price)
createVehicle(
vehicleModel,
0,
0,
5
)
end
)
Проблемы
sourceможно подделать;- цену передаёт клиент;
- модель не проверяется;
- не проверяется местоположение;
- не проверяется баланс;
- нет ограничения частоты;
- не проверяется результат операции.
Безопасный принцип
Клиент должен сообщать только своё намерение:
triggerServerEvent(
"shop:buyVehicle",
localPlayer,
selectedVehicleId
)
Цена, модель, наличие товара, баланс и координаты магазина определяются сервером.
Каким данным клиента можно доверять
Доверенная переменная
client
В серверном обработчике удалённого события она указывает игрока, который действительно отправил вызов.
Не следует без проверки доверять
source;- элементу игрока в аргументах;
- цене;
- количеству денег;
- идентификатору предмета;
- координатам;
- расстоянию;
- уровню администратора;
- результату клиентского расчёта;
- времени выполнения действия;
- любой Lua-таблице клиента.
Базовая проверка источника
if not client or client ~= source then
return
end
Для некоторых событий в качестве source используется resourceRoot. Тогда проверяйте client отдельно и не предполагайте, что source является игроком.
Проверка аргументов клиентского события
Безопасная покупка транспорта
local VEHICLES = {
[1] = {
model = 411,
price = 500000
},
[2] = {
model = 426,
price = 500000
},
[2] = {
model = 426,
price = 75000
}
}
local SHOP_POSITION = {
x = 2131.5,
y = -1150.2,
z = 24.0
}
addEvent("shop:buyVehicle", true)
addEventHandler("shop:buyVehicle", root,
function(vehicleId)
if not client or client ~= source then
return
end
vehicleId = tonumber(vehicleId)
if not vehicleId then
return
end
vehicleId = math.floor(vehicleId)
local vehicleData = VEHICLES[vehicleId]
if not vehicleData then
return
end
local x, y, z = getElementPosition(client)
local distance = getDistanceBetweenPoints3D(
x,
y,
z,
SHOP_POSITION.x,
SHOP_POSITION.y,
SHOP_POSITION.z
)
if distance > 10 then
return
end
local playerMoney = getPlayerMoney(client)
if playerMoney < vehicleData.price then
return
end
takePlayerMoney(
client,
vehicleData.price
)
local vehicle = createVehicle(
vehicleData.model,
SHOP_POSITION.x + 5,
SHOP_POSITION.y,
SHOP_POSITION.z
)
if not vehicle then
givePlayerMoney(
client,
vehicleData.price
)
return
end
outputServerLog(
string.format(
"[VEHICLE PURCHASE] player=%s serial=%s vehicle=%d price=%d",
getPlayerName(client),
getPlayerSerial(client),
vehicleId,
vehicleData.price
)
)
end
)
Сервер проверяет
- отправителя события;
- тип идентификатора;
- существование товара;
- расстояние до магазина;
- цену из серверной таблицы;
- реальный баланс;
- успешное создание элемента;
- возврат денег при ошибке;
- запись операции в журнал.
Собственное ограничение частоты действий
Общий порог событий защищает сервер целиком, но отдельным дорогим операциям нужен собственный лимит.
local actionCooldowns = {}
local function isActionAllowed(player, actionName, delay)
if not isElement(player) then
return false
end
local now = getTickCount()
actionCooldowns[player] =
actionCooldowns[player] or {}
local availableAt =
actionCooldowns[player][actionName] or 0
if now < availableAt then
return false
end
actionCooldowns[player][actionName] =
now + delay
return true
end
addEventHandler("onPlayerQuit", root,
function()
actionCooldowns[source] = nil
end
)
Использование
addEvent("inventory:moveItem", true)
addEventHandler("inventory:moveItem", root,
function(fromSlot, toSlot)
if not client or client ~= source then
return
end
if not isActionAllowed(
client,
"inventory:moveItem",
250
) then
return
end
-- Проверка слотов и операция на сервере
end
)
Ограничивайте отдельно
- авторизацию;
- регистрацию;
- покупки;
- перемещение предметов;
- отправку репортов;
- телепортацию;
- создание транспорта;
- запрос больших списков;
- административные действия.
События только для серверной стороны
Событие, которое не должно вызываться клиентом, регистрируйте с запретом удалённого вызова:
addEvent(
"server:saveAllPlayers",
false
)
addEventHandler(
"server:saveAllPlayers",
resourceRoot,
function()
saveAllPlayers()
end
)
Небезопасно
addEvent(
"server:saveAllPlayers",
true
)
Значение true разрешает клиентам пытаться вызвать событие через triggerServerEvent.
Не используйте названия стандартных событий MTA
Не создавайте собственное удалённое событие с названием:
onPlayerLogin
onPlayerJoin
onPlayerQuit
onPlayerWasted
Используйте уникальный префикс ресурса:
accounts:requestLogin
inventory:moveItem
vehicles:requestPurchase
Защита административных событий
Административная операция должна проверять отдельное ACL-право.
local ADMIN_RIGHT =
"resource.admin_tools.giveMoney"
addEvent("admin:giveMoney", true)
addEventHandler("admin:giveMoney", root,
function(targetPlayer, amount)
if not client or client ~= source then
return
end
if not hasObjectPermissionTo(
client,
ADMIN_RIGHT,
false
) then
outputServerLog(
string.format(
"[SECURITY] unauthorized_admin_event player=%s serial=%s event=admin:giveMoney",
getPlayerName(client),
getPlayerSerial(client)
)
)
return
end
if not isElement(targetPlayer)
or getElementType(targetPlayer) ~= "player" then
return
end
amount = tonumber(amount)
if not amount then
return
end
amount = math.floor(amount)
if amount < 1 or amount > 100000 then
return
end
givePlayerMoney(
targetPlayer,
amount
)
outputServerLog(
string.format(
"[ADMIN] admin=%s target=%s action=giveMoney amount=%d",
getPlayerName(client),
getPlayerName(targetPlayer),
amount
)
)
end
)
Третий аргумент false в hasObjectPermissionTo запрещает действие, если право не найдено.
Защита element data
Element data может синхронизироваться между клиентом и сервером, поэтому важные значения нельзя считать защищёнными только потому, что они находятся на элементе игрока.
Не храните как доверенные клиентские данные
- баланс;
- уровень администратора;
- стоимость предмета;
- владельца транспорта;
- результат оплаты;
- разрешение на команду;
- секретный токен;
- пароль базы.
Дополнительная защита MTA 1.6
<elementdata_whitelisted>1</elementdata_whitelisted>
При включении сервер игнорирует клиентские изменения element data, кроме специально разрешённых ключей.
Серверная таблица вместо element data
local securePlayerData = {}
local function setSecureBalance(player, balance)
if not isElement(player) then
return false
end
balance = tonumber(balance)
if not balance then
return false
end
securePlayerData[player] =
securePlayerData[player] or {}
securePlayerData[player].balance =
math.floor(balance)
return true
end
addEventHandler("onPlayerQuit", root,
function()
securePlayerData[source] = nil
end
)
Безопасная настройка ACL
ACL определяет, какие команды и защищённые функции доступны пользователям и ресурсам.
Опасная ошибка
<group name="Admin">
<acl name="Admin" />
<object name="user.*" />
<object name="resource.*" />
</group>
Маски предоставят административную группу всем аккаунтам и ресурсам.
Правильный подход
<group name="Admin">
<acl name="Moderator" />
<acl name="SuperModerator" />
<acl name="Admin" />
<acl name="RPC" />
<object name="resource.admin" />
<object name="user.ServerOwner" />
</group>
Для модераторов создайте отдельную группу
<group name="ProjectModerators">
<acl name="ProjectModeratorRights" />
<object name="user.ModeratorAlex" />
</group>
<acl name="ProjectModeratorRights">
<right name="command.mute" access="true" />
<right name="command.kick" access="true" />
<right name="command.ban" access="false" />
<right name="command.start" access="false" />
<right name="command.stop" access="false" />
<right name="command.shutdown" access="false" />
</acl>
После ручного изменения:
reloadacl
Минимальные права Lua-ресурсов
Не добавляйте неизвестный ресурс в группу Admin только потому, что он не запускается.
Запрос в meta.xml
<aclrequest>
<right
name="function.kickPlayer"
access="true"
/>
</aclrequest>
Просмотр запроса
aclrequest list resource_name
Разрешение одного права
aclrequest allow resource_name function.kickPlayer
Запрет
aclrequest deny resource_name function.kickPlayer
Не используйте без проверки
aclrequest allow resource_name all
Особенно опасные права
- изменение ACL;
- создание и удаление аккаунтов;
- запуск и остановка ресурсов;
- выключение сервера;
- изменение паролей;
- управление другими ресурсами;
- выполнение произвольного кода;
- удалённые HTTP-запросы к неизвестному адресу.
Как проверить ресурс перед установкой
1. Распакуйте архив отдельно
Не копируйте неизвестную сборку сразу в рабочую папку.
2. Откройте meta.xml
Проверьте:
- серверные Lua-файлы;
- клиентские файлы;
- зависимости;
- экспортируемые функции;
- ACL-запросы;
- подключаемые карты;
- нативные модули.
3. Найдите опасные функции
fetchRemote
loadstring
load
fileCreate
fileDelete
fileRename
addAccount
removeAccount
setAccountPassword
aclCreate
aclSetRight
aclGroupAddObject
startResource
stopResource
restartResource
shutdown
Само наличие функции не доказывает вредоносность, но её назначение должно быть понятно.
4. Проверьте внешние адреса
Ресурс не должен без объяснения:
- загружать Lua-код с внешнего сайта;
- отправлять пароли и данные игроков;
- отправлять содержимое файлов;
- запрашивать команды с удалённого сервера;
- подключаться к неизвестному API;
- создавать скрытый административный аккаунт.
5. Проверьте обфускацию
Большой нечитаемый код, длинные закодированные строки и динамическое выполнение не всегда являются вирусом, но значительно затрудняют аудит.
6. Запустите на тестовом сервере
- используйте отдельную базу;
- не добавляйте реальные пароли;
- не выдавайте полные ACL-права;
- контролируйте новые файлы;
- проверьте сетевые соединения;
- сравните ACL до и после запуска;
- просмотрите журналы.
Опасность DLL- и SO-модулей
Lua-ресурс ограничен возможностями MTA и ACL, а нативный модуль выполняет машинный код в операционной системе.
Модули указываются в mtaserver.conf
<module src="module_name.dll" />
<module src="module_name.so" />
Перед установкой модуля
- проверьте официальный источник;
- проверьте контрольную сумму;
- найдите открытый исходный код;
- проверьте совместимость архитектуры;
- проверьте цифровую подпись, если она существует;
- протестируйте на отдельном сервере;
- не запускайте файл из случайного архива.
Защита базы данных MySQL
Включите дополнительную защиту MTA
<database_credentials_protection>1</database_credentials_protection>
Она добавляет ограничения для ресурсов, использующих MySQL через dbConnect.
Не используйте root
Создайте отдельного пользователя:
CREATE USER 'mta_user'@'127.0.0.1'
IDENTIFIED BY 'СЛОЖНЫЙ_ПАРОЛЬ';
GRANT ALL PRIVILEGES
ON `mta_server`.*
TO 'mta_user'@'127.0.0.1';
Для удалённой базы
Разрешайте подключение только с IP сервера MTA:
CREATE USER 'mta_user'@'IP_MTA_СЕРВЕРА'
IDENTIFIED BY 'СЛОЖНЫЙ_ПАРОЛЬ';
Основные правила
- не открывайте порт 3306 всему интернету;
- не храните пароль в
client.luaилиshared.lua; - не отправляйте пароль через игровой чат;
- используйте заполнители
?в запросах; - создавайте отдельную базу для тестового сервера;
- регулярно меняйте доступ после ухода разработчиков;
- не публикуйте SQL-дампы с пользовательскими данными.
Защита административных аккаунтов
Отдельный аккаунт каждому сотруднику
addaccount TechnicalAdmin СЛОЖНЫЙ_ПАРОЛЬ
addaccount GameModerator ДРУГОЙ_ПАРОЛЬ
Один общий аккаунт не позволяет определить автора действия и безопасно отозвать доступ только у одного человека.
Защита группы Admin по serial
<auth_serial_groups>Admin</auth_serial_groups>
<auth_serial_http>1</auth_serial_http>
Попытка входа в защищённый аккаунт с другого serial блокируется до ручного подтверждения.
Управление привязанными serial
authserial ServerOwner list
Удаление последней авторизации:
authserial ServerOwner removelast
После ухода сотрудника
- удалите его из всех ACL-групп;
- удалите или заблокируйте аккаунт;
- смените общие пароли;
- отзовите SSH-доступ;
- измените пароль MySQL;
- отзовите токены ботов и API;
- проверьте установленные им ресурсы;
- просмотрите последние административные действия.
Защита webadmin
Веб-интерфейс предоставляет доступ к чувствительным функциям сервера. Не оставляйте его открытым без необходимости.
Основные параметры
<httpserver>1</httpserver>
<httpport>22005</httpport>
<httpdosthreshold>20</httpdosthreshold>
Меры защиты
- ограничьте TCP-порт доверенным IP;
- используйте serial-защиту HTTP-авторизации;
- не используйте простой административный пароль;
- не публикуйте адрес панели;
- отключите
webadmin, если он не нужен; - проверяйте журнал авторизации;
- не добавляйте случайные IP в исключения HTTP-защиты;
- используйте VPN для технического доступа.
Остановка неиспользуемого интерфейса
stop webadmin
stop resourcebrowser
stop resourcemanager
Перед остановкой убедитесь, что эти ресурсы не нужны другим системам проекта.
Безопасность VPS и Windows-сервера
Linux
- создайте отдельного пользователя
mtasa; - не запускайте процесс от имени root;
- используйте SSH-ключи;
- запретите вход root по паролю;
- устанавливайте обновления безопасности;
- ограничьте права на серверную папку;
- не храните резервные копии в публичном веб-каталоге;
- проверяйте новые задания cron и systemd.
Пример владельца папки
sudo chown -R mtasa:mtasa /home/mtasa/mta-server
Ограничение прав
chmod -R u=rwX,g=rX,o= /home/mtasa/mta-server
Windows
- создайте отдельного пользователя без прав администратора;
- ограничьте удалённый рабочий стол;
- включите сетевой экран;
- не отключайте защиту системы ради неизвестного модуля;
- проверяйте автозагрузку и планировщик заданий;
- установите обновления Windows;
- ограничьте доступ к папке сервера.
Панель игрового хостинга
- используйте уникальный пароль;
- включите двухфакторную авторизацию, если доступна;
- не передавайте основной аккаунт разработчику;
- создавайте отдельный ограниченный доступ;
- проверяйте активные сессии;
- удаляйте старые FTP-аккаунты.
Сетевой экран и необходимые порты
Открывайте только реально используемые порты.
Типичная конфигурация
| Назначение | Пример | Протокол |
|---|---|---|
| Игровое подключение | 22003 | UDP |
| HTTP-загрузка и webadmin | 22005 | TCP |
| ASE | Игровой порт + 123 | UDP |
| SSH | 22 или изменённый | TCP |
| MySQL | 3306 | TCP |
MySQL на одном VPS с MTA
Не открывайте 3306 наружу. Используйте:
127.0.0.1:3306
Удалённый MySQL
Разрешите порт только с IP MTA Server.
Пример UFW
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22003/udp
sudo ufw allow 22126/udp
sudo ufw allow from ДОВЕРЕННЫЙ_IP to any port 22 proto tcp
sudo ufw allow from ДОВЕРЕННЫЙ_IP to any port 22005 proto tcp
sudo ufw enable
sudo ufw status numbered
Журналы безопасности MTA Server
Основные файлы
mods/deathmatch/logs/server.log
mods/deathmatch/logs/server_auth.log
mods/deathmatch/logs/scripts.log
mods/deathmatch/logs/db.log
В server.log проверяйте
- неожиданный запуск или остановку ресурсов;
- новые аккаунты;
- неизвестные команды;
- частые подключения одного IP;
- ошибки модулей;
- уведомления античита;
- превышение порога событий;
- подозрительные телепортации.
В server_auth.log проверяйте
- неудачные входы в Admin;
- авторизацию с нового IP;
- вход бывшего сотрудника;
- подбор пароля;
- использование аккаунта в необычное время;
- HTTP-авторизацию.
Lua-ошибки
<scriptdebuglogfile>logs/scripts.log</scriptdebuglogfile>
<scriptdebugloglevel>2</scriptdebugloglevel>
MySQL
debugdb 1
Полный журнал запросов включайте только временно:
debugdb 2
Отключение:
debugdb 0
Резервное копирование сервера
Базовая функция MTA
<backup_path>backups</backup_path>
<backup_interval>3</backup_interval>
<backup_copies>10</backup_copies>
Базовые копии создаются во время запуска сервера. Если сервер долго не перезапускается, фактический интервал может оказаться больше указанного.
Базовая копия не заменяет
- дамп MySQL;
- копию на другом физическом сервере;
- копию после каждого крупного обновления;
- проверку восстановления;
- архив рабочих ресурсов;
- историю версий.
Дамп MySQL
mysqldump \
--single-transaction \
-h 127.0.0.1 \
-u mta_user \
-p \
mta_server \
> mta_server_backup.sql
Что сохранять
- папку
resources; mtaserver.conf;acl.xml;banlist.xml;- внутренние базы MTA;
- SQL-дамп;
- модули;
- файлы запуска;
server-id.keys;- список версий.
Правило нескольких копий
- рабочая копия на сервере;
- копия на другом VPS или хранилище;
- локальная копия владельца;
- отдельная копия перед обновлением.
Проверка восстановления
Периодически разворачивайте копию на тестовом сервере и проверяйте:
- запуск MTA;
- импорт MySQL;
- авторизацию;
- ACL;
- персонажей;
- имущество;
- загрузку клиентских файлов;
- административные команды.
Защита файла server-id.keys
Файл обычно расположен здесь:
mods/deathmatch/server-id.keys
Он используется механизмом защиты приватных клиентских файлов, созданных с путём, начинающимся с @.
Обязательно
- сохраните отдельную резервную копию;
- не публикуйте файл;
- не передавайте его вместе с демонстрационной сборкой;
- ограничьте права файловой системы;
- восстанавливайте его вместе с сервером;
- не заменяйте файлом другого проекта без причины.
Потеря ключа может нарушить доступ к ранее созданным приватным клиентским файлам.
Что делать после взлома или подозрительной активности
1. Ограничьте доступ
- закройте сервер временным паролем;
- остановите подозрительный ресурс;
- отключите webadmin;
- заблокируйте подозрительные IP;
- отзовите скомпрометированный аккаунт;
- не удаляйте журналы.
2. Сохраните доказательства
- скопируйте все логи;
- сохраните текущий
acl.xml; - сохраните подозрительные ресурсы;
- запишите список процессов;
- сохраните список сетевых соединений;
- зафиксируйте время инцидента;
- создайте снимок VPS, если доступно.
3. Смените доступы
- аккаунты MTA;
- панель хостинга;
- SSH и удалённый рабочий стол;
- MySQL;
- электронную почту;
- FTP и SFTP;
- токены Telegram и Discord;
- ключи сторонних API.
4. Проверьте ACL
Ищите неизвестные строки:
<object name="user.UnknownAccount" />
<object name="resource.unknown_resource" />
Проверяйте опасные права:
<right
name="general.ModifyOtherObjects"
access="true"
/>
5. Проверьте файлы
- новые Lua-файлы;
- изменения
meta.xml; - неизвестные DLL и SO;
- внешние HTTP-запросы;
- автозагрузку операционной системы;
- cron и планировщик заданий;
- новые системные аккаунты;
- изменения конфигурации MySQL.
6. Восстановите чистую копию
Не продолжайте работу на сборке, целостность которой невозможно подтвердить. Разверните проверенную резервную копию, обновите сервер, смените все доступы и только затем возвращайте публичный режим.
Контрольный список защиты MTA:SA
Античит
disableacне содержит необоснованных исключений;enablesdсоответствует актуальному шаблону;- минимальная клиентская версия обновляется;
- модифицированные файлы контролируются;
- уведомления античита записываются;
- превышение порога событий отслеживается.
Lua-код
- используется доверенная переменная
client; - каждый аргумент проверяется;
- цены и деньги рассчитываются сервером;
- есть ограничение частоты;
- служебные события имеют
allowRemoteTrigger=false; - административные действия проверяют ACL;
- важные операции записываются в журнал.
Ресурсы и ACL
- неизвестные ресурсы не находятся в Admin;
- ACL-запросы разрешены выборочно;
- нет маски
resource.*в привилегированной группе; - каждый сотрудник имеет отдельный аккаунт;
- права бывших сотрудников удалены;
- модули получены из проверенного источника.
Инфраструктура
- MTA не работает от root;
- открыты только нужные порты;
- MySQL закрыта от общего интернета;
- webadmin ограничен;
- операционная система обновляется;
- пароли уникальны;
- административная группа защищена по serial.
Резервные копии
- копии создаются регулярно;
- MySQL сохраняется отдельно;
server-id.keysсохранён;- есть копия вне VPS;
- проверено реальное восстановление;
- создаётся копия перед каждым обновлением.
Частые вопросы по защите MTA:SA
Достаточно ли встроенного античита MTA?
Нет. Он является важным уровнем защиты, но серверный Lua-код всё равно должен проверять события, аргументы, деньги, права и частоту действий.
Нужно ли заполнять disableac?
Без подтверждённой необходимости оставьте его пустым. Отключение обнаружений уменьшает защиту.
Что означает enablesd?
Параметр включает специальные дополнительные обнаружения. Используйте значения актуального шаблона и тестируйте изменения.
Можно ли автоматически банить за любое обнаружение?
Это риск ложных решений. Полезнее сохранять технические данные, учитывать повторяемость и действовать по правилам проекта.
Как защититься от спама triggerServerEvent?
Настройте общий порог событий и добавьте отдельные cooldown-ограничения для дорогих операций.
Можно ли доверять source?
В удалённом клиентском событии его можно подделать. Для определения отправителя используйте серверную переменную client.
Можно ли доверять цене от клиента?
Нет. Клиент передаёт только идентификатор товара, а цена и проверка баланса выполняются сервером.
Как защитить административное событие?
Проверьте client, отдельное ACL-право, типы аргументов, допустимый диапазон и запишите действие в журнал.
Что делает elementdata_whitelisted?
Сервер игнорирует клиентские изменения element data, кроме специально разрешённых ключей. Сначала проверьте совместимость ресурсов.
Можно ли добавить ресурс в Admin?
Технически возможно, но безопаснее выдать только конкретные права через aclrequest или отдельную ACL-группу.
Как понять, что ресурс вредоносный?
Проверьте внешние запросы, динамическое выполнение кода, работу с аккаунтами, ACL, файлами, модулями и необъяснимые разрешения.
Безопасен ли обфусцированный ресурс?
Обфускация не доказывает вредоносность, но мешает аудиту. Не выдавайте такому ресурсу расширенные права без доверенного источника.
Можно ли запускать неизвестную DLL?
Нет. Нативный модуль выполняет код операционной системы и требует особенно тщательной проверки.
Нужно ли открывать порт MySQL?
При локальной базе — нет. Для удалённой разрешайте подключение только с IP MTA Server.
Что защищает административный аккаунт по serial?
Вход с нового serial блокируется до ручного подтверждения владельцем или администратором.
Нужно ли держать webadmin включённым?
Только когда он используется. В остальных случаях ресурс можно остановить и закрыть HTTP-доступ.
Какие логи проверять после атаки?
server.log, server_auth.log, scripts.log, db.log и собственный журнал административных действий.
Сохраняет ли встроенный backup базу MySQL?
Для MySQL создавайте отдельный дамп. Не рассчитывайте только на базовую копию MTA.
Зачем сохранять server-id.keys?
Он используется для защиты приватных клиентских файлов и должен восстанавливаться вместе с сервером.
Что делать при подозрении на взлом?
Ограничьте доступ, сохраните доказательства, смените пароли, проверьте ACL и ресурсы, а затем восстановите проверенную чистую копию.
Официальная документация
Заключение
Защита MTA:SA должна сочетать встроенный античит, безопасный Lua-код, ограниченные ACL-права, защищённые административные аккаунты, сетевой экран, журналы и проверенные резервные копии.
Не доверяйте данным клиента. Переменная client определяет отправителя удалённого события, но остальные аргументы должны проверяться сервером: тип, диапазон, расстояние, баланс, состояние персонажа и ACL-права.
Не добавляйте неизвестные ресурсы в Admin и не разрешайте все запросы aclrequest. Особое внимание уделяйте внешним HTTP-запросам, динамическому выполнению кода и нативным DLL- или SO-модулям.
Регулярно проверяйте журналы авторизации, античита, Lua и MySQL. После подозрительной активности сначала сохраните доказательства, затем отзовите доступы и восстановите сервер из проверенной копии.
Резервные копии должны храниться вне рабочего VPS. Отдельно сохраняйте MySQL, конфигурацию, ACL, ресурсы, внутренние базы и файл server-id.keys.
Настройка прав пользователей и ресурсов:
Администрирование и обслуживание:
Оптимизация производительности:
Настройка главного конфигурационного файла:
Комментарии к инструкции
Обсудите решение, задайте вопрос или дополните инструкцию