Cheaty umożliwiają złośliwym klientom wywoływanie zdarzeń w dowolnym kontekście. Dowiedz się, jak zabezpieczyć komunikację klient-serwer, wdrożyć walidację po stronie serwera i skonfigurować zmienne bezpieczeństwa (convars) FXServer.
Zespół ds. anti-cheata zawsze stara się go ulepszać, ale czasami coś się prześlizgnie.
W tym poradniku postaramy się omówić kilka powszechnych praktyk, które możesz wdrożyć, aby zwiększyć bezpieczeństwo swojego serwera poprzez odpowiednie zabezpieczenie zdarzeń.
Cheaty mogą pozwalać klientowi na wywoływanie zdarzeń w dowolnym kontekście.
Mówiąc o kontekście, mamy na myśli to, że mogą one wywołać relację klient->serwer (poprzez TriggerServerEvent) lub zasób klienta->zasób klienta (poprzez TriggerEvent).
Podczas pracy ze zdarzeniami w Lua kluczowe jest ich prawidłowe rejestrowanie w zależności od tego, czy są wywoływane przez klienta, czy przez serwer.
Częstym błędem jest rejestrowanie zdarzeń serwerowych, które nie powinny być wywoływane przez klienta (lub odwrotnie), co może prowadzić do poważnych luk w zabezpieczeniach.
Używaj AddEventHandler, gdy zdarzenie ma być wywoływane w tym samym kontekście, czyli klient-klient lub serwer-serwer. Gwarantuje to, że zdarzenia nie są sieciowe i nie mogą być wywołane przez przeciwną stronę.
AddEventHandler("eventName", function(eventParam1, eventParam2)
-- Kod tutaj zostanie wykonany, gdy zdarzenie zostanie wywołane w tym samym kontekście.
end)Używaj RegisterNetEvent, gdy zdarzenie musi być wywoływane w różnych kontekstach, np. z klienta na serwer lub z serwera na klienta.
RegisterNetEvent("eventName", function(eventParam1, eventParam2)
-- Kod tutaj zostanie wykonany, gdy zdarzenie zostanie wywołane w różnych kontekstach.
end)Ten przykład dotyczy klienta, a jak wszystko po stronie klienta, nie jest to rozwiązanie niezawodne i może być zmanipulowane przez cheaterów.
Jeśli chcesz zablokować wykonanie z tego samego kontekstu (np. zapobiec wywołaniu przez klienta sieciowego zdarzenia typu serwer-serwer), powinieneś zarejestrować swoje zdarzenie i sprawdzić źródło nadawcy:
RegisterNetEvent("eventName", function(eventParam1, eventParam2)
-- Serwer wyśle identyfikator sieciowy `65535` dla zdarzeń z serwera
if source ~= 65535 then return end
end)Nawet jeśli zbudujesz silny anti-cheat, dodanie kontroli w zdarzeniach serwerowych czyni je znacznie bezpieczniejszymi. Jest to wysoce zalecana praktyka, choć nie zapobiega wszystkiemu. Poniżej dzielimy się kilkoma dobrymi wskazówkami.
Zapewnia to integralność i bezpieczeństwo środowiska gry.
Wszystkie poniższe przykłady zakładają użycie jakiegoś frameworka (takiego jak ESX, QB-Core itp.).
Ma to na celu pokazanie złych sposobów tworzenia zdarzeń, nigdy nie powinieneś tego robić. Bezpośrednie dodawanie przedmiotów użytkownikowi na podstawie jego własnych danych wejściowych jest zawsze złą praktyką: zawsze należy walidować dane wejściowe użytkownika.
RegisterNetEvent("job:givePlayerItem", function(item, count)
local ply = FX.GetPlayerFromSource(source)
-- Bezpośrednie dodawanie przedmiotów użytkownikowi na podstawie jego własnych danych wejściowych jest niebezpieczne!
ply.addItem(item, count)
end)Oto solidny wzorzec bezpieczeństwa. Serwer śledzi stan i koordynaty gracza oraz weryfikuje działania za pomocą ticków po stronie serwera, zamiast polegać wyłącznie na wyzwalaczach klienta.
-- losowa koordynata
local VALID_JOB_COORD = vector3(125.0, 111.1, 35.83)
local MAX_ITEM_COUNT = 10
-- losowa koordynata
local VALID_TURNIN_COORD = vector3(1888.0, 1254.1, 48.0)
local ITEM_NAME = 'log'
-- lista graczy z aktywnymi pracami
local activeJobs = {}
AddEventHandler("playerDropped", function ()
if not activeJobs[source] then return end
activeJobs[source] = nil
end)
function isPedWithinRange(ped, tgtCoords)
return #(GetEntityCoords(ped) - tgtCoords) < 15.0
end
-- obsługa zwiększania ilości przedmiotów po stronie serwera
CreateThread(function()
while true do
for src, data in pairs(activeJobs) do
local ped = GetPlayerPed(src)
-- jeśli nie są w zasięgu, nie chcemy dawać im przedmiotu
if isPedWithinRange(ped, VALID_JOB_COORD) then
-- daj im przedmiot, ale ogranicz go do MAX_ITEM_COUNT
data.itemCount = math.min(data.itemCount + 1, MAX_ITEM_COUNT)
end
end
-- przetwarzaj tick pracy raz na sekundę
Wait(1000)
end
end)
RegisterNetEvent("job:startJob", function()
local ped = GetPlayerPed(source)
-- jeśli są w odległości do 15 jednostek, wykonują pracę
if isPedWithinRange(ped, VALID_JOB_COORD) then
activeJobs[source] = {
itemCount = 0,
}
end
end)
RegisterNetEvent("job:givePlayerItem", function()
local ply = FX.GetPlayerFromSource(source)
-- jeśli nie mają aktywnej pracy, nie powinni tego wywoływać!
local jobData = activeJobs[source]
if not jobData then return end
local ped = GetPlayerPed(source)
-- nie są w zasięgu koordynatów oddawania, odrzuć ich zmiany
if not isPedWithinRange(ped, VALID_TURNIN_COORD) then return end
-- zresetuj dane przedmiotu, aby nie mogli go wywołać wielokrotnie
activeJobs[source] = nil
-- dodaj przedmioty użytkownikowi po walidacji serwerowej
ply.addItem(ITEM_NAME, jobData.itemCount)
end)Należy pamiętać, że poniższych ustawień nie powinno się modyfikować, chyba że dokładnie wiesz, co robisz. Zespół Cfx.re / Adhesive zawsze ciężko pracuje, aby zapobiegać cheaterom. Większość z tych funkcji będzie domyślnie włączona w wersjach kompilacji FXServer 8450 i wyższych.
Aktywowanie tych zmiennych convar prawdopodobnie spowoduje wyrzucenie gracza z następującym powodem: Connection to CNL timed out.
Wyrzucenie nie oznacza, że gracz automatycznie otrzyma Globalnego Bana. Zapewnia jednak silną wskazówkę dotyczącą niezawodności gracza, co jest niezwykle przydatne przy ocenie jego wiarygodności.
Dostarczone kody nie są przeznaczone do bezmyślnego kopiowania i wklejania. To tylko kilka wskazówek, jak zapobiegać niektórym działaniom, które mogą mieć miejsce na serwerze. Wymaga to pewnej wiedzy programistycznej. Zawsze możesz dołączyć do naszego Discorda, aby uzyskać dodatkową pomoc.