Mitigate the risk of abuse of your game service

To defend your game system from bad actors, use the techniques described in this topic. These techniques can help you mitigate the risk of bad actors injecting bad data or overloading the system.

This topic describes the following:

Spark.setScriptError() and Spark.exit()

In this section, you'll learn how to block an abusive use case by calling:

For example, to block a user from creating a new player with a userName of "bad-actor", you can implement these API calls in your RegistrationRequest Cloud Code script:

var userName = Spark.getData().userName  

// If this is an abuse use case...
if(userName === "bad-actor") {  
    // Block creation of the new player and return an error message
    Spark.setScriptError("error", "The attempt to create 'bad-actor' player was blocked.")  
    // Warn that some "importantData" was not loaded
    Spark.setScriptData("importantData", "Warning: 'bad-actor'!")
    // Stop running this script
    Spark.exit()  
}  

// Store our "importantData"
Spark.setScriptData("importantData", "Our game rocks; try it!")

// More of your custom code runs after here
// ...

Try it!

To see the above code in action:

  1. In the GameSparks console in your web browser, move your mouse pointer over Configurator in the left navigation panel, and then choose Cloud Code.

  2. In the Scripts panel, expand the Requests folder, and then choose the RegistrationRequest Cloud Code script.

  3. Copy and paste the above example into the Cloud Code editor, and then choose to save and close.

  4. In the navigation panel, choose Test Harness, and then choose Authentication -> RegistrationRequest.

  5. Copy the following code into the JSON box, and then choose Send Request.

     {  
         "@class": ".RegistrationRequest",  
         "displayName":"Bad Actor",  
         "password":"",  
         "userName": "bad-actor"
     }  
    

The response demonstrates that you blocked the attempt to abuse this service.

{
  "@class": ".RegistrationResponse",
  "error": {
    "error": "The attempt to create 'bad-actor' player was blocked."
  },
  "newPlayer": false,
  "scriptData": {
    "importantData": "Warning: 'bad-actor'!"
  }
}

Explanation

Spark.setScriptError() is typically used to communicate an error to the player when something goes wrong or when they try to do something unsupported in the game. In the case of a bad actor attempting to abuse your game service, you can use the function to block the operation.

Spark.Exit() is handy for terminating your script when fatal errors occur. In this case, you call the function to block a bad actor from executing subsequent lines of code in your Cloud Code script.

Prevent Abuse of Leaderboards

In this section you'll learn how to check and block invalid scores from being posted to your leaderboard.

Create an Event to Submit a Score

  1. In the GameSparks console in your web browser, point to Configurator, and then choose Events.

  2. On the Events page, choose Add, and then define the postScore event:

    • Short Code: postScore
    • Name: postScore
    • Description: postScore

      Choose Save.

  3. On the right side of the Attributes panel, choose Add, and then define the score attribute:

    • Short Code: score
    • Name: score
    • Data Type: Number
    • Default Value (leave it empty)
    • Default Aggregation Type: Maximum
  4. Choose Save and Close.

Create a Leaderboard

  1. Point to Configurator, and then choose Leaderboards.

  2. On the right side of the Leaderboard page, choose Add, and then define the leaderboard leaderboard:

    • Short Code: leaderboard
    • Name: leaderboard
    • Description: leaderboard
    • High Score Notification: ON

      (Leave all other options on their default settings.)

  3. In the Fields panel, choose Add to add a new running total to your leaderboard. Specify the options:

    • Running Total: postScore
    • Collector: postScore.score-all
    • Filter Type: *
    • Filter Value: (leave it empty)
    • Sort: DESC
  4. Choose Save and Close.

Block Invalid Score Updates

To assert, for example, that leaderboard scores over 1,000 are invalid, add a LogEventRequest Cloud Code script:

  1. In the GameSparks console, point to Configurator, and then choose Cloud Code.

  2. Expand the Requests folder, and then choose LogEventRequest.

  3. Copy and paste the code below into the script, and then save and close.

// LogEventRequest 
// Block scores over 999   
if(Spark.getData().eventKey == "postScore" && Spark.getData().score > 1000 ) {  
    // block the invalid leaderboard update and return an error to the client 
    Spark.setScriptError("error", "Score cannot be higher than 1,000!")  
    // block the invalid update from causing any other operations to occur 
    Spark.exit()  
}

Try it out!

To test your leaderboard validation script and see it in action, choose Test Harness.

Authenticate as a player:

{  
    "@class": ".DeviceAuthenticationRequest",  
    "deviceId": "test",  
    "deviceOS": "",  
    "displayName": "testUser"  
}

Post a valid score update:

{  
    "@class": ".LogEventRequest",  
    "eventKey": "postScore",  
    "score": 100  
}

The system returns a NewHighScoreMessage.

Now try posting an invalid score update:

{  
    "@class": ".LogEventRequest",  
    "eventKey": "postScore",  
    "score": 1500  
}

The system blocks the leaderboard update and returns your error message.

Note The LogEventRequest Cloud Code script will be executed for every custom event that the game sends. You can check which event is currently being executed with Spark.getData().eventKey. Knowing this you can place validation logic for multiple custom events in this one script.

Prevent Abuse of Challenges

Challenges can make your game more fun by giving players some control over how they compete in your game. To block bad actors from abusing this capability, add Cloud Code scripts to enforce reasonable boundaries on how and when challenges can be created.

We recommend that you add code to CreateChallengeRequest to block abusive behavior such as:

Configure the Challenge

Begin by configuring the challenge.

  1. Point to Configurator, and then choose Challenges.

  2. On the right side of the Challenges page, choose Add, and then define the testChallenge challenge:

    • Short Code: testChallenge
    • Name: testChallenge
    • Description: testChallenge

      (Leave all other options on their default settings.)

  3. Choose Save and Close.

Limit How Frequently a Player can Issue a Challenge

For example, you want to block each player from issuing a challenge more often than once per minute.

  1. In the GameSparks console, point to Configurator, and then choose Cloud Code.

  2. Expand the Requests folder, and then choose CreateChallengeRequest.

  3. Copy and paste the code below into the script, and then save and close.

// CreateChallengeRequest    
// check for the last time the player created a challenge  

var lastCreatedChallengeTime =
Spark.getPlayer().getPrivateData("lastCreatedChallenge");  
var now = new Date().getTime();  

if (lastCreatedChallengeTime !== null) {  
    var lastCreatedChallengeDif = now - lastCreatedChallengeTime  

    // if the player created a challenge in the last 60 seconds, block the
    // new challenge creation.  
    if(lastCreatedChallengeDif <= 60000) {  
        var waitTime = (60000 - lastCreatedChallengeDif) / 1000  
        Spark.setScriptError("error", "challenge creation limit reached. please
        try again in "+ Math.round(waitTime) +" seconds");  
        Spark.exit();  
    }  
}

// Additional challenge creation validation checks go here!  

// on successful challenge creation set the current time to the players privateData  
Spark.getPlayer().setPrivateData("lastCreatedChallenge", new Date().getTime());

Try it out!

To test your challenge frequency limitation script and see it in action, choose Test Harness.

Authenticate as a player:

{  
    "@class": ".DeviceAuthenticationRequest",  
    "deviceId": "test",  
    "deviceOS": "",  
    "displayName": "testUser"  
}

Issue a challenge by sending this request:

{  
    "@class": ".CreateChallengeRequest",  
    "accessType": "PUBLIC",  
    "challengeShortCode": "testChallenge",  
    "endTime": "2020-09-17T00:00Z",  
    "maxPlayers": 32,  
    "minPlayers": 2,  
    "startTime": "2020-09-16T00:00Z"  
}  

The system responds with a challengeInstanceId, indicating that you you successfully issued a challenge

{  
    "@class": ".CreateChallengeResponse",  
    "challengeInstanceId": "5f60c3195801912d385dae96"  
}

Before 1 minute passes, issue another challenge by sending the above request again. This time the response is something like:

{  
    "@class": ".CreateChallengeResponse",  
    "error": {  
        "error": "challenge creation limit reached. please try again in 50 seconds"  
    }  
}

Limit the Number of Players in a Challenge

For example, you want to limit challenges to no more than 32 players:

// CreateChallengeRequest  
// maxPlayer check  

var maxPlayers = Spark.getData().maxPlayers  
if(maxPlayers > 32) {  
    Spark.setScriptError("error", "maxPlayers must be 32 or less");  
    Spark.exit();  
}

Limit the Length of a Challenge

For example, you want to block players from issuing challenges that last longer than 30 days:

// CreateChallengeRequest  
// challenge time length check  
var startTime = new Date(Spark.getData().startTime).getTime();  
var endTime = new Date(Spark.getData().endTime).getTime();  

var startEndDif = endTime - startTime  

if (startEndDif > 2592000000) {
    Spark.setScriptError("error", "endTime must be within 30 days of
    startTime");  
    Spark.exit();  
}

More Tips & Tricks

For more tips and tricks to build robust and scalable games, see this.