Roblox utilizza un sistema di fisica distribuita in cui i client hanno la custodia della simulazione fisica di oggetti nel loro controllo, tipicamente il personaggio del Giocatoree oggetti non ancorati vicino a quel personaggio.Inoltre, attraverso l'uso di software di terze parti, gli exploiter possono eseguire un codice Luau arbitrario sul client per manipolare il modello di dati del client e decompilare e visualizzare il codice in esecuzione su di esso.
Collettivamente, questo significa che un esperto exploiter può potenzialmente eseguire il codice per truffare nel tuo Gioco, tra cui:
- Teletrasportare il proprio personaggio intorno al Posto.
- Sparare non sicuro RemoteEvents o invocare RemoteFunctions , come per assegnare loro oggetti senza guadagnarli.
- Aggiustare il loro personaggio di WalkSpeed in modo che si muova molto velocemente.
Mentre puoi implementare limitate difese di progetto per catturare 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 progettazione difensive
Le decisioni di progettazione di base possono servire come "primo passo" misure di sicurezza per scoraggiare gli exploit.Ad esempio, in un gioco sparatutto in cui i giocatori ottengono punti per uccidere altri giocatori, un exploiter può creare un gruppo di bot che si teletrasporta nello stesso posto 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 |
---|---|
Inseguire i bot scrivendo codice che tenta di individuarli. | |
Riduci o elimina del tutto i guadagni di punti per le uccisioni su giocatori appena generati. |
Mentre il design difensivo ovviamente non è una soluzione perfetta o completa, può contribuire a un approccio più ampio alla sicurezza, insieme a mitigazione lato server.
Mitigazione lato server
Per quanto possibile, il server dovrebbe emettere il verdetto finale su ciò che è "vero" e quale sia lo stato attuale del mondo.I clienti possono, naturalmente, richiedere al server di apportare modifiche o eseguire un'azione, ma il server dovrebbe validare e approvare ciascuna di queste modifiche/azioni prima che i risultati vengano replicati ad altri giocatori.
Con l'eccezione di alcune operazioni fisiche, i cambiamenti al modello di dati sul client non si riplicano sul Server, quindi il percorso principale di attacco è spesso attraverso 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 qualsiasi dato che desidera.
Validazione del tipo di runtime remoto
Un percorso di attacco è per un exploiter per invocare RemoteEvents e RemoteFunctions con argomenti di inserisci / scrivierrato.In alcuni scenari, questo può causare un codice sul server che ascolta questi remoti in modo che sia vantaggioso per l'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 controllo del tipo in questo modo.Ad esempio, supponendo che il codice del modulo esista come ModuleScript chiamato t all'interno di ReplicatedStorage :
Script locale in StarterPlayerScripts
local ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")-- Passa la parte del colore e della posizione quando si invoca 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 Workspace = game:GetService("Workspace")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
local t = require(ReplicatedStorage:WaitForChild("t"))
-- Crea un validatore di tipo in anticipo per evitare sovrastrutture non necessarie
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 il tipo degli argomenti passati
if not createPartTypeValidator(player, partColor, partPosition) then
-- Restituisci silenziosamente "false" se il controllo del tipo fallisce qui
-- Sollevare un errore senza un tempo di recupero può essere abusato per rallentare il Server
-- Fornisci feedback del client invece!
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
-- Lega "createPart()" alla richiamata della funzione remota
remoteFunction.OnServerInvoke = createPart
Validazione dei dati
Un altro attacco che gli exploiter potrebbero lanciare è quello di inviare tipi tecnicamente validi ma renderli estremamente grandi, lunghi o altrimenti malformati.Ad esempio, se il server deve eseguire un'operazione costosa su una stringa che aumenta con la lunghezza, un exploiter potrebbe inviare una stringa incredibilmente grande o malformata per rallentare il Server.
Allo stesso modo, sia inf e NaN saranno type() come number , ma entrambi possono causare problemi importanti 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 exploiter possono utilizzare consiste nell'invio di tables invece di un Instance.I carichi complessi possono imitare ciò che sarebbe un riferimento oggetto ordinario altrimenti.
Ad esempio, fornito con un negozio in-experience sistema dove i dati degli oggetti come i prezzi sono memorizzati in NumberValue, un exploiter può aggirare 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 anche essere utilizzati, risultando nel dare la valuta piuttosto che prenderla!},}-- Invia un carico utile malevolo al server (questo verrà respinto)print(buyItemEvent:InvokeServer(payload)) -- Produce "false oggetto non valido fornito"-- Invia un oggetto reale al server (questo passerà!)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)
-- Verifica se l'elemento passato non è stato spoofato e si trova nella cartella ItemData
if typeof(item) ~= "Instance" or not item:IsDescendantOf(itemDataFolder) then
return false, "Invalid item provided"
end
-- Il server può quindi procedere al processamento dell'acquisto in base al flusso di esempio qui sotto
end
-- Lega "buyItem()" alla richiamata della funzione remota
buyItemEvent.OnServerInvoke = buyItem
Validazione del valore
Oltre a validare tipi e dati , devi validare i valori passati attraverso RemoteEvents e RemoteFunctions , assicurandoti che siano validi e logici nel contest richiesto.Due esempi comuni sono un negozio in-experience e un sistema di targeting di armi.
Negozio nell'esperienza
Considera un sistema di negozio in-experience con interfaccia utente, ad esempio un menu di selezione del prodotto con un pulsante "Acquista".Quando viene premuto il pulsante, puoi invocare un RemoteFunction tra il client e il server per richiedere l'acquisto.Tuttavia, è importante che il server , il gestore più affidabile dell'esperienza, confermi che l'utente ha abbastanza denaro per acquistare l'Articolo.

Targeting dell'arma
Gli scenari di combattimento richiedono una particolare attenzione alla validazione dei valori, in particolare attraverso la mira e la validazione degli obiettivi.
Immagina un gioco in cui un giocatore può sparare un raggio laser ad un altro Giocatore.Piuttosto che il cliente dica al server a chi danneggiare, dovrebbe invece dire al server la posizione di origine del colpo e la parte/posizione che pensa di aver colpito.Il server può quindi validare quanto Seguendo:
La posizione che il cliente segnala spara da è vicina al personaggio del Giocatoresul Server.Si noti che il server e il client differiranno leggermente a causa del ritardo, quindi sarà necessaria un'ulteriore tolleranza.
La posizione che il client segnala colpendo è ragionevolmente vicina alla posizione della parte che il client segnala colpendo, sul Server.
Non ci sono ostrazioni statiche tra la posizione da cui il cliente rileva il tiro e la posizione a cui il cliente rileva il tiro.Questo controllo garantisce che un client non stia tentando di sparare attraverso le pareti.Nota che questo dovrebbe controllare solo la geometria statica per evitare che i colpi validi vengano rifiutati a causa del ritardo. Inoltre , potresti voler implementare ulteriori validazioni lato server come segue:
Traccia quando il giocatore ha lanciato l'arma per l'ultima volta e validare per assicurarsi che non stia sparando troppo velocemente.
Traccia la quantità di munizioni di ciascun Giocatoresul server e conferma che un giocatore in fiamme abbia abbastanza munizioni per eseguire l'attacco dell'arma.
Se hai implementato squadre o un sistema di combattimento "giocatori contro bot", conferma che il personaggio colpito è un nemico, non un compagno di squadra.
Conferma che il giocatore colpito è vivo.
Memorizza lo stato dell'arma e del giocatore sul server e conferma che un giocatore di fuoco non è bloccato da un'azione attuale come ricarica o uno stato come sprint.
Manipolazione del deposito dati
Nelle esperienze che utilizzano DataStoreService per salvare i dati del giocatore, gli exploiter possono approfittare di dati non validi data e di metodi più oscuri, per impedire a un DataStore di salvare correttamente.Questo può essere abusato in particolare in esperienze con il trading di oggetti, mercati e sistemi simili in cui gli oggetti o la valuta lasciano l'Inventario, reportoriodi un Giocatore.
Assicurati che qualsiasi azione eseguita attraverso un RemoteEvent o RemoteFunction che influisca sui dati del giocatore con l'input del client sia sanitizzata in base al Seguendo:
- Instance i valori non possono essere serializzati in un DataStore e falliranno. Utilizza la validazione del tipo per prevenire questo.
- DataStores hanno limiti di dati .Le corde di lunghezza arbitraria devono essere controllate e/o limitate per evitare questo, garantendo che le chiavi arbitrarie illimitate non possono essere aggiunte alle tabelle dal client.
- Gli indici delle tabelle non possono essere NaN o nil . Iterate su tutte le tabelle passate dal client e verifica che tutti gli indici sono validi.
- DataStores può accettare solo caratteri UTF-8 validi, quindi dovresti sanare tutte le stringhe fornite dal client tramite utf8.len() per assicurarti che siano valide. utf8.len() restituirà la lunghezza di una Stringa, trattando i caratteri Unicode come un singolo carattere; se viene incontrato un carattere UTF-8 non valido restituirà nil e la posizione del carattere non valido.Si noti che le stringhe UTF-8 non valide possono anche essere presenti nelle tabelle come chiavi e valori.
Rallentamento remoto
Se un client è in grado di rendere il tuo server completare un'operazione costosa in termini di calcolo o accedere a un servizio a tariffa limitata come DataStoreService attraverso un RemoteEvent , è critico che tu implementi limitazione della tariffa per garantire che l'operazione non venga chiamata troppo spesso.La limitazione del tasso può essere implementata tracciando quando il client ha invocato per l'ultima volta un evento remoto e rifiutando la prossima richiesta se viene chiamato troppo presto.
Validazione del movimento
Per le esperienze competitive, potresti voler validare i movimenti del personaggio del giocatore sul server per garantire che non stanno teletrasportandosi intorno alla mappa o muovendosi più velocemente di quanto accettabile.
Incrementando di 1 secondo, controlla la nuova posizione del personaggio contro una posizione precedentemente memorizzata.
Confronta il delta della distanza effettiva contro il delta tollerabile e procedi come segue:
- Per un delta tollerabile, memorizza la nuova posizione del personaggio in preparazione per il prossimo incremento del Controllare /Verificare.
- Per un delta inaspettato o intollerabile (potenziale exploit di velocità/teletrasporto):
- Aumenta un valore separato di "numbero di violazioni" per il Giocatore, rispetto a penalizzarlo per una "falsa positiva" dovuta a estrema latenza del server o ad altri fattori non exploit.
- Se un gran numero di violazioni si verifica in un periodo di 30-60 secondi, Kick() il giocatore dall'esperienza completamente; altrimenti, ripristina il conteggio "numbero di violazioni".Nota che quando si caccia un giocatore per truffa, è consigliabile registrare l'evento in modo da poter tenere traccia di quanti giocatori sono interessati.