[Twisted-Python] pb.Copyable, round trip objects, and untrusted clients

Jasper Phillips jasper at peak.org
Thu May 20 05:25:20 EDT 2004


On Wed, 19 May 2004, David Ripton wrote:

> I'm working on a client-server game, with hidden information, using PB. 
>   I don't want to trust the clients.

Titan, I presume?  Nice game!

I'm working on a game more akin to Civilization or Age of Wonders, but have
basically the same problem.


> Because there is hidden information, it's important not to send anything 
> to the client that it's player shouldn't see.  Doing that with PB is 
> pretty straightforward.  If a class's data is always secret, don't make 
> it Copyable.  If parts of a class are secret, censor them in getStateToCopy.

For me this was more complex, as what a Player knows is itself a true part
of the Game's State, potentially affecting Action/Event resolution.  I end
up calculating each Players state myself, and passing them explictly.

Plus this feels to me more like it should be part of the game itself, rather
than some oblique networking aspect.  Same end effect though.


> Obviously, the client should only be able to change the server's game 
> state via a well-defined error-checked interface.  Also fairly 
> straightforward, though error-prone since you need to forsee and test 
> against every way to cheat.

IMHO handling this can avoid the 3rd problem you mention.  I have Players
send Actions for a given Turn as the only API to change Game State.  These
actions don't take game object as args, but rather Ids as you suggest below.

I do send actual objects from the Game to Players, but IMHO this is a bit
error prone lest you accidentally leave in secret info.  I only do it so
that the clients can validate actions they plan sending against their
perceived State using the same mechanism as the Game.


> There's a third hole to plug, which is passing an object from the server 
> to the client as an argument of a client-side remote_* method, and later 
> getting it back as an argument to a server-side perspective_* method. 
> (e.g. the server passes the client a list of games in progress, and 
> later the client passes back the game it wants to join.)  If the client 
> changes the object before passing it back, it might trick the server 
> into doing the wrong thing with it.
> 
> Anyway, it seems easy enough to avoid this problem, by just rewinding 
> any changes the client has made to such objects.  At some point before 
> sending an object to the client side, add it to a dict, keyed by its id. 
>   When an object comes back from the client as an argument in a 
> perspective_* call, use its id to lookup the server's copy of the object 
> in the dict, and then reassign the current name to the good version of 
> the object, losing any changes the client may have made.  In other 
> words, the client is treated as if it only passed the object's id back, 
> not its __dict__.  But the interface is simpler.

IMHO it seems superflous to have the game update the information a client
sends, only to later access this same information for calculations.  Why not
just pass back the relavent Ids, and have the Game API look up their True
counterpart as needed?  This doesn't seem onerous to me.

-Jasper





More information about the Twisted-Python mailing list