SecretService - A service for securely storing application secrets

Currently, as a developer on Roblox, it is too difficult to securely store API keys (or any other highly sensitive data) without it being in plain text in a script. While you can store secrets in a datastore, this is not perfect. Datastores are not designed for storing secrets and do not have the appropriate mechanisms for protecting them.

In my time on this platform, I have worked on many games which reach out to external services (first or third-party) and authenticate themselves with secret keys. Many of those services run critical parts of these games and, as such, a breach of those secrets would be catastrophic.

For example, I was recently hired by SizzleBurger to program their new game. This new game utilizes both PlayFab (the full service, not Roblox’s offering) and runs a first-party API for services such as group ranking and error logging. Should the secret keys to either of these services be compromised, an attacker could not only brick the entire game but could also perform group actions such as ranking everyone to the highest allowed rank or removing people from the group.

Secret vaults are an industry-standard mechanism for protecting application secrets. No matter the context, storing secrets as plain-text is not okay and is a security breach just waiting to happen.


409 Likes

If we as developers want this to get added, we need to like this post into oblivion. This is required with the “code review” situation.

Source from staff:

Storing sensitive information in plain text is just not ok.

16 Likes

One possible issue to this, is people storing secrets that contain inappropriate content shown to players.

E.g.

TextLabel.Text = SecretService:Get(“ahhh”)
-- Lets say ‘ahhh’ is a highly offensive term

A solution to this would be prohibiting secrets from being shown to the user, ever.

12 Likes

This would be a great addition! Very similar to GitHub Secrets where I can have a public repository without exposing my API keys. All I have to do is Secrets.PrivateAPIKey as opposed to actually inputting the API key.

Additionally, whenever a secret is exposed GitHub automatically makes it *** as opposed to the actual secret.

6 Likes

With the new script review system, this shouldn’t be a problem. As stated in the follow-up recently, the moderators first play the game and then search through the code for suspicious stuff. It wouldn’t be difficult to put 2 and 2 together to know someone is using the secrets service to display inappropriate things to the user.

Storing sensitive application secrets in plain-text isn’t just bad practice, it is almost always a major security vulnerability for any system. It is industry standard to store secrets at a minimum in the environment. A lot of the time you should invest in a HSM to store secrets. However, I find it very unlikely Roblox would invest in HSMs for use by games (they’re not cheap).

2 Likes

Now a lot of developers have been mentioning the concern for placing swear words within these keys. One possible solution would be for Roblox to apply their chat filter to the API string (excluding numbers), and if it returns as filtered then you would have to try a new API key or something of the sort. Of course, this wouldn’t be 100% accurate all the time, but it would be a step in the right place and might help settle Roblox’s concerns that would arise with implementing this feature.

I 100% agree that this should be an added feature. It would make development a lot easier not having to worry about exposed API keys.

2 Likes

Perhaps a solution would be only allowing these to be set as “Authorization” headers, not interacted with

HttpService:RequestWithTokenAsync("https://api.example.com/v2/credits", "GET", nil, "body", "TokenKey")

Where TokenKey is a key in the “Keys” settings under that game page.

This would obviously mean its use would be more limited (Trello, etc) to sites that utilise bearer tokens. Still better than the current situation, though.

4 Likes

The problem with that is 3rd party site API keys.

Trello for example doesn’t let you regenerate keys last time I checked (their API is actually quite inadequate compared to the use it gets, it’s just simple), so this would mean some people couldn’t use tokens.

1 Like

That would limit the service a lot, I think. Like you said not all API use bearer tokens. I still don’t think that this is an issue though, so I’m going to quote one of my replies in case you didn’t see it.

Agreed - they could have a blanket “code doesn’t send keys to clients for display” rule - this would probably resolve the issue.

2 Likes

It’s not as simple as that. To do that they would have to add a new data type to Lua. Think about it, if this service returns a string how will they know that the string is from the service when you try and send it to the client? If you actually wanted to restricted it from being sent to the client you would need a data type that is only for keys.

2 Likes

By rule, I meant enforcement - not a technical feature.
i.e. staff would identify it being sent to the client

3 Likes

Please excuse my lack of sugar-coat as I explain a valid solution to this issue.

I see people on here suggesting a new datatype. You can’t attach a datatype on a key that’s already encrypted in the first place. That’s like putting more patties on a burger until it’s no longer able to be eaten. There comes a point where too much security on an object that’s meant to be secure by design becomes worthless and/or a regression because it has been abstracted past what common sense dictates as feasible.

I also see people on here suggesting a new API. You don’t need a new API to handle one task. That’s too much work for something that can be attached to a pre-existing API that already exists. I’ll explain more as you read through this post.

First and foremost before I begin my lengthy essay, I believe that this functionality is very much needed. Storing tokens on a game that can be exploited, leaked or both is a thought that should not be attempted nor thought about in the first place. It defeats the purpose of what authentication tokens/keys do and why they’re meant to be stored in a secure place. Storing authentication data in a lua script (as a module, not a textfile… this is roblox so, for the sake of you and my sanity… I’ll use roblox terminology) is not how people do it in the industry. Authentication tokens are almost always (unless you’re naive and new to this field) stored in a secure database and fetched when needed. It is never stored freely within a game, a file on your desktop, etc.

For some odd reason, this has never been addressed and I feel like it only furthers the point that roblox wants you to use their tools over any third party. Rightfully so. I mean, who wouldn’t want a full-all-in-one solution to all their game-making needs. What roblox doesn’t realize is that their toolchain is subpar at best. You cannot force tools on developers (even more so seasoned ones) and expect them to love it. You cannot re-invent the wheel time and time again only to find failure and public outcry. Third-party tools allow us to complete tasks that the roblox platform can’t do in a feasible manner and provides experience to industry-leading technologies that can be used outside of roblox. Blocking these technologies through subtle yet prevalent means to indirectly or directly push sub-par tools only leads to the regression of this platform and the mitigation to features where users can and will benefit from.

Any who, I don’t know why I bothered to create a feasible solution to this since it’ll either be ignored like better support for plugins or stolen and rebranded into something that doesn’t help but, here we are. I have created the most roblox-istic mockup / prototype I personally thought would work. Excuse the somewhat ambiguous naming. I’m not getting paid and I did this to prove a point. Petty or not lol.

As you can see by the image, I’ve attached it to the Configure Game menu and named it Storage with its own little tab. The visualization is quite standard as most platforms that allow you to add keys use table-tags to display data. Personally, I thought that Identifier was a bit excessive but, +1 for ordered lists. The Edit button under the Actions tab allows you to edit Name or Key Data in case you generate a new token. Delete allows you to remove the key entirely from the game.

If you were in a game and you wanted to use the items you just created, I propose the following:

-- Can only be called in a server script, not a module or local script
local keys = game:GetStorage() -- Returns an array in { name = key data } ordered
print(keys["Foo"]) -- Prints out the key data value for the key named "Foo"

If you really want to create an entire service for one functionality because you feel that it’s absolutely needed, I propose the following:

-- Can only be called in a server script, not a module or local script
local keys = game:GetService("TokenService"):Fetch() -- Returns an array in { name = key data } ordered
print(keys["Foo"]) -- Prints out the key data value for the key named "Foo"

Thanks for bringing this up and I hope it gets implemented so that we can finally see support for third-party and not forced to use tools that barely meet industry standards.

14 Likes

I just realised a really neat solution to this issue - Data Stores.

local KeyStore = game:GetService("DataStoreService"):GetDataStore("Secrets")

local ApiKey = KeyStore:GetAsync("Web_ApiKey")

Perhaps worth encouraging this as best practice?

6 Likes

I agree 100% with the points you’ve bought up. The only thing I would argue is that secrets shouldn’t be visible on the website. It would make more sense to hide the keys with **** (forgot the technical term).

@EllipticCurve_DHE
Datastores aren’t designed for storing secrets. This is, technically, the best way as of now to store secrets. However, it is far from ideal. For one, you have to use a third-party plugin to actually insert and modify secrets.

It is also impossible to rotate secrets on a recurring basis. If this feature was implemented, I still find it highly unlikely that there will be native support for rotating secrets. However, it would have an API. You could use that API to rotate keys on your end via a Cron Job.

1 Like
function _G.AddKey(KeyName, Key)
	local Success, Error = pcall(function() game.DataStoreService:GetDataStore("SecretsData"):SetAsync(KeyName, Key) end)
	if not Success then
		warn(Error)
	end
end

function _G.GetKey(KeyName)
	local Success, Value = pcall(function() return game.DataStoreService:GetDataStore("SecretsData"):GetAsync(KeyName) end)
	if Success then
		return Value
	else
		warn(Value)
	end
end

I wrote these real quick, it’s not too bad.

My point is that datastores are not designed for storing keys in the first place. You shouldn’t have to use any code to store a key.

As a Roblox developer, I see a conflict of interests in the recent issues around code safety, as seen in this post.

I want to help mitigate one main issue with the review system currently in place, the security and secrecy of important API and other security Keys fellow developers use for their games.
My suggestion is very simple, but should help relieve developer’s concerns about having their keys bring seen by strangers, if their game code becomes under review.

I would like Roblox to create a ‘secure’ store, similar to that of the current data store service, that allows developers to store API Keys and retrieve them using server code when required.


TLDR
Provide a way to separate API Keys from visible game code so that Roblox moderators cannot see secret keys.

If Roblox is able to address this issue, it would go a long way to easing concerns with the current review system.

If you are a fellow developer and agree with this request, please reply below with what you would expect this feature to look like, and why you believe it is necessary.
I will be honest and say I don’t use this platform enough now to get use out of such a feature, however I’ll push this request for those concerned.

5 Likes

I think that code review should only be invoked when the code in question is proven to be malicious. Moderating codebases based on words, phrases or anything of that nature seems rather stupid as a normal user wouldn’t be able to view the contents of your codebase unless they were to exploit. Even then, they’re willingly breaking into your game for the sole purpose to gain an advantage.

I agree that a datastore should be provided to help correct this issue. However, datastores are maintained by Roblox and can still be viewed.

A way to manage secrets better should be added regardless of technical staff getting flagged to malicious code – the point is that this is basic security when working with third party apps, we shouldn’t be forced to put application secrets in our developer code, or devise unintended workarounds for this to avoid having to put it in the source (e.g. uploading to a private model inserted in the game, or in datastores, etc).

The focus for this feature request should be on that and not hinging on the code review argument because the latter is not a strong enough one for Roblox to consider implementing this. Roblox staff are not the people you should be worried most about seeing your app secrets.

5 Likes