1y ago · Nov 12, 2024 2:30 PM
The Architecture Problem in Photon PUN (Photon Unity Networking)
In many indie Unity multiplayer games using Photon PUN 2 or Photon Realtime, developers mistakenly assume that only the Room Host (MasterClient) can modify Room properties.
By default in Photon PUN, **any connected client** in a room can invoke:
Because Photon Cloud acts primarily as a relay server without custom server-side game logic by default, the relay server broadcasts the new custom properties to **all clients in the room** without verifying if the sender is the MasterClient!
---
Common Vulnerable Implementations:
1. Room Name / Title in CustomProperties: Storing the room display title in allows any random player joining the lobby to rename the room or inject spam.
2. Match State / Map Selection: Overwriting or forcing map changes mid-game.
3. Score / Team Points: Client-authoritative score tracking where any client sets team scores directly.
---
How to Secure Your Photon Game (Defensive Best Practices):
1. Use Check-And-Set (CAS / expectedProperties):
Always pass so the server only applies the change if the existing value matches an expected state token:
2. Photon Server Plugins / Enterprise Webhooks (PathProperties):
On self-hosted Photon Server or Photon Enterprise Cloud, implement the plugin hook on the server side:
3. Client-Side Verification & Ignoring Non-Master Broadcasts:
In, verify if the update originated from a trusted state, or validate authoritative game rules strictly through MasterClient RPCs before accepting state transitions.
In many indie Unity multiplayer games using Photon PUN 2 or Photon Realtime, developers mistakenly assume that only the Room Host (MasterClient) can modify Room properties.
By default in Photon PUN, **any connected client** in a room can invoke:
CSHARP
ExitGames.Client.Photon.Hashtable props = new ExitGames.Client.Photon.Hashtable();
props["RoomName"] = "Hacked Room Name";
props["GameMode"] = "Deathmatch";
props["MaxScore"] = 999999;
PhotonNetwork.CurrentRoom.SetCustomProperties(props);Because Photon Cloud acts primarily as a relay server without custom server-side game logic by default, the relay server broadcasts the new custom properties to **all clients in the room** without verifying if the sender is the MasterClient!
---
Common Vulnerable Implementations:
1. Room Name / Title in CustomProperties: Storing the room display title in
CODE
customProperties["name"]2. Match State / Map Selection: Overwriting
CODE
customProperties["State"] = "Ended"3. Score / Team Points: Client-authoritative score tracking where any client sets team scores directly.
---
How to Secure Your Photon Game (Defensive Best Practices):
1. Use Check-And-Set (CAS / expectedProperties):
Always pass
CODE
expectedProperties CSHARP
// Only updates if the previous version matches
PhotonNetwork.CurrentRoom.SetCustomProperties(props, expectedProperties);2. Photon Server Plugins / Enterprise Webhooks (PathProperties):
On self-hosted Photon Server or Photon Enterprise Cloud, implement the
CODE
BeforeSetProperties CSHARP
public override void BeforeSetProperties(BeforeSetPropertiesRequest request) {
// Reject property changes if the actor is not the MasterClient!
if (request.ActorNumber != 1) {
request.Cancel();
}
}3. Client-Side Verification & Ignoring Non-Master Broadcasts:
In
CODE
OnRoomPropertiesUpdate
SecurityAudit | Secure C++ Architecture & Boundary Auditing
The following users thanked SecurityAudit for this post: