Advertisement

Network encryption thoughts and security paranoia

Started by December 29, 2016 10:40 AM
7 comments, last by Randy Gaul 7 years, 10 months ago

Hello,

As i am about to finish custom analytics tool, i began to think about games over network.

But i have one issue i cannot solve.

Data encryption.

When sending custom analytical events to server, i have a problem - player can simply change the code, recompile it or even make a POST to server and send "F**K YOU SCRUB, HACKED" message using proper variables.

I was thinking about the ways to prevent it, but i always get stopped by simple thought - if its encrypted on client side, it can always be manipulated.

And its not that hard, you only need Wireshark to sniff packets!

And that prevented me from developing network game. Because you can even emulate the player by sending fake data packets.

Am i overthinking it? Are there measures to counter this?

As you are discovering, encryption only protects data in transit, much like an armored delivery service. It works by protecting information in transit from modification, from immediate viewing, and a few other things. It does not protect against someone tampering with one end, such as giving the armored car people bags of printer paper and metal washers instead of real paper money and coins, or if the person receiving the shipment is planning on fleeing the country with your bags of money after delivery.

For banks, it means that logged-in customers can send commands to the servers without fear of people hijacking their account. However, a malicious bank customer could still determine their protocol and figure out commands, such as "deposit $1,000,000". The data is protected in transit, but if the source sends bad data the servers still need to ensure it is correct and valid. The servers need to be carefully written to validate and handle input, even malicious input, because the person on the other end of the secure connection may be an attacker.

For games, it means the same thing. The connection may be secure, but the person on the other end may be malicious. You need to validate all your data. If the server gets an event and that event is supposed to be 32 bytes long, the data better be 32 bytes long. Whatever the ID is for the type of data being sent, that value must be on the table of actual event IDs and must be validated for sanity and proper ranges; if the only valid values are 0-6 then it must be validated. If the server is expecting a string it must have sane limits and the length must be within those limits, the contents of the string must be valid characters in the character set, and must be validated to not include things like html script or such. When processing the events, it must match what the server expects; a player announcing they are at a location far away from their previous location is a problem, a player announcing they hit a target they could not see is a problem; the common solution to these is to have clients send event requests with timestamps like 'shot fired' or 'started running' or 'turned', then the server figures out how those events play out and sends the authoritative information back to the game clients. Validate everything.

Advertisement
To expand on what frob said, keep your server protocol simple.

Instead of letting the user send a string, or worse an SQL query (yes some people do that) send for example a single byte indicating status, and let the server expand that to the text from a lookup table. That way you can't send "HAHA HACKED" because the only choices are 0 or 1 for "WON" or "LOST".

Similarly on the server check if the player can legitimately send status 1 for "WON", e.g. if the server knows they didn't win, block the request.

This does mean the server needs to know and orchestrate the gameplay not just run that client side.

Hope this helps!

Thanks for the responses!

Yeah, the data gets validated, but i made it more readable in the past, currently refraining myself from doing changes to old system.
Messages look like this

d85bec0f433d4a1 182 _44 1482950156320 _1_1_2 vc gmpScr _Eris g
d85bec0f433d4a1 182 _45 1482950156399 _1_1_2 vc gmpScr r

Issue lies within values like
d85bec0f433d4a1 - user id
182 - session number
_45 - event number
1482950156320 - local user timestamp

User can change one of those parameters and it will still get validated, but analytical data gets distorted.

But yeah, as frob stated, in network game, i could refrain from sending so much data and could do more stuff on server and make client application sort of paper glass.

but analytical data gets distorted


Yes. There is no way around that!
(Also note that the user's clock will be off by seconds, hours, days, or years, in either direction, compared to your server clock.)

So, if you want to gather analytics about what generally happens in the client, you can do that, and use the law of large numbers to get "good enough" measurements, even if some users try to screw with your analytics.
However, anything that needs to be authoritative, needs to be derived from the server.
Thus, for example, you never have the player say "harvest the gold nugget giving me $500" -- instead you say "I would like to harvest a gold nugget that's within 3 meters of my character," and the server will then A) verify that such a nugget exists and B) decide what the outcome actually is.
Same thing for analytics -- running user behavior models on what the server sees of the cilents is generally more reliable.

There are of course validation, adjustment, outlier, de-noise, de-season, and other scrubbing you can do on noisy input data to get some kind of signal from clients. You just have to realize that you do, in fact, have to worry about those things!
enum Bool { True, False, FileNotFound };

Thanks!

Yeah, plan was to use clients local time, but there is something funny going on, all the times are a bit "off" and use GMT 0 i think, because my local time is GMT -2. But ill fix that.

Thanks for the responses!

Advertisement

You may also want to ensure network messages can be repeated without problems, also called being "idempotent".

If somehow my system never got a response and it kept transmitting the code that it won the game, each transmission should be acknowledged by the server but only get a single entry.

That can partially be accomplished with unique IDs applied to all transactions, but should also be validated with other criteria as appropriate. If a game lasts several minutes, notifications of victory that happen within seconds should be handled.

As for timestamps, all machines will be slightly different. Typically games just assign a number to indicate the beginning of time for the session and call it good. Servers may use some other value, like the current uptime of the server or some other value so it isn't reset to zero or reset to the current wall clock time, as both values can be more easily spoofed by malicious users.

You may also want to ensure network messages can be repeated without problems, also called being "idempotent".

If somehow my system never got a response and it kept transmitting the code that it won the game, each transmission should be acknowledged by the server but only get a single entry.

I have made rather simple webpage, that logs proper urls, and returns 1 if all is good.

Simplified code:


Response.Clear();

if (allGood())
   Response.Write(1);

Response.End();

Whilst mobile game logs all events into SQLite, and queuees sheduler to run after 5 minutes if no new events are generated, run after 2 seconds if player pressed "back".

In case of no network, run alarm every 30 minutes.

Events are sent in chunks and GZiped and base64'ed. If data is to long, split into smaller chunks, creating sort of "session", which brakes if response is "", and continues if response is "1".

If everything was positive, records are deleted from SQLite.

As frob pointed out, the hard work is making sure your protocol or data is easy to validate. A-priori knowledge or design decisions are the hard work. Try to design what data is sent and why in order to make sure that even if it is maliciously tampered, it just does not matter. For example with games, lockstep style net events (mostly user inputs) are sent to an authoritative server. If the user inputs are faked that user can be disconnected from the server. Thus tampering with net packets is not useful, even if still possible.

Usually the encryption is there just to protect knowledge of the data. Or in other words, only the server and a specific client can have knowledge of some sensitive data, like logins, passwords, or anything else that should be kept secret. The encryption is just to ensure only certain machines have access to knowledge. It does not prevent packet tampering, since packets can trivially be tampered before the encryption function is called.

This is why many games go for client server style. If the server holds all authority the clients can have whatever malicious intents they desire, but in the end a good design will make it so malicious intent can not do any harm. For my own personal code this is the style I chose to adopt; an authoritative server, and "dummy" clients, that mostly just relay user inputs.

This topic is closed to new replies.

Advertisement