Roblox używa dystrybucyjnego systemu fizyki, w którym klienci mają opiekę nad fizyczną simulacją obiektów w ich kontrolach, zwykle postać gracza i niezakorzenione obiekty blisko tej postaci. Ponadto poprzez użycie oprogramowania stron trzecich, eksploatatorzy mogą wykonawać dowolny kod Lua na kliencie, aby manipulować ich modelem danych i dekom
Zbiorowo, to oznacza, że doświadczony eksploiter może potencjalnie wykonują kod do oszustw w gra, w tym:
- Teleportowanie ich własnego postaci wokół miejsce.
- Wystrzeliwanie niezabezpieczonych RemoteEvents lub wezwywanie RemoteFunctions, takich jak nagradzanie siebie przedmiotami bez ich zarabiania.
- Dostosowywanie Class.Humanoid.WalkSpeed|WalkSpeed ich postaci, aby poruszała się bardzo szybko.
Podczas gdy możesz zaimplementować ograniczone obrony projektu, aby złapać zwykłe ataki, bardzo zalecane jest, aby zaimplementować bardziej wiarygodne taktyki strony serwera, ponieważ serwer jest najwyższą autorytetem dla każdej bieżącej doświadczenia.
Taktyki projektowe obronne
Podstawowe decyzje o projektowaniu mogą służyć jako "pierwszy krok" środki bezpieczeństwa, aby zniechęcić do wykorzystywania exploitów. Na przykład w grze strzelczo-gry, gdzie gracze zdobywają punkty za zabijanie innych graczy, eksploiter może stworzyć zbiór botów teleportujących się do tego samego miejsca, aby mogły być szybko zabite za punkty. Ze względu na ten potencjalny exploit
Podejście | Przewidywalny wynik |
---|---|
Ścigaj boty, pisząc kod, który próbuje ich wykryć. | |
Zmniejsz lub całkowicie usuń zyski punktów za zabójstwa na nowo zaspawnowanych graczy. |
Podczas gdy projekt obronny oczywiście nie jest doskonałym lub kompletnym rozwiązaniem, może przyczynić się do szerszego podejścia bezpieczeństwa, wraz z mitigacją serwera.
Mitigacja stron serwera
O ile to możliwe, serwer powinien wydać ostateczny wyrok na to, co jest "prawdziwe" i co jest obecnym stanem świata. Klienty mogą oczywiście zapytać serwer o dokonanie zmian lub wykonanie akcji, ale serwer powinien zatwierdzić i zaakceptować każdą z tych zmian/akcji przed wdrożeniem wyników do innych graczy.
Poza niektórymi operacjami fizycznymi zmiany w modelu danych na klienta nie odzwierciedlają się na serwerze, więc główny droga atakowa jest często poprzez wydarzenia sieci, któreś zgłosiłeś za pomocą RemoteEvents i RemoteFunctions. Pamiętaj, że haker, który wykonuje własny kod na swoim klencie, mo
Weryfikacja typu czasu uruchomienia zdalnego
Jedną drogę ataku jest dla atakującego, aby wywołać RemoteEvents i RemoteFunctions z argumentami niezgodnego wpisywać. W niektórych scenariuszach może to powodować błąd kodu na serwerze słuchającym tych zdalnych do błędu w taki sposób, że jest to korzystne dla atakującego.
Podczas używania zdalnych wydarzeń/funkcji możesz zapobiec temu typowi ataku poprzez uwalidowanie typów przekazanych argumentów na serwerze. Moduł t, dostępny tutaj, jest przydatny do sprawdzania typu w ten sposób. Na przykład, załóż
Lokalny skrypt w StarterPlayerScripts
local ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")-- Przekaż kolor i pozycję części podczas wzywania funkcjilocal newPart = remoteFunction:InvokeServer(Color3.fromRGB(200, 0, 50), Vector3.new(0, 25, 0))if newPart thenprint("The server created the requested part:", newPart)elseif newPart == false thenprint("The server denied the request. No part was created.")end
Skrypt w ServerScriptService
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
local t = require(ReplicatedStorage:WaitForChild("t"))
-- Twórz wcześniej weryfikator typu, aby uniknąć niepotrzebnej nadmiernej wydajności
local createPartTypeValidator = t.tuple(t.instanceIsA("Player"), t.Color3, t.Vector3)
-- Utwórz nową część z przekazanymi właściwościami
local function createPart(player, partColor, partPosition)
-- Sprawdź przekazane argumenty
if not createPartTypeValidator(player, partColor, partPosition) then
-- Cicho zwracaj "false", jeśli checkowanie typu nie powiodło się tutaj
-- Podwyższanie błędu bez odliczania może być wykorzystane do spowolnienia serwera
-- Zamiast tego zapewnij opinię klienta!
return false
end
print(player.Name .. " requested a new part")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = workspace
return newPart
end
-- Zwiąż funkcję "createPart()" z wezwaniem funkcji zdalnej
remoteFunction.OnServerInvoke = createPart
Weryfikacja danych
Kolejnym atakiem, który może zainicjować hakerzy, jest wysyłanie technicznie poprawnych typów ale czynią je niezwykle dużymi, długimi lub w inny sposób nieznormalizowanymi. Na przykład, jeśli serwer musi wykonić drogie operacje na łańcuchu, który skala się z długości, haker może wysłać niezwykle duży lub nieznormalizowany łańcuch, aby spowolnić serwer.
Podobnie zarówno inf i NaN będą type() jako 1> number1>, ale obie mogą powodować poważne problemy, jeśli eksploiter wysyłuje je i nie są one prawidłowo przetwarzane poprzez funkcje takie jak obserwuje:
local function isNaN(n: number): boolean
-- NaN nigdy nie jest równy siebie
return n ~= n
end
local function isInf(n: number): boolean
-- Liczba może być -inf lub inf
return math.abs(n) == math.huge
end
Kolejnym powszechnym atakiem, który może wykonać eksploiter, jest wysyłanie tables zamiast Class.Instance . Złożone ładowania mogą imitować to, co byłoby w przeciwnym razie zwykłym odniesieniem do obiektu.
Na przykład, zapewniony z systemem w sklepie w czasie eksperymentu, gdzie dane przedmiotów, takie jak ceny, są przechowywane w NumberValue obiektach, haker może określić wszystkie inne czynniki, wykonując obserwujekroki:
Lokalny skrypt w StarterPlayerScripts
local ReplicatedStorage = game:GetService("ReplicatedStorage")local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")local payload = {Name = "Ultra Blade",ClassName = "Folder",Parent = itemDataFolder,Price = {Name = "Price",ClassName = "NumberValue",Value = 0, -- Można użyć również negatywnych wartości, co prowadzi do dawania waluty, a nie jej brania!},}-- Wyślij niechciany ładunek na serwer (ten zapis zostanie odrzucony)print(buyItemEvent:InvokeServer(payload)) -- Wyświetla "false Invalid item provided"-- Prześlij prawdziwy przedmiot na serwer (ten przedmiot przejdzie!)print(buyItemEvent:InvokeServer(itemDatafolder["Real Blade"])) -- Outputs "true" and remaining currency if purchase succeeds
Skrypt w ServerScriptService
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")
local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")
local function buyItem(player, item)
-- Sprawdź, czy przesłany przedmiot nie jest fałszywy i znajduje się w katalogu ItemData
if typeof(item) ~= "Instance" or not item:IsDescendantOf(itemDataFolder) then
return false, "Invalid item provided"
end
-- Następnie serwer może kontynuować przetwarzanie zakupu w oparciu o poniższy przykładowy przepływ
end
-- Zwiąż funkcję „buyItem()” z wezwaniem funkcji zdalnej
buyItemEvent.OnServerInvoke = buyItem
Wartościowe uwierzytelnienie
Oprócz weryfikacji typy i dane, powinieneś weryfikować wartości przesłane poprzez 2> Class.RemoteEvent|RemoteEvents2> i 5> Class.RemoteFunction|RemoteFunctions5>, zapewniając, że są one poprawne i logiczne
Sklep w trybie bez doświadczenia
Rozważaj system sklepu w grze z interfejsem użytkownika, na przykład menu wyboru produktu z przyciskiem "Kup". Gdy przycisk jest naciśnięty, możesz wejść w RemoteFunction pomiędzy klientem a serwerem, aby złożyć kupować. Jest jednak ważne, aby serwer, najbardziej wiarygodny kierown
Celowanie za pomocą broni
Scenerie walki wymagają szczególnej uwagi na uwalnianie wartości, szczególnie poprzez celowanie i potwierdzenie celowania.
Wyobraź sobie grę, w której gracz może wystrzelić laserowy promień na innego gracza. Zamiast klienta powiadomić serwer, aby zadać obrażenia, powinien powiedzieć serwerowi pozycję źródła strzału i pozycję części/pozycji, którą myśli, że dotknął. Następnie serwer może potwierdzić obserwuje:
Pozycja, którą klient zgłasza strzela z jest bliska charakterowi gracza na serwerze. Uwaga, że serwer i klient będą się nieco różnić ze względu na opóźnienie, więc dodatkowe tolerancja będzie wymagać zastosowania.
Pozycja, którą raportuje klient, uderzenie jest rozsądnie blisko pozycji części , którą raportuje, na serwerze.
Nie ma statycznych przeszkód między pozycją, którą klient zgłasza, że strzela, a pozycją, którą klient zgłasza, że strzela. Ta sprawdza zapewnia, że klient nie próbuje strzelać poprzez ściany. Uwaga, że powinno to tylko sprawdzać geometrię statyczną, aby uniknąć zgłaszanych przez klatkę piersiową rzutów. Dodatkowo można zaimplementować dalsze weryfikacje stron serwera jako następuje:
Śledź, kiedy gracz po raz ostatni wystrzelił swoją bronią i potwierdź, aby upewnić się, że nie strzela zbyt szybko.
Śledź ilość amunicji każdego gracza na serwerze i potwierdź, że grający strzelający ma wystarczająco amunicji, aby wykonać atak broni.
Jeśli wdrożyłeś zespoły lub system walki z botami, potwierdź, że hit character jest wróg, przeciwnik, nie członkiem zespołu.
Potwierdź, że gracz trafiony jest żywy.
Przechowuj stan uzbrojenia i gracza na serwerze i potwierdź, że nie zablokowano gracza do strzelania przez bieżącą akcję, taką jak ponowne ładowanie lub stan biegu.
Manipulacja magazynem danych
W doświadczeniach używając DataStoreService do zapisywania danych gracza, oszuści mogą wykorzystać nieprawidłowe dane i inne nieoznakowane metody, aby zapobiec, aby DataStore zapisał prawidłowo. To może być szczególnie wykorzystywane w doświadczeniach z wyposażenieprzed
Upewnij się, że wszystkie działania wykonane za pośrednictwem RemoteEvent lub RemoteFunction, które wpływają na dane gracza z wejścia klienta, są zsanizowane w oparciu o obserwujekwestie:
- Wartości Class.Instance nie można zapisać w Class.DataStore i nie powiodą się. Użyj weryfikacji typu aby zapobiec temu.
- DataStores mają ograniczenia danych . Strings długości dowolnej długości powinny być sprawdzane i/lub ograniczone, aby to uniknąć, wraz z zapewnieniem, że nie można dodać tabelom dowolnych nieskończonych kluczy.
- Indeksy tabel nie mogą być NaN lub nil . Przez przeglądarkę przetwarzane są wszystkie tabely i sprawdza się, czy wszystkie indeksy są poprawne.
- DataStores może otrzymywać tylko poprawne znaki UTF-8, więc powinieneś upewnić się, że wszystkie łańcuchy dostarczone przez klienta poprzez
Dystansowe sterowanie
Jeśli klient jest w stanie zrobić, aby twój serwer wykonał kosztowną operację obliczeniową lub uzyskał dostęp do usługi ograniczonej czasowo, takiej jak DataStoreService poprzez RemoteEvent , jest istotne, aby zaimplementować ograniczanie stóp, aby upewnić
Weryfikacja ruchu
Dla doświadczeń konkurencyjnych można chcieć zidentyfikować ruchy postaci gracza na serwerze, aby upewnić się, że nie teleportują się po mapie lub nie przesuwają się szybciej niż akceptowalne.
W ciągu 1 sekundy sprawdź nową lokalizację znaku z wcześniej zapisanej lokalizacji.
Porównaj rzeczywisty dystrybucja dystansu przeciwko dystrybucji tolerowalnej i postępuj zgodnie z poniższym:
- Dla do zniesienia Delta, zapisz nową lokalizację postaci w przygotowaniu do następnego zwiększonego sprawdzać.
- Dla nieoczekiwanego lub nieznośnego Delta (potencjalne wykorzystanie prędkości/teleportacji):
- Zwiększ wartość "liczby przestępstw" dla gracza względem kary za "źle pozytywne" wynikające z ekstremalnej latencji serwera lub innych czynników niezawinienia.
- Jeśli dochodzi do dużej liczby naruszeń w ciągu 30-60 sekund, Kick() gracza z doświadczenia całkowicie; w przeciwnym razie zresetuj liczbę naruszeń. Uwaga, że przy okazaniu kary za oszustwo należy zapisać wydarzenie, abyś mógł śledzić, ile osób jest dotkniętych.