Domanda:
Invio sicuro di un punteggio elevato lato client a un server
StationaryTraveller
2017-01-15 15:45:41 UTC
view on stackexchange narkive permalink

Sto creando un'applicazione web che contiene un semplice gioco javascript. Una volta che il giocatore ha finito di giocare, il punteggio più alto viene inviato al server e salvato.

Dopo un determinato periodo il giocatore con il miglior punteggio riceve un premio.

C'è un modo per inviare il punteggio più alto in modo sicuro e impedire al cliente di inviare punteggi "falsi"?

Attualmente stiamo utilizzando:

  • Https.
  • Token casuale del server prima di ogni partita e inviato dopo che la partita è finita insieme al punteggio.
Non esiste un modo infallibile per risolvere questo problema.L'unico modo è tenere traccia del punteggio di ogni singola partita sul server.
TLS non ha nulla a che fare qui e non puoi garantire nulla sul lato client se * cerca * di essere dannoso.Dovresti leggere una [risposta sul tuo problema attuale] (http://security.stackexchange.com/a/147047/91111).
C'è una domanda simile qui, la risposta principale ha un sacco di buoni suggerimenti.https://stackoverflow.com/questions/73947/what-is-the-best-way-to-stop-people-hacking-the-php-based-highscore-table-of-a-f
A proposito, stai facendo questa domanda * troppo * troppo tardi.Se fosse stato necessario, questo tipo di sicurezza avrebbe dovuto essere integrato fin dall'inizio, non innestato in seguito.
OTOH, se l'incentivo a decifrare il tuo gioco (e quindi falsificare i punteggi più alti) è inferiore alla difficoltà di decifrarlo, il tuo gioco potrebbe andare bene semplicemente perché non c'è abbastanza interesse a falsificare il punteggio.
Sei risposte:
grc
2017-01-15 16:54:50 UTC
view on stackexchange narkive permalink

Il server non può fidarsi completamente dei dati che riceve dal client, quindi convalidare i punteggi più alti è difficile.

Ecco alcune opzioni:

  1. Offuscare il codice lato client e il traffico al server. Questa è l'opzione più semplice: sarà comunque possibile imbrogliare, ma probabilmente non varrà il tempo di nessuno.

  2. Invia un replay completo o parziale del gioco al server per la convalida. Le mosse del giocatore possono essere eseguite sul server per determinare il punteggio legittimo. Questo funzionerà per alcuni giochi e non per altri.

  3. Sposta la logica del gioco e la convalida sul server. Il client trasmette semplicemente ogni mossa al server, dove viene convalidata e lo stato del gioco aggiornato.

Dipende da come funziona il tuo gioco, quanto è probabile che le persone imbrogliano e quanto ti importa se lo fanno.

# 3 è l'unico modo corretto per farlo
@theonlygusti Forse ho frainteso il punto ma non devi spostare la logica del gioco: devi solo replicarla sul server.Se tutto ciò che invii sono tutti gli input del giocatore, il server può riprodurli e verificare il punteggio.Quindi devi solo preoccuparti dei giocatori di "TASbot" :).Per un esempio di un gioco che lo fa bene - DROD.Poiché è un gioco logico, è anche resistente alle partite assistite da strumenti.L'unico problema irrisolvibile è lo sniping, in cui qualcuno guarda la demo di un altro giocatore e cerca punti di ottimizzazione.
@Maurycy Stavo solo dicendo che l'unico modo per essere sicuri che un punteggio alto sia valido è gestire il gioco sul server.Spostare / replicare non ha importanza
@theonlygusti Voglio dire che il punto dice "sposta la logica del gioco" e ho sentito che è necessario essere pignoli che devi semplicemente replicarlo.Probabilmente avrei dovuto taggarti nel commento perché volevo davvero rispondere alla risposta nel suo insieme, non al tuo commento :)
@theonlygusti: Per molti tipi di giochi, 2 equivale a 3.
@theonlygusti Correction, # 3 è l'unico modo * infallibile * per farlo (ma in realtà non è vero in quanto non è infallibile!).È solo la più infallibile e la più difficile delle opzioni offerte.
@theonlygusti, per i giochi deterministici (pensa: Tetris), # 2 funzionerà fintanto che non ti dispiace concedere record di alto punteggio agli AI.
@Mark # 2 ha anche lo svantaggio che un cliente potrebbe ottimizzare in base alle conoscenze future.Per esempio.in Tetris, se conosci tutti i pezzi che otterrai, puoi trovare una strategia migliore rispetto a se prendi solo un pezzo, poi lo metti da qualche parte, quindi prendi il prossimo.
# 1 è inutile con un gioco javascript, poiché è _molto_ più facile rigenerare codice leggibile rispetto a qualsiasi altra lingua.
Philipp
2017-01-15 16:54:58 UTC
view on stackexchange narkive permalink

Se il tuo aggressore fosse un attaccante man-in-the-middle a livello di rete, allora https sarebbe sufficiente. Ma sfortunatamente il tuo aggressore è il client, quindi questo è piuttosto inutile.

Regola numero uno dei giochi a prova di cheat: Non fidarti mai del client! Il client è nelle mani del nemico.

I giochi Javascript vengono eseguiti nel browser web dell'utente. Come sicuramente saprai come sviluppatore web, ogni browser web al giorno d'oggi viene fornito con un debugger integrato che può visualizzare e modificare tutte le variabili mentre un'applicazione è in esecuzione. L'utente può semplicemente utilizzare il debugger per modificare il punteggio prima che venga inviato. Non puoi fare nulla per impedirlo. Con i giochi basati su browser non puoi nemmeno usare uno strumento anti-cheat di terze parti (che sono di dubbio valore e comunque eticamente discutibili).

L'unica contromisura è implementare tutte le meccaniche di gioco che vale la pena manipolare sul server. Il client non deve fare altro che inoltrare i comandi dell'utente al server e visualizzare il gameplay in base ai messaggi del server. Il gioco effettivo dovrebbe avvenire sul server dove è fuori dalla portata degli imbroglioni.

Sì, questo significa che dovrai riprogettare da zero l'architettura del software del tuo gioco. Significa anche che dovrai aggiungere alcuni codici di predizione e interpolazione per rendere meno visibile il ritardo di rete. E significa anche che avrai bisogno di un hardware del server di gran lunga migliore e di una connessione Internet migliore per i tuoi server. Ma quando vuoi un gioco online senza cheat, questa è l'unica opzione.

C'è la solita ** fiducia, ma verifica ** la risposta - vedi l'opzione # 2 nella risposta di grc.
@MSalters Non è ** fidarsi, ma verificare ** un ossimoro?Non ti fidi del cliente, motivo per cui verifichi la sua risposta.Se ti fidi del cliente, perché la necessità di verificarlo?
@Tom "Fidati ma verifica" è una frase comune che deriva da un proverbio russo (vedi [Wikipedia] (https://en.wikipedia.org/wiki/Trust,_but_verify)).E sì, è un ossimoro, ma puoi anche leggerlo come se fosse "innocente a meno che non sia stato dimostrato colpevole".O, a proposito, quando Wikipedia presume che gli utenti agiscano in buona fede durante la modifica (è solo un wiki perché non è bloccato), ma richiede comunque che citino i riferimenti.
Lie Ryan
2017-01-15 22:29:01 UTC
view on stackexchange narkive permalink

Per ottenere il punteggio più alto in un gioco sicuro, ciò di cui hai bisogno è una " prova di lavoro", o meglio, più appropriatamente chiamata prova di gioco.

Una prova di lavoro / play è qualsiasi dato difficile da calcolare prima di terminare il gioco, ma facile da calcolare una volta terminato il gioco ed è facile da verificare dal server. Ad esempio, per un gioco di Sudoku, una prova di lavoro è la soluzione al puzzle.

Sfortunatamente, non esiste un modo generico per integrare un adeguato sistema di prova del gioco in molti giochi. Non è sempre possibile integrare una prova di gioco senza modificare o riorganizzare il gioco o limitare l'ambito della classifica ai soli elementi in cui è possibile includere una prova di gioco sufficientemente sicura.

Prova di gioco su un il gioco inizia dal server che emette il seme per l'RNG del gioco. Il cliente quindi dovrà trovare una prova di gioco che corrisponda al seme che il giocatore aveva emesso. In molti giochi, una prova di gioco può essere formata inviando la soluzione del gioco al server con l'invio del punteggio più alto, in altri potrebbe essere necessario registrare l'intera sessione di gioco in vari livelli di dettagli a seconda del gioco e della prova di play che stai utilizzando.

Una prova di gioco deve essere resistente alla riproduzione (un giocatore non dovrebbe essere in grado di utilizzare il gioco finito di un altro giocatore per rendere più facile il calcolo della propria prova di gioco). Questo limita la prova di gioco a giochi in cui c'è una certa casualità che i giocatori non possono semplicemente riutilizzare la prova di gioco di un altro giocatore, ma non può nemmeno avere un comportamento troppo non deterministico al punto che la verifica del gioco diventa impossibile.

Prova anche il gioco è limitato. Ad esempio, in un gioco di Sudoku, non è possibile dimostrare il tempo impiegato dal giocatore per risolvere il puzzle. Inoltre, la prova di gioco non può sempre distinguere tra il gioco giocato dal giocatore stesso e il giocatore che ha scritto un copione che ha riprodotto il gioco per loro.

Un approccio per prevenire il "plagio" delle soluzioni potrebbe essere quello di avere il nome del giocatore specificato prima dell'inizio del gioco, hash il seme del numero casuale in base a quel nome.e chiedi al gioco di segnalare il seme non sottoposto a hashing insieme al nome e alla soluzione.
La quantità di tempo è facile da monitorare poiché ** abbiamo ** un lato server qui.È la quantità tra la generazione del puzzle e la presentazione del risultato.
CR Drost
2017-01-16 00:15:32 UTC
view on stackexchange narkive permalink

Volevo solo menzionare che esiste una sorta di soluzione a questo problema, ma probabilmente non sarà disponibile per te; la soluzione si chiama "crittografia omomorfica" e consente a un client di eseguire un calcolo noto senza sapere esattamente con quali valori sta calcolando, e un server per controllare quindi la struttura del valore calcolato per dimostrare che il client non ha semplicemente invia una stringa casuale indietro ma in realtà la costruisce a partire dai diversi valori forniti.

Il problema è che è lento o incompleto , con il significato di "incompleto" "non incorpora una gamma completa di primitive logiche". Molto spesso è un sistema parziale che consente alcune operazioni di crittografia e decrittazione E (), D (), più alcune operazioni complicate ⊕ tali che

D (E (A) ⊕ E (B)) = A + B,

o simili.

Quindi vediamo come questo risolve il problema per alcuni giochi. Considera un gioco di tipo "luci spente" in cui premi sugli N esagoni di una griglia esagonale e ognuno alterna il proprio stato e gli stati di coloro che lo circondano. Questa è un'algebra commutativa su quelle "pressioni" e quindi non ci saranno più di N pressioni totali in una data soluzione, inoltre ogni esagono dipende solo dallo stato iniziale più le pressioni del proprio esagono più i 6 esagoni attorno ad esso.

Poiché il nostro schema di crittografia omomorfico consente solo +, non XOR, diamo a ciascun esadecimale un contatore a 3 bit per il numero di volte in cui è stato capovolto. (Il software client ridurrà automaticamente ogni doppia pressione di un esadecimale a una sola pressione.) Le azioni di capovolgimento effettive sono quindi vettori di bit che assomigliano a,

  001 001 000 000 000 001001 001 000 001 001 000 000 ... 000 00000000 00000001  

In altre parole hanno 1 in ciascuno di questi campi a 3 bit che capovolge, più un 1 in un contatore a 16 bit.

Li crittografiamo tutti con uno schema di crittografia omomorfico, li inviamo al client e il client ci restituisce un valore crittografato calcolato da questi valori crittografati che abbiamo inviato indietro. Quindi decifriamo questo e AND il valore decrittografato con la stringa di bit,

  001 001 001 001 ... 001 11111111 00000000  

e confrontiamo con il gioco iniziale -stato adiacente a 0 per quegli 8 bit contatore.

Se ci inviano un valore casuale, la loro possibilità che lo accettiamo è 2 - (N + 8) e quindi la loro L'unico modo utile per superare i test è usare i valori che abbiamo fornito loro in alcune combinazioni consentite. Hanno accesso ad alcune mosse che non stiamo consentendo loro direttamente a causa di overflow di interi, ma possiamo sempre rendere i campi più larghi di 3 bit per renderli più costosi per il contatore a destra. Ma non ci sono mai state trasmesse le singole pressioni dei pulsanti, tanto meno la cronologia: abbiamo accettato un vettore che dice "ecco come ho capovolto la griglia", che è la "cosa super insicura" di cui tutti ti mettono in guardia, ma noi lo hanno fatto in modo tale che non possano fare le cose di cui ci preoccupiamo senza avere accesso a una chiave segreta.

Invece si vedono queste cose nelle votazioni crittografiche in cui si desidera avere la certezza che una macchina per il voto non dà spontaneamente 1000 voti ad Alice.

Non vedo perché la crittografia sia utile qui.L'unico modo per assicurarci che il cliente abbia effettivamente risolto il puzzle è includere la "prova del lavoro" che ha fatto.Che differenza fa se la prova del lavoro non è stata crittografata?
@AgnishomChattopadhyay Riesci a pensare a una situazione in cui la prova del lavoro di una soluzione S è sostanzialmente più lunga di S stessa?Grazie alla crittografia omomorfica, in pratica non devi.
OscarAkaElvis
2017-01-15 16:04:08 UTC
view on stackexchange narkive permalink

Tutto sul lato client può essere falsificato. Quindi la risposta è no.

EDIT Ho rimosso il meccanismo di sicurezza che ho scritto qui perché assicura solo sessioni legali ... ma i punteggi falsificati possono essere inviati tramite sessioni legali. Grazie @Luke Park

Non ho capito il tuo secondo paragrafo.Diciamo che tengo il token "casuale" sul lato server.Come posso convalidarlo quando il cliente invia il punteggio? E nel terzo paragrafo, cosa intendi per invio sicuro del token casuale iniziale?
Inviarlo sul lato server significa che se stai usando php ad esempio, devi inviarlo usando php sul backend, non da js.Immagino che i client non siano in grado di annusare nulla e se usi https come hai detto è sufficiente.Per convalidarlo, è necessario ricevere e memorizzare il token iniziale (nel database in sessione o ovunque) sullo score server e quindi, dopo aver ricevuto il token del client (che potrebbe essere falsificato), è necessario confrontarlo con il token iniziale inviato (che è protetto) in modonessuna possibilità di ingannarlo.
Qualsiasi cosa lato client può essere falsificata, l'hai detto tu stesso.Il resto della tua risposta non è quindi necessario.
@Luke Park, ha chiesto "Esiste un modo per inviare il punteggio più alto in modo sicuro e impedire al cliente di inviare punteggi" falsi "?" Quindi sto cercando di spiegare l'intero processo
Non esiste un intero processo.Non puoi impedirlo.Tutto ciò che fa il client legittimo può essere falsificato da un client illegittimo.
Tui hai torto.Il punto è che il server può creare un token iniziale per il gioco inviato in backend al server dei punteggi.Questo token è SICURO.Quindi, dopo i giochi, il token del client può essere falsificato, ok, ma il meccanismo di sicurezza è che il token inviato dal client deve corrispondere al token di sicurezza inviato per primo quando il gioco è stato creato.
Ma il client è ancora quello che invia il punteggio al server, giusto?Con il gettone?
Cerchiamo di [continuare questa discussione in chat] (http://chat.stackexchange.com/rooms/51820/discussion-between-oscarakaelvis-and-luke-park).
Dopo un po 'a pensarci più a fondo, penso che tu abbia ragione Luke Park, scusa.Ho modificato la mia risposta.
Ben Harrison
2017-01-18 22:09:42 UTC
view on stackexchange narkive permalink

Il mio consiglio è più una tecnica per l'offuscamento e potrebbe essere un ostacolo frustrante per molti utenti. Tuttavia, gli utenti avanzati o determinati potrebbero ancora analizzare il tuo codice sorgente per riprodurre i risultati.

Utilizza uno strumento come Hashid per creare un hash del punteggio e invialo nella tua richiesta del server insieme alla partitura in chiaro. Il valore stringa dell'id utente potrebbe essere il sale utilizzato per codificare un hashid del punteggio, rendendo l'hash inutile se condiviso. Sul lato server puoi decodificare questo hash e confrontare il risultato con il punteggio di testo in chiaro inviato per assicurarti che corrispondano come previsto.

Volevo sottolineare che gli hashid sono solo uno degli strumenti che potrebbero essere utilizzati.Una limitazione con questa particolare libreria è che non supporta i numeri negativi (supponendo che il tuo gioco potrebbe averne bisogno).
È solo un po 'meglio che inviare un testo normale perché l'utente conosce il suo ID e può decodificarlo proprio come fa il server.


Questa domanda e risposta è stata tradotta automaticamente dalla lingua inglese. Il contenuto originale è disponibile su stackexchange, che ringraziamo per la licenza cc by-sa 3.0 con cui è distribuito.
Loading...