Skip to main content

Mobile Game Security: Accounts, Data and Purchases

Protect a mobile game with server-side validation, secure sessions, careful secret storage, purchase checks and tested recovery.

R
Written by Reiko

Mobile game security protects account access, progress, purchases, inventories and competitive results. Each of these needs a clear source of truth and a recovery process. Encryption, anti-cheat tools and app integrity checks address different risks; none replaces the rest of the design.

Draw a trust boundary for valuable operations

For each reward, purchase and account change, identify what the client requests and what the server can verify independently. A client may report that a level ended, but a competitive reward needs evidence consistent with permitted game actions. The exact validation depends on the game model. Record the authoritative account, inventory ledger and transaction identifier so an engineer can trace a disputed grant.

Test access to another account's object by changing a harmless identifier in a controlled environment. The server should reject the request even if the client hides the object in its UI. A valid login proves who the caller is; it does not prove that the caller owns every referenced save, purchase or shared-room record.

Treat the game client as untrusted input

A player controls the device running the app. Local files, memory and outgoing requests may be modified. If a client requests a reward, the backend should verify the reason for that reward and check whether it has already been granted.

Use unique operation identifiers for valuable actions so retries do not duplicate a reward or a debit. Validate access to each requested object: knowing another player's profile or inventory ID must not grant permission to read or change it. Competitive systems also need checks that submitted actions are plausible under the game's rules.

Exercise retries and concurrency against the ledger

Send the same reward operation twice, then send two copies concurrently. If both return success, the ledger must still contain one grant for that logical event. Next force the server to commit while the client loses the response, and repeat the request using its original operation identifier. The result should reconcile to the same grant, not create another balance change.

For a spend action, test insufficient balance and two simultaneous purchases that each would individually fit but together would exceed the account's available amount. A client-side button disable is not a concurrency control. The server needs an atomic decision or another explicitly designed consistency rule. Compare the displayed balance after both replies with the authoritative ledger, including a process restart.

Protect sign-in and account recovery

  • Use HTTPS with correct certificate validation.

  • Limit session lifetimes and provide a way to revoke sessions.

  • Rate-limit sign-in and recovery attempts without making denial-of-service against a player easy.

  • Require appropriate reauthentication for sensitive account changes.

  • Let users terminate other sessions after suspected compromise.

If the project handles passwords itself, store salted password hashes using a suitable password-hashing scheme such as Argon2id. Do not keep reversibly encrypted passwords so they can be sent back to users. When using an external identity provider, validate its tokens on the backend, including their intended audience and expiry.

Device biometrics can protect local access to a stored secret, but they do not replace server authorisation. Recovery codes and reset links need limited lifetimes and one-time use. A successful recovery should allow suspicious sessions to be revoked.

Review the account recovery boundary

Run password reset, provider reauthentication and device loss as separate scenarios. Confirm that a reset link cannot be reused after success and that a link for account A cannot change account B. Check what happens to existing sessions after a credential change according to the product policy. If the app offers “sign out everywhere,” verify it across at least two devices rather than checking only the current screen.

Support staff need a route to investigate an account without receiving its password or one-time code. Provide a non-secret case reference and narrowly scoped logs. A request to merge two profiles should require proof of control over both identities and a recorded decision about inventory conflicts. Otherwise recovery becomes a path for moving another person's assets.

Store secrets according to their purpose

On iOS, Keychain can hold small sensitive values. On Android, Android Keystore holds cryptographic keys that can protect locally stored data. Keystore is not a general database for arbitrary save files. Hardware protection depends on the device and configuration.

Keep privileged backend credentials and administrative secrets out of the app package. Obfuscation can slow inspection, but it cannot make an embedded secret reliably inaccessible. Exclude passwords, access tokens and private-message content from analytics and crash logs.

Use integrity signals alongside gameplay checks

Play Integrity on Android and App Attest on Apple platforms provide additional evidence about the client. App Attest requires server validation of attestation and subsequent assertions; fresh server challenges help defend against replay. These signals support an anti-abuse strategy rather than proving that every action is legitimate.

Observe results before enforcing new restrictions. A temporary service failure is different from confirmed fraud. Define fallback handling and escalation for sensitive actions, and provide a way to review mistaken restrictions. Validate gameplay and account permissions even when an integrity check succeeds.

Risk

Main protection

Verification

Forged results

Server validation of allowed actions

Impossible-state and anomaly tests

Duplicate rewards

Unique operation records

Repeated and concurrent request tests

Stolen sessions

Protected storage and token revocation

Expired and revoked session tests

Lost progress

Versioned saves and backups

Restore exercises using old data

Verify purchases before granting items

Check the transaction, current state and association with the intended account. In Google Play, a pending purchase should not grant the paid entitlement. Track processed purchase tokens to prevent duplicate delivery, and implement acknowledgement or consumption as appropriate for the product.

For Apple purchases, verify signed transaction information using a supported approach and process server notifications when the architecture uses them. Handle refunds, interrupted delivery and repeated events. Keep test and production environments distinct.

Test purchases throughout development. Apple's Xcode tools and sandbox support purchase testing, and TestFlight uses the sandbox for in-app purchases. Include cancellation, restoration and delayed delivery in the test plan rather than testing only a successful payment.

Test data protection beyond login

Look for secrets in crash reports, analytics events, local backups and exported logs. A secure transport does not prevent sensitive data from being copied into a diagnostic field. Generate test events with synthetic account details, inspect the resulting payloads and remove fields that are unnecessary for debugging. Confirm that account deletion or sign-out follows the product's retention policy for local caches and pending uploads.

Run a restore exercise with a known backup: record the latest transaction before backup, restore to a test environment and reconcile the gap. An untested backup is only a stored file. Document who can initiate a restore, which systems are affected and how duplicate events are handled when services resume. This is particularly important for a game economy where an old snapshot could otherwise reissue spent currency.

Prepare for data loss and incidents

Collect the data needed for the feature and restrict staff access by role. Define retention and deletion behaviour. Backups need regular restore tests: the team should know which records can be recovered and how much recent activity could be lost.

Before release, test expired sessions, access to another account's objects, replayed requests, damaged saves and forged payment messages. Assign an incident owner and a way to disable an exposed feature quickly. A response plan should cover secret rotation, session revocation where needed, root-cause correction and communication with affected players.

Build a small abuse test set for each privileged endpoint: an expired token, a token from a different account, a duplicate operation identifier and a replayed request after logout. Check both the response and the resulting ledger. A rejected response is not sufficient if a side effect was committed before the authorization check. Store the test identifiers and expected outcomes with the release evidence so a future backend change can rerun the same cases.

Did this answer your question?