Search Unity

Feedback Prevent direct writes from the client = server authoritative solution

Discussion in 'Cloud Save' started by DavidZobrist, Jan 17, 2022.

  1. DavidZobrist

    DavidZobrist

    Joined:
    Sep 3, 2017
    Posts:
    234
    For a pure server authoritative solution we never want the client to directly create or change the data in cloud save database. Clients only should be able to get their data sets.

    What we need would be an option to prevent save calls from the client while they are still able to get their data.
    We change / create already via cloud code.

    Is there anything like this planned?
     
  2. DavidZobrist

    DavidZobrist

    Joined:
    Sep 3, 2017
    Posts:
    234
    Yes.

    I got a cloud code function for creating specifc cloud save entries with its default values.
    How ever I work on it right now and for now It takes the start value aswell from the client.
    But the initial value will be taken from the remote config later on.
    So no values are set by the client. It only initialy sends the required key / ID.

    CreateCloudSaveData

    Code (JavaScript):
    1. const {
    2.   DataApi
    3. } = require("@unity-services/cloud-save-1.0");
    4.  
    5.  
    6. module.exports = async ({
    7.   params,
    8.   context,
    9.   logger
    10. }) => {
    11.  
    12.   const {
    13.     projectId,
    14.     playerId,
    15.     accessToken
    16.   } = context;
    17.  
    18.   const api = new DataApi({
    19.     accessToken
    20.   });
    21.  
    22.  
    23.   const setResult = await api.setItem(projectId, playerId, {
    24.     key: params.saveGameID,
    25.     value: params.value // this later should be taken from the remote config
    26.   });
    27.  
    28.  
    29.   return true;
    30. };
     
  3. DavidZobrist

    DavidZobrist

    Joined:
    Sep 3, 2017
    Posts:
    234
    So right now the client call:
    Code (CSharp):
    1. await SaveData.ForceSaveAsync(new Dictionary<string, object>(){{"anySaveEntry",dataType}});
    could overwrite the cloud code create cloud save entry.
     
    Last edited: Jan 18, 2022
  4. DavidZobrist

    DavidZobrist

    Joined:
    Sep 3, 2017
    Posts:
    234
    I like the option to get it tough.

    Code (JavaScript):
    1. loadedServerData = await SaveData.LoadAllAsync();
     
  5. DavidZobrist

    DavidZobrist

    Joined:
    Sep 3, 2017
    Posts:
    234
    I try to not use the ForceSaveAsync option, so this is an example.
    Just if I work with other coders aswell as for maybe ungrounded security reasons I would like to block this somehow.
    But we can also watch out to never use it ourselfs however if some clever player which is signed in can imitate that call he could exploit it aswell. (correct me here)

    Maybe our solution is also to not import the cloudsave sdk at all and just retrieve all cloudsave entries through an cloud code call.


    Right now we try to use the cloud save sdk only for
    Code (CSharp):
    1.  
    2. loadedServerData = await SaveData.LoadAllAsync();
    to get all cloud save entries for the client at the beginning.
     
  6. DavidZobrist

    DavidZobrist

    Joined:
    Sep 3, 2017
    Posts:
    234
    Here is how we change cloud save entries via cloud code:
    (example resource types: wood, xp etc)


    Also work in progress. We would not just increment by +1.
    But based on the related resource level ( another cloudsave entry) and the specific formula.

    ChangeResource

    Code (JavaScript):
    1. [code=JavaScript]const {
    2.   DataApi
    3. } = require("@unity-services/cloud-save-1.0");
    4.  
    5.  
    6. module.exports = async ({
    7.       params,
    8.       context,
    9.       logger
    10.     }) => {
    11.  
    12.       const {
    13.         projectId,
    14.         playerId,
    15.         accessToken
    16.       } = context;
    17.  
    18.       const api = new DataApi({
    19.         accessToken
    20.       });
    21.  
    22.  
    23.       let {
    24.         data: response
    25.       } = await api.getItems(projectId, playerId, params.resource);
    26.  
    27.  
    28.       // TODO get the increment based on the current level from the related
    29.        //TODO impl. formula using the level to determine the increment amount
    30.  
    31.       let changedVal = response.results[0].value + 1;
    32.  
    33.  
    34.       const setResult = await api.setItem(projectId, playerId, {
    35.           key: params.resource,
    36.           value: changedVal
    37.         })
    38.  
    39.         return changedVal;
    40.       }
    [/code]
     
  7. DavidZobrist

    DavidZobrist

    Joined:
    Sep 3, 2017
    Posts:
    234
    I learned a lot about function injection and variable manipulation on the client recently as a follow up to this thread:

    Example:


    While this is on Mono and not IL2CPP i am sure there is simular stuff to change variables and execute / injection own function calls into clients.

    Our solution for this problem to be pure server authorative is to remove the cloud save SDK completly.
    And retrieve all save values via function aswell as only change the values via cloud function in the cloud save db.
    Aslong the client can determine the save value its never save, we never send any values only requests and the cloud function validates going through cloud save variables and the remote config.
     
  8. DavidZobrist

    DavidZobrist

    Joined:
    Sep 3, 2017
    Posts:
    234
    Here method injection on IL2CPP unity games:
     
  9. DavidZobrist

    DavidZobrist

    Joined:
    Sep 3, 2017
    Posts:
    234
    I think its beyond this topic but unity should have its on obfuscator atleast to increase client security.
     
  10. Laurie-Unity

    Laurie-Unity

    Unity Technologies

    Joined:
    Mar 5, 2020
    Posts:
    220
    Hi David,

    Looping back on this post, thanks for sharing those videos and your insights, you raise a very valid point. Economy and Cloud Save are still in Beta and we are very pleased to receive this kind of feedback as it helps to inform our roadmap.

    Whilst not all implentations will need to be fully server authoritative, we are considering options to improve security from the client, including the option to allow you to disable modifying Economy and Cloud Save write operations from the client. I can't provide any more detail at the moment, but we will keep this forum updated with any news on incoming features.
     
  11. LilGames

    LilGames

    Joined:
    Mar 30, 2015
    Posts:
    570
    Playfab's dashboard has simple checkboxes for a few of these exploitable write permissions. eg: "Allow Client to add virtual currency". They even have a helpful warning that if you turn that on then players could cheat.

    It's odd Unity wouldn't have followed the same model as a competitor that's been around since at least 2016. You should try to build a service that current PlayFab users will want to switch to. That means supporting the same features and improving the competition's deficiencies. A secure backend is a major priority.
     
    DavidZobrist likes this.