Security concerns with Unreal Engine AWS Plugins

So a number of plugins have been published on the Unreal Engine Marketplace promising to make integration with AWS GameLift, Cognito, and Lambda, easy and just through blueprints (no c++).
My team would like to use such plugins especially related to AWS Cognito.

However, looking through their tutorials it seems like some of the practices they are using are not secure.

Specifically, in this part of the Aws Cognito tutorial it shows to put in your Aws Access ID and AWS Secret Key to create a Cognito Idp object on the game client. This seems to just be a blueprint wrapper over the CognitoIdentityProviderClient constructor in CognitoIdentityProviderClient.h of the aws-cpp-sdk.
I was under the impression that you could not trust the game client with anything in terms of keys or credentials, never mind an AWS Secret Key. Similar credentials are used in the GameLift plugin when creating game sessions from the client (again not a good practice?).

I would love to get some of the AWS staff’s take on this. Am I incorrect about this security practice? Is it fine in production as long as the credentials you are adding to the client is one of an IAM user that has limited permissions just for these few functions?

Along the same lines but maybe less of an issue: it shows to implement the signup and authentication again on the client. Wouldn’t it be a better practice to put the proposed username and password in an HTTPS request to an API Gateway that then runs this Cognito function on say a Lambda that then communicated the result to the game server that then communicates back to the game client?

I assume its ok to put the Aws Cognito app client id on the game client?

Any input on this would be appreciated. Cheers!

I will give my opinions formed from the research I have done, but I am definitely also interested in what an AWS Staff member has to say about this topic. Let me first provide this picture from the documentation.

According to the docs, it is recommended to call GameLift, Cognito, and other AWS services through a client service. It seems from a lot of the forum posts that a popular option is to call Lambda APIs via http requests. From what I believe, the reason for this is because it can be dangerous to leak secret keys to the client. If you call specific AWS services directly from the client, you need credentials to call those specific AWS services. If someone has these credentials, then there is no limiting of how often they can call those AWS services unless those credentials are manually revoked. On the other hand, if you handle everything through authorized Lambda functions, you have more control over how the AWS service is being used. For example, if the function is authorized via a token, you can limit how many times a specific user identified by a token can call this AWS service in a certain amount of time. It is not the best example but it just shows that you can surround additional logic around an AWS SDK function call to help further make the architecture secure.

My only concern with even temporary AWS credentials is that at this moment, they can’t be invalidated. Temporary AWS tokens will last their full lifespan of an hour no matter what. However, refresh tokens can be invalidated at any time so keep this in mind. For more information about best practices regarding AWS credentials, check out this link: https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html

As for your last question about the Cognito client id, I believe that this is safe to expose. Here’s a stackoverflow answer that talks about it, https://stackoverflow.com/questions/39649899/is-it-safe-to-expose-the-aws-cognito-ids, but there are a lot of forum posts that talk about this topic.

1 Like

@Pip Any insights on this from y’all?

@WillWM - your instincts are right. Ideally, you should not really have any long term static credentials on the client side esp in discoverable places as they will be abused and are hard to change/rotate once in the wild.

Now, a lot of software developers think about just development (ie how do I get this working, rather than what should I do in production) or make assumptions that you have already gotten credentials from somewhere as everyone does it differently. So you may see patterns like those of the UE4 plugin developers.

The recommendation is that you always fetch and use your credentials (which are short lived session based) in memory like Cognito etc.

Chris already posted a good link, where if you replace the word ‘mobile’ with ‘games’, you can see what you should do:
https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html

Basically, clients should never be trusted to be the source of truth, all their input should be sanitized/checked and any credentials/permissions they have should be easy to revoke/remove.

Obviously you may have some specific use cases where you may not a strong identity to tie credentials too such as launch/pre-login metrics. But even those should be designed with abuse in mind and with extremely limited permissions/functionality with throttles and best-case delivery.

As to the video, Client side authentication is cheaper (fewer lambda calls etc), faster and easier for most folks to build and in the mobile space where its easy to push updates, it can work. Server side will be more secure but, requires just that a server, which can quickly require more expense/development time/outlay then people have. In both cases I believe you can use lambda triggers to further secure your flows. There are probably some great best practice documents on client side auth (will try and dig some up).

Is it "ok to put the [Aws Cognito app client] id on the game client? "

From the docs they state “It is your responsibility to secure any app client IDs or secrets so that only authorized client apps can call these unauthenticated APIs”. However, if you are doing client side auth then you probably need these client side and you probably aren’t using a secret in this case.

Oh and you can also use Cognito Authorizers directly with APIGateway: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html which gives you some different controls to handle auth wrt to serverless style ‘game services’

2 Likes

Just want to add that you can avoid putting the Cognito app client id on your game client by authenticating your user through a Lambda function and then of course have your client call that function. This is still client-side authentication and currently the approach I am using to avoid putting any Cognito user pool information on the client directly.

1 Like

Thanks, @Pip for your take on this. Glad that I’m not the only one who thought the plugin’s implementation wasn’t a good method for production.

Also thanks @chrisgong for your thinking on this.

After doing some reading I’m still a bit unclear about how the implementation of the initial unauthorized functions (a.k.a. signup, login, & forgot password) could be called securely.

The lambda triggers that Pip alluded to seem to be additional checks and experience improvements that are triggered at specific intervals on the Cognito calls. For example, the pre sign-up lambda trigger could be used for additional validation checks. However, from the examples I have seen it would seem that we would still have to call CognitoIdentityProviderClient::SignUp(const SignUpRequest& request) from our game client to have the lambda trigger fire. We would still need the aws credentials in the client to create the CognitoIdentityProviderClient object to call it, which is exactly what we wanted to avoid.

The other way I can see around this is just to have the game client send an HTTPS request, say for a signup, with the proposed username and password. That hits the api gateway that hits a lambda function that then (if we’re using python) calls the signup method on cognito-idp in boto3. The Client Id, Secret hash, etc would then just be on the lambda and never exposed to the game client. One could then do a similar dance from the game client to a different lambda to confirm_sign_up . Easy enough to do the same thing for login and forget password.

The second method seems more secure and straight forward, but (at least from my research) it does not seem to be common which makes me hesitant as I may have overlooked something.
Maybe its too easy for an attacker to flood the api gateway with requests to login, requiring us to ro throttle it and hence not allowing legitimate users through?

After authentication, it seems straight forward enough to use Cognito Authorizers directly with APIGateway (as Pip pointed out) to make sure that the HTTPS requests to the matckmaker are done securly. Its just how to get users authenticated in the first place that I am unclear on.

If you’re going for client-side authentication, which seems to be a popular option due to the allure of serverless, you can use the auto-generated UI from Cognito user pools for the functions that you mentioned. For example, signup, login, and forget password are all taken care of by that UI. For more information on that, you can follow the steps outlined here:

https://docs.aws.amazon.com/cognito/latest/developerguide/getting-started-with-cognito-user-pools.html

You can of course later on make your own UI to better customize it. Here is a good article on how to do that, https://medium.com/@gmonne/custom-authentication-using-aws-cognito-e0b489badc3f

You can also do this in Unreal Engine as well, I just could not find any good examples. The quickest solution is to use the auto-generated UI in the web browser widget in Unreal Engine. Of course, you can also make a program separate from Unreal Engine for logging in, signing up, etc. If you choose to do something like that or making your own UI, then that medium article I linked above would be good for recognizing the patterns you would need to follow. Just a note that in the medium article, the user makes the cognito user pool and client id public. However, I will then point out that the auto-generated UI link has the client-id in it. At the end of the day, in my opinion, this is better than sending username and password data to a API through an http request. Even if encrypted, you don’t want to risk those man-in-the-middle attacks regardless. It is better to do everything strictly through Cognito when it comes to login, signup, forget password, etc., because it is more secure. I am not sure exactly how Cognito is more secure because that is outside of my direct knowledge scope.

The point of this is that, assuming you are using the authorization code grant flow for client-side authentication, after successful authentication, you will now have a code. This code can be used to retrieve a temporary access token as well as ID and refresh tokens. For more information about the token endpoint, check out this link, https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html

Another good read on AWS credentials and Cognito in general: https://theiconic.tech/authentication-an-in-depth-look-at-aws-cognito-658336515169

1 Like

Hmmm yeah I have setup the auto-generated UI for a test. Thanks for the insight and the helpful links. Gmonne’s article was especially helpful. I did notice that he specifies “To keep this information [“User Pool” id & client id] private I created a config.js file that saves this information on two global variables.”

I’ll try doing something close to gmonne’s article but would like to build the UI in ue4 so will also try to investigate other methods to do that (likely with the aws-sdk-cpp).

why not use SRP directly in unreal? this cognito plugin support SRP. Advanced Login System SRP(edited version) - YouTube and tracking the device Advanced Login System device track and advanced security features(edited version) - YouTube and with MFA Advanced Login System MFA(edited version) - YouTube
and login with SRP is what the cognito UI did in js.

Will,
Were you able to get the aws-sdk-cpp into your project? I’m trying to do the same as you, but am having trouble getting the sdk into my visual studio functionality. Can’t get things linked.