Roblox utilizza un sistema fisico distribuito in cui i client hanno la custodia su la simulazione fisica degli oggetti nel loro controllo, di solito il personaggio del Giocatoree gli oggetti non ancorati vicino a quel personaggio. Inoltre, attraverso l'uso di codice di terze parti, gli exploiter possono eseguire codice Lua arbitrario sul client per manipolare il modello di dati del loro client e decompilare e visualizzare il codice in esecuzione su di esso.
Collettivamente, questo significa che un esperto hacker potrebbe potenzialmente eseguire il codice per truffare nel tuo Gioco, tra cui:
- Teletrasportare il loro personaggio intorno al Posto.
- Sparare un'RemoteEvents non sicuri o invocare un'RemoteFunctions , come per esempio assegnarsi oggetti senza guadagnarli.
- Regolando la loro caratteristica WalkSpeed in modo che si muova davvero velocemente.
Mentre puoi implementare limitate difese di design per catturare gli attacchi comuni, è altamente raccomandato che tu implementi più affidabili tattiche di mitigazione lato server, poiché il server è l'autorità finale per qualsiasi esperienza in esecuzione.
Tattiche di design difensivo
Le decisioni di base del design possono servire come misure di sicurezza "primo passo" per dissuadere gli exploit. Ad esempio, in un gioco shooter in cui i giocatori ottengono punti per uccidere altri giocatori, un exploiter può creare un insieme di bot che si teletrasporta nello stesso luogo in modo che possano essere rapidamente uccisi per i punti. Data questa potenziale Sfruttare, considera due approcci e il loro risultato prevedibile:
Avvicinamento | Risultato prevedibile |
---|---|
Insegui i bot scrivendo codice che tenta di rilevare loro. | |
Riduci o elimina completamente i guadagni di punti per le uccisioni sui giocatori appena spawnati. |
Mentre il design difensivo ovviamente non è una soluzione perfetta o completa, può contribuire a un approccio di sicurezza più ampio, insieme a mitigazione lato server.
Mitigazione lato server
Il più possibile, il server dovrebbe esprimere il verdetto finale su ciò che è "vero" e su quale sia lo stato attuale del mondo. I client possono, naturalmente, richiedere al server di fare cambiamenti o eseguire un'azione, ma il server dovrebbe valutare e approvare ogni di questi cambiamenti / azioni prima che i risultati siano replicati ad altri giocatori.
A parte alcune operazioni fisiche, le modifiche al modello di dati sul client non si replicano sul Server, quindi la principale strada d'attacco è spesso tramite gli eventi di rete che hai dichiarato con RemoteEvents e RemoteFunctions . Ricorda che un exploiter che esegue il proprio codice sul tuo client può invocarli con i dati che vuole.
Validazione del tipo di runtime remoto
One attack path is for an exploiter to invite RemoteEvents and RemoteFunctions with arguments of the incorrect inserisci / scrivi. In some scenarios, this may cause code on the server listening to these remotes to error in a way that's advantageous to the exploiter.
Quando si utilizzano eventi/funzioni remote, puoi prevenire questo tipo di attacco validando i tipi di argomenti passati sul Server. Il modulo t", disponibile qui, è utile per il tipo di controllo in questo modo. Ad esempio, supponendo che il codice del modulo esiste come 2> Class.ModuleScript
Script locale in StarterPlayerScripts
local ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")-- Passa il colore e la posizione della parte quando invochi la funzionelocal 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
Script nel ServerScriptService
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
local t = require(ReplicatedStorage:WaitForChild("t"))
-- Crea un validatore di tipo in anticipo per evitare l'Overhead inutto
local createPartTypeValidator = t.tuple(t.instanceIsA("Player"), t.Color3, t.Vector3)
-- Crea una nuova parte con le proprietà passate
local function createPart(player, partColor, partPosition)
-- Controlla gli argomenti passati
if not createPartTypeValidator(player, partColor, partPosition) then
-- Ritorna silenziosamente "false" se il tipo di check non funziona qui
-- Alzare un errore senza un cooldown può essere abusato per rallentare il Server
-- Ruota invece il feedback del client!
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
-- Abbindare "createPart()" al Richiamadella funzione remota
remoteFunction.OnServerInvoke = createPart
Validazione dei dati
Un altro attacco che gli exploiter potrebbero lanciare è inviare tipi validi tecnicamente ma renderli estremamente grandi, lunghi o altro non conformi. Ad esempio, se il server deve eseguire un'operazione costosa su una corda che si adatta alla lunghezza, un exploiter potrebbe inviare una corda estremamente grande o malformata per rallentare il Server.
Similmente, sia inf che NaN``Global.LuaGlobals.type() come 1> number1> , ma entrambi possono causare problemi principali se un exploiter li invia e non vengono gestiti correttamente attraverso funzioni come le Seguendo:
local function isNaN(n: number): boolean
-- NaN non è mai uguale a se stesso
return n ~= n
end
local function isInf(n: number): boolean
-- Il numero potrebbe essere -inf o inf
return math.abs(n) == math.huge
end
Un altro attacco comune che gli esploiatori possono utilizzare coinvolge l'invio di tables invece di un Instance . I complessi payload possono imitare ciò che sarebbe un riferimento di oggetto altrimenti comune.
Ad esempio, fornito con un sistema in-experience shop in cui i dati degli articoli come i prezzi vengono memorizzati in NumberValue oggetti, un exploiter può bypassare tutti gli altri controlli facendo quanto Seguendo:
Script locale in 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, -- I valori negativi potrebbero essere utilizzati, il che comporta la consegna della valuta invece che prenderla!},}-- Invia malicious payload al server (questo sarà rifiutato)print(buyItemEvent:InvokeServer(payload)) -- Outputs "false oggetto non fornito"-- Invia un oggetto reale al server (andrà attraverso!)print(buyItemEvent:InvokeServer(itemDatafolder["Real Blade"])) -- Outputs "true" and remaining currency if purchase succeeds
Script nel ServerScriptService
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")
local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")
local function buyItem(player, item)
-- Controlla se l'elemento passato non sia spoofed e sia nella cartella ItemData
if typeof(item) ~= "Instance" or not item:IsDescendantOf(itemDataFolder) then
return false, "Invalid item provided"
end
-- Il server può quindi continuare il processo d'acquisto in base al flusso di esempio qui sotto
end
-- associare "buyItem()" al Richiamadella funzione remota
buyItemEvent.OnServerInvoke = buyItem
Validazione dei valori
Oltre a validare tipi e dati, dovresti validare i valori passati attraverso 1> Class.RemoteEvent|RemoteEvents1> e 4> Class.RemoteFunction|RemoteFunctions4>, assicurandoti che siano validi e logici nel contesto richiesto. Due esempi comuni
Negozio In-Experience
Considera un sistema di negozio in-experience con un'interfaccia utente, ad esempio un menu di selezione di un prodotto con un pulsante "Acquista". Quando viene premuto il pulsante, puoi invocare un RemoteFunction tra il client e il server per richiedere l'Articolo. Tuttavia, è importante che il servers, il gestore più affidabile dell'esperienza, confermi che l'utente ha
Targeting delle armi
Gli scenario di combattimento richiedono l'attenzione speciale per la validazione dei valori, in particolare attraverso la validazione della mira e del colpo.
Immagina un gioco in cui un giocatore può sparare un raggio laser ad un altro Giocatore. Invece che il cliente dica al server chi sta danneggiando, dovrebbe invece dire al server la posizione di origine del colpo e la posizione/posizione che pensa di aver colpito. Il server può quindi validare il Seguendo:
La posizione che il client segnala spara dal è vicino al personaggio del Giocatoresul Server. Nota che il server e il client differiscono leggermente a causa della latenza, quindi è necessario applicare una tolleranza extra.
La posizione che il client segnala colpendo è ragionevolmente vicino alla posizione della parte colpita dal client che segnala colpendo, sul Server.
Non ci sono ostacoli statici tra la posizione in cui il client segnala di aver sparato e la posizione in cui il client segnala di aver sparato. Questo controllo garantisce che un client non stia tentando di sparare attraverso i muri. Nota che questo dovrebbe controllare solo la geometria statica per evitare che i colpi validi vengano rifiutati a causa della latenza. Inoltre , potresti voler implementare ulteriori convalida lato server come segue:
Traccia quando l'ultimo giocatore ha sparato con l'arma e validi per assicurarti che non stanno sparando troppo velocemente.
Traccia la quantità di munizioni di ogni Giocatoresul server e conferma che un giocatore in grado di sparare abbia abbastanza munizioni per eseguire l'attacco dell'arma.
Se hai implementato squadre o un sistema di combattimento "tra giocatori contro bot", conferma che il personaggio colpito è un nemico, non un compagno di squadra.
Conferma che il giocatore colpito è vivo.
Conserva lo stato dell'arma e del giocatore sul server e conferma che un giocatore in stato di sparo non è bloccato da un'azione corrente come ricaricare o uno stato come sprinting.
Manipolazione del DataStore
In esperienze che utilizzano DataStoreService per salvare i dati del giocatore, gli exploiter possono approfittare di dati non validi e metodi più oscuri per impedire che un Class.DataStore salvi correttamente. Ciò può essere abusato in particolare in esperienze con il trading di oggetti, i mercati e simili sistemi in cui gli oggetti o la valuta lasciano l'Inventario, reportoriodi un Giocatore.
Assicurati che qualsiasi azione eseguita attraverso un RemoteEvent o RemoteFunction che influenza i dati del giocatore con l'input del client è sana in base a quanto Seguendo:
- Instance valori non possono essere serializzati in un DataStore e falliranno. Utilizzare tipo di validazione per prevenire questo.
- DataStores hanno limiti di dati . Le stringhe di lunghezza arbitraria devono essere controllate e/o limitate per evitare questo, oltre a garantire che le chiavi arbitrarie non possono essere aggiunte alle tabelle dal client.
- Gli indici di tabella non possono essere NaN o nil . Iterate su tutti i tabelari passati dal client e verifica che tutti gli indici siano validi.
- DataStores può accettare solo caratteri UTF-8 validi, quindi dovresti sanificare tutti i caratteri forniti dal client tramite utf8.len() per assicurarti
Throttling remoto
Se un client è in grado di rendere il tuo server completare un'operazione di calcolo a costo elevato, o accedere a un servizio a tariffazione limitata come DataStoreService tramite un RemoteEvent , è critico che tu implementi limitazione delle rate per garantire che l'operazione non venga chiamata troppo spesso. La limitazione delle rate può essere implementata tr
Validazione della movimentazione
Per le esperienze competitive, potresti voler validare i movimenti del personaggio del giocatore sul server per assicurarti che non stiano teletrasportando intorno alla mappa o si stiano muovendo più velocemente del normale.
Incrementi di 1 secondo, controlla la nuova posizione del personaggio contro una posizione precedentemente memorizzata.
Confronta il reale Delta Distanza contro il Delta tollerabile e procedi come segue:
- Per una Delta tollerabile, memorizza la nuova posizione del personaggio in preparazione per il prossimo incrementato Controllare /Verificare.
- Per un delta inaspettato o intollerabile (potenziale exploit di velocità/teletrasporto):
- Aumenta un valore "number of offenses" separato per il Giocatore, invece di punirlo per un "false positive" risultante da una latenza del server estrema o da altri fattori non-exploit.
- Se si verificano un gran numero di offese in un periodo di 30-60 secondi, Kick() il giocatore dall'esperienza interamente; altrimenti, ripristina il conteggio "number of offenses" . Nota che quando sei in grado di cacciare un giocatore per truffa, è meglio praticare la pratica della registrazione per poter tenere traccia di quanti giocatori sono colpiti.