[Question] Replication and cheat protection

In ShooterGame, there is a TimeBetweenShots variable, which I made Replicated, because a weapon (a chaingun) can modify that (its fire rate increases as the user holds the fire button).

UPROPERTY(EditDefaultsOnly, Replicated, Category=Config)
	float TimeBetweenShots[NUM_FIRING_MODES];

Here’s the set function…

	/** set current TimeBetweenShots */
	UFUNCTION(BlueprintCallable, Category=Weapon)
	void SetFireRate(uint8 FireModeIndex, float NewTimeBetweenShots);

…which checks for authority before setting:

FORCEINLINE void AShooterWeapon::SetFireRate(uint8 FireModeIndex, float NewTimeBetweenShots)
{
	if (Role == ROLE_Authority)
	{
		TimeBetweenShots[FireModeIndex] = NewTimeBetweenShots;
	}
}

I have added DOREPARRAY(AShooterWeapon, TimeBetweenShots); to the GetReplicationList() function, under if (RepFlags.bNetOwner) (only the weapon owner needs that variable updated).

The set function is called from on the chaingun’s Blueprint.

My question is, can a hacker modify the TimeBetweenShots variable (e.g. by directly editing memory, or whatever, I’m not a specialist on that) and have it replicated to the server? If so, how can I overcome this flaw?

In other words… I want that the variable be replicated only from server to clients, but not from client to server.

You are pretty close. There are a few things to clarify:

Marking the function as Server, Client, or NetMulticast makes the function replicated. E.g., when a Server function is called on the client the call is replicated to the server and the server executes the body of code (in an _Implementation function. E.g, if you marked SetFireRate as Server, you need to do your work in SetFireRate_Implementation). So just marking that function as Server is probably not what you want.

BlueprintAuthorityOnly is closer to what you want. Marking a function BlueprintAuthorityOnly means that in blueprints, only the server may execute the function (if a client tries to call it, nothing will happen and execution will continue).

Having the Role check in the function body may still be a good idea, since SetFireRate could be called directly from C++ as well.

Property replication does only ever happen server → client. Clients cannot set properties and have them propagate to the server. The only way clients communicate with the server is by calling Server replicated functions. A hacker could in theory send bogus calls to (only) Server functions (they cannot trick the server into executing non Server functions remotely). Any parameters to Server replicated functions could be compromised as well.

Hackers could also modify anything in memory. So, locally, the client could modify his TimeBetweenShots. In the end the onus is on the server to decide how to handle what the client tells him. E.g, if TimeBetweenShots is what gates rate of fire, which ultimately results in a Server weapon fire function being called - the server should do security checks in that Server weapon fire function.

I hope that helps you.

Aye, clear now. So I’ll need checks that the client’s rate of fire is consistent with the server game state, much like what’s done already in ShooterGame with view direction and bounding box checks on hit. Or handle the entire firing on the server and only replicate the effects/results (probably a bad idea due to latency). Thanks Dave!

Hi,

From my understanding of replication in UE, replication is always server-to-client only. The server is authoritative and adjusts the value, clients have “read-only” access to this value in a sense.

Maintain a good understanding of how and from where code is executed, you should be able to prevent the client from calling functions that modify the TimeBetweenShots unintentionally. To aid with this keep the interface to these types of values to a minimum.

Hmm. So I don’t even need to check if (Role == ROLE_Authority) on the Set function?

If you know it’s a server-only function (eg. marked as “server” and not “client”) that you should be able to rely on it to only ever run on the server-side.
If it’s a function that could potentially be called on either side (eg. simulated) then it makes sense to check for it’s role to determine the type of function it must execute (eg. ClientSetSpeed() or ServerSetSpeed() where the prefix of Client* / Server* is a common naming convention in UT3 for call-type)

I’m not an expert on multiplayer security concerns, but from my FPS multiplayer coding experience, this is what I’m accustomed to and seen happen in source of UT and others.

Ah, good call. I’ll mark the function as server only.

I’ll just wait for confirmation that replication is server to clients only, never client to server (documentation doesn’t mentions it), before marking as answered. Thans Tom :slight_smile: