You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
security-tactics improvements and additions (Roblox#8)
## Changes
<!-- Please summarize your changes. -->
I made the following changes to improve pre-existing code:
- The `typeValidator` tuple type validator in the Remote Runtime Type
Validation was created on-the-fly every single time a request was made
from the client. If something can be made once and reused infinitely, it
should be!
- Instead of throwing an error on the server when the `typeValidator`
type check fails, which could trigger analytics requests and other heavy
error handling logic (among other things) on an event that is *not* rate
limited, it silently fails and returns that information to the client to
receive, display and act on accordingly. In this example it isn't a
fatal error that should be logged in that way.
- Adjusted some of the "highlight" data in the Lua code blocks. I
presume these are used to highlight important parts of the code samples,
though I've never seen this myself on the creator docs. Regardless, they
should be more accurate for the code snippets now.
I added the following additions to the article:
- Added an example of "instance spoofing" under Data Validation that
ties in with the existing "In-Experience Shop" example. This is an
incredibly common and easily overlooked exploit that can be taken
advantage of in many games, and definitely deserves a spot in this
article.
- Added an in-depth list of various attacks that can prevent DataStore
saving from malicious client input under the right circumstances, and
how to prevent them. The listed attacks can be detrimental to games and
could result in item duplication among other game-breaking actions based
on the type of game.
I've given everything a good look over based on the style guide and
rewritten a lot from my initial draft. Please correct anything that I
might've missed. Cheers!
<!-- Please link to any applicable information (forum posts, bug
reports, etc.). -->
## Checks
By submitting your pull request for review, you agree to the following:
- [X] This contribution was created in whole or in part by me, and I
have the right to submit it under the terms of this repository's open
source licenses.
- [X] I understand and agree that this contribution and a record of it
are public, maintained indefinitely, and may be redistributed under the
terms of this repository's open source licenses.
- [X] To the best of my knowledge, all proposed changes are accurate.
ifnotcreatePartTypeValidator(player, partColor, partPosition) then
89
+
-- Silently return "false" if type check fails here
90
+
-- Raising an error without a cooldown can be abused to bog down the server
91
+
-- Provide client feedback instead!
92
+
93
+
returnfalse
94
+
end
85
95
86
96
print(player.Name.." requested a new part")
87
97
localnewPart=Instance.new("Part")
@@ -113,6 +123,52 @@ local function isInf(n: number): boolean
113
123
end
114
124
```
115
125
126
+
Another common attack that exploiters may use involves sending `Library.table|tables` in place of an `Class.Instance`. Complex payloads can mimic what would be an otherwise ordinary object reference.
127
+
128
+
For example, provided with an [in-experience shop](#in-experience-shop) system where item data like prices are stored in `Class.NumberValue` objects, an exploiter may circumvent all other checks by doing the following:
129
+
130
+
```lua title="LocalScript in StarterPlayerScripts" highlight="5, 17, 20"
-- Check if the passed item isn't spoofed and is in the ItemData folder
161
+
iftypeof(item) ~="Instance" ornotitem:IsDescendantOf(itemDataFolder) then
162
+
returnfalse, "Invalid item provided"
163
+
end
164
+
165
+
-- The server can then go on to process the purchase based on the example flow below
166
+
end
167
+
168
+
-- Bind "buyItem()" to the remote function's callback
169
+
buyItemEvent.OnServerInvoke=buyItem
170
+
```
171
+
116
172
### Value Validation
117
173
118
174
In addition to validating [types](#remote-runtime-type-validation) and [data](#data-validation), you should validate the **values** passed through `Class.RemoteEvent|RemoteEvents` and `Class.RemoteFunction|RemoteFunctions`, ensuring they are valid and logical in the context being requested. Two common examples are an [in-experience shop](#in-experience-shop) and a [weapon targeting](#weapon-targeting) system.
@@ -144,6 +200,17 @@ Imagine a game where a player can fire a laser beam at another player. Rather th
144
200
- Confirm that the hit player is alive.
145
201
- Store weapon and player state on the server and confirm that a firing player is not blocked by a current action such as reloading or a state like sprinting.
146
202
203
+
#### DataStore Manipulation
204
+
205
+
In experiences using `Class.DataStoreService` to save player data, exploiters may take advantage of invalid [data](#data-validation), and more obscure methods, to prevent a `Class.DataStore` from saving properly. This can be especially abused in experiences with item trading, marketplaces, and similar systems where items or currency leave a player's inventory.
206
+
207
+
Ensure that any actions performed through a `Class.RemoteEvent` or `Class.RemoteFunction` that affect player data with client input is sanitized based on the following:
208
+
209
+
-`Class.Instance` values cannot be serialized into a `Class.DataStore` and will fail. Utilize [type validation](#remote-runtime-type-validation) to prevent this.
210
+
-`Class.DataStore|DataStores` have [data limits](../../cloud-services/datastores.md#data-limits). Strings of arbitrary length should be checked and/or capped to avoid this, alongside ensuring limitless arbitrary keys cannot be added to tables by the client.
211
+
- Table indices cannot be `NaN` or `nil`. Iterate over all tables passed by the client and verify all indices are valid.
212
+
-`Class.DataStore|DataStores` can only accept valid UTF-8 characters. Sanitize all strings provided by the client to ensure only bytes 1-127 are used. By using `Library.string.find()` with the pattern `"[%z\128-\255]"`, an operation can be aborted if any invalid characters are found in a string.
213
+
147
214
### Remote Throttling
148
215
149
216
If a client is able to make your server complete a computationally expensive operation, or access a rate-limited service like `Class.DataStoreService` via a `Class.RemoteEvent`, it's critical that you implement **rate limiting** to ensure the operation is not called too frequently. Rate limiting can be implemented by tracking when the client last invoked a remote event and rejecting the next request if it's called too soon.
0 commit comments