AWS API Gateway secure an end-point - authentication

I have a Lambda function which triggered by API Gateway service, however this API is accessed by front-end application, this application not requiring the users to login or sign up to use it.
However I would like to secure my API to allow only from my front-end application.
After my research I found that I can use custom authorization in API Gateway, this custom authorization will check the authorization header of the incoming request and validate it.
the question is, can I use Amazon Cognito for something like this(implicit grant type)?
if not what is the thing that the front-end application will send to me to be validated and how can I keep it always changeable, so no one can guess it?
Thank You.

You could check the headers, but if they're always the same, someone can send an HTTP request with those headers - from any client - and trick your Lambda into thinking it's coming from your UI.
Even if you generate a unique token every time your UI is loaded and include it in the headers, someone could take that token and send requests from another client as well.
You could build fancy JavaScript tricks to make headers more dynamic, but it would only make it harder to use your API from another client, not impossible.

Related

Using AccessToken in a secure way

I have a NextJS web app and I'm adding firebase authentication to it.
I want to make secure GET calls to my server, and was wondering what is the token I should use with the server and where to set it?
Should I use the firebase user's AccessToken?
And should I send it in the URL query parameter (or header)? Aren't both alternatives exposed to whomever sees the URL and they can impersonate the user?
Thank you in advance for the help.
Are you talking about your API keys? if you are they are supposed to be visible, you need to write Security Rules which are pretty simple to use.
Read more here: Learn about using and managing API keys for Firebase
If you want your own server-side code to use the caller's Firebase Authentication credentials to ensure they are authorized for the operation they are trying to perform, you should:
Pass the users ID token from the client to your server over a secure connection. This is typically done in the Authorization header of the HTTP request.
On the server decode the ID token, and then check your own authorization logic to see if the call is allowed.
The entire process is quite well described in the Firebase documentation on verifying ID tokens, so I recommend checking that out too.

How to manage a JWT login procedure from Micronaut client to a REST API?

I am new to Micronaut and trying to develop a gateway that connects on the client side to a REST API. The API requires an authentication token which is obtained by first sending a POST requests with credentials in the body. The API is then responding with a valid token which needs to be refreshed from time to time. I am able to inject a bearer token in the headers to authenticate my requests but I do not understand whether I have to handle the whole authentification process myself or if the Micronaut framework can manage it on its own?
Thank you very much for your help.
You could create an HttpClientFilter to handle authentication, refresh and the header. You can find an example here which cover basic authentication.
Yours will be more complicated since you need to refresh etc.
Also doing this way, allow you to decouple your authentication code from your API.

Is it a security vulnerability to put TWITTER_CONSUMER_KEY / SECRET in client for oAuth1 Twitter Login?

All of the React Native Twitter Login Clients that I'm finding seem to be hard-coding the TWITTER_CONSUMER_KEY and TWITTER_CONSUMER_SECRET into the the client code, rather than relying on a server to generate tokens and/or a twitter redirect URL.
Is this safe? (e.g. couldn't a consumer then DOS the API with the TWITTER_CONSUMER_KEY, causing the app to be rate limited?)
Is this the correct way to do it?
Is there a better / more secure way?
According to twitter's documentation, it seems like this is NOT the correct way to do this:
"In the event that you believe that your API keys has been exposed, you should regenerate your API keys by following these steps" - Authentication best practices
Examples which specify that the consumer key/secret should be hardcoded:
https://rnfirebase.io/docs/v5.x.x/auth/social-auth#Twitter
https://github.com/GoldenOwlAsia/react-native-twitter-signin/blob/master/Example/TwitterButton.js#L14
Related questions:
Twitter consumer secret really a secret?
Is it a security vulnerability
Yes.
Your app can be rate limited or flagged as malware/spam etc.
Is there a better / more secure way?
Basically only to have your own site auth (oauth2) done correctly and proxy specific requests from your clients, after validation or a simplified locked down site API that is then translated to the Twitter API.
Why is this, Twitter app-only auth supports OAuth2, allows a secure negotiated handshake and then requests made using a Bearer token. In this mode you can make requests on behalf of your App, but without a logged in user. So can't post tweets or see private accounts or read DMs.
For user-auth, Twitter only support OAuth1 and both the App and User are authenticated, but using a model that assumed plaintext http, so can't share a single token. Every single request needs to be made using consumer key/secret and signing the request. So there isn't a way to do this from a javascript client safely.
Is this safe?
Absolutely not. A bad actor can get users to authenticate via Twitter to receive their token credentials and then use your app's consumer key/secret (which would be available in plain text) to masquerade as your app to do all kinds of nasty stuff.
Is this the correct way to do it?
Given the security vulnerability described above, no.
Is there a better / more secure way?
I'm currently in the process of trying to figure out how to securely achieve authentication with Twitter. This involved a lot of reading, but it appears as though it's simply not possible without your own backend. I'll try and explain why:
Your goal is to receive the user's email/Twitter-ID
To achieve (1), you need to send a request to the GET account/verify_credentials endpoint (https://developer.twitter.com/en/docs/twitter-api/v1/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials).
To do (2), you need to provide an authorisation header, which is constructed out of several items, including the user's OAuth tokens as well as your app's consumer key/secret. More info here: https://developer.twitter.com/en/docs/authentication/oauth-1-0a/authorizing-a-request.
You retrieve the user's OAuth tokens using the 3-legged OAuth flow
described here: https://developer.twitter.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens. The first step of this process is to send a POST request to the oauth/request_token endpoint (https://developer.twitter.com/en/docs/authentication/api-reference/request_token).
This endpoint itself requires an authorisation header constructed using
your app's consumer key/secret.
Obviously you can't perform step (4) because that implies you would have your consumer secret available in the client; even if it's not hardcoded, it would have to be in memory at runtime, at some point
Once you have your own backend service, one option would be for your client app to open a browser and direct to an endpoint (let's call it /auth/twitter) on this service which will perform all the steps mentioned above.
This same service could also implement another endpoint (/auth/twitter/token) which handles requests to the callback URL, which you set in your Twitter app settings. This callback URL is used as part of the same 3-legged flow. This endpoint would have all the information needed to then go ahead and retrieve the user's email/Twitter-ID.
Finally, /auth/twitter/token can redirect to a custom URL which your client app would need to handle as part of its URL schemes. It can include enough information by way of parameters for your app to continue as needed post-auth.

Where should the access token be placed at successful login?

I'm planning an API and I haven't found any information about where the access token should be placed in the response. I'm interested in the case where I'm providing the access token. What is the best practice to send the token to the clients (from the backend service)?
Should it be sent to clients in the Header or in the Body of the answer?
You should look at examples and see what others do. For example, Facebook, Twitter, Google, Amazon... and all those popular PaaS services exposing a REST API all use OAuth2 as authentication mechanism:
In OAuth2 you'll see the specification requires to send the generated token to the client in the body of a json response: https://www.rfc-editor.org/rfc/rfc6749#section-5 . But you can also see how Google and other vendors extend this mechanism so it can be sent as a callback url param, for example (Check out https://developers.google.com/identity/protocols/OAuth2UserAgent).
Once you get the authorization token you put it on the Authorization: HTTP header you send on your requests for accessing protected resources. They have to support this way of doing it, because it is how the OAuth2 standard specifies it https://www.rfc-editor.org/rfc/rfc6749#section-7
If you want to tinker a little bit more with oauth, check out https://developers.google.com/oauthplayground
(OAuth is pretty much the same thing.)
They usually also extend the Authorization header mechanism to allow the token to be provided as a GET/POST parameter in the url or the body of the response, respectively (For example, Facebook's Graph API also supports passing an access_token= parameter on your HTTP POST request body or GET URI). There is no way to manipulate or even read HTTP headers on a javascript browser application (see the modern fetch API and other proposals on Accessing the web page's HTTP Headers in JavaScript), so providing this functionality makes life easier for many app developers.
Another popular authentication scheme is SOAP authentication. It doesn't support tokens but it supports digest authentication, which is a similar thing. The interesting part of it is that it is not HTTP/Web based (although it is primarily used that way), so you can use it over other application protocols. It's a little more cumbersome, but you can find ready to use implementations for both server and client.
You can also use digest authentication over HTTP without SOAP. It is also based on Authorization: headers and every browser supports it. Check out https://en.wikipedia.org/wiki/Digest_access_authentication to see how the authorization headers are formed in different ways depending on the level of security you want to reach.
Some services, like redmine, allow you to use an API token (API key) instead of a session token. Then you can make basic http auth on your requests like https://whatever:yourapikey#example.com/protectedMethod, although passing of auth data on URLs is currently deprecated in favor of basic auth header, and plain passwords / static API keys should only be sent over secured SSL connections. In this case the client can have the server generate an api key using a web interface or a rest api (so the generated key will be passed as a JSON response). This method may not be such a good idea, though: Check http://talks.codegram.com/http-authentication-methods#/intro if you want to know why, and also this question discussing where to put them: Where should I place API keys in REST API calls?

“Shared” authentication for website and RESTful API

Goal: My server needs to direct non-users to a landing/home page, and logged in users to the actual app. When the app is loaded, it will make authenticated HTTP requests to a RESTful API (via Ajax).
I have a RESTful API that needs authentication. On another server I have my website, which also needs authentication, so I can determine whether to display the landing/home page for non-users or the app for logged in users.
Initially I thought it would be enough to implement HTTP Basic Auth for the RESTful API. However, in order to get authentication running for my website too, I would also need to setup authentication there, which would mean duplicating the low-level code to check the credentials in the database in both the REST API and the website servers.
Alternatively, I wondered if the website could authenticate via the RESTful API. For example, in my request handler for POST /login, I could make a GET request to my API, passing along the user credentials from the request body. If the request returns 200 OK, I could sign the user’s session, thus authenticating them. From there onwards, the Ajax requests to the REST API need to be authenticated with the same credentials, so I could:
set a cookie containing the credentials, thus allowing the JavaScript to retrieve the credentials before doing the request (OK with SSL?)
dump the credentials in the served HTML for the web app thus allowing the JavaScript to retrieve the credentials before doing the request (OK with SSL?)
proxy the API through the web app server, where I could retrieve the credentials from the session and add them to the Authorization header of the proxied request?
Alternatively, I imagine I could just share a session between the two servers, although I’ve heard that’s bad practice for RESTful design.
What would be wrong with doing it like this? Is there a better way to meet my goal?
I recently implemented something similar to this (assuming I understand you correctly), and there seemed to be a few viable options.
Have the server side of your web-app always authenticate with a specific username/password when accessing the REST API, ensuring that your web-app is always trusted and assuming that users are properly logged in on the web-app if a request is authenticated as the app.
Pros: Easy to implement, easy to understand, easy to extend for other applications as well (we had a CLI that accessed the same REST API as well).
Cons: It's impossible for the REST API to know which user is actually accessing it. If a trusted client is compromised the whole system is compromised.
Have the server side of your web-app keep user details in the session and authenticate using the users credentials every time you access the REST API.
Pros: Fairly easy to implement (although some authentication mechanisms make it hard to keep hold of the user password - for good reason). The whole procedure is transparent to the REST API.
Cons: You're now storing (for all intents and purposes in clear-text) the username and password of a user in the session of the web-server - one of the most prime targets for attack in the system.
Create an authentication system on the REST API that authenticates a request with a username/password authorization and returns a token that is valid for a limited time.
Pros: More secure, if your web-app is compromised you're not providing the attacker with your users username/passwords, but instead only allowing them a limited time access.
Cons: Much harder to implement. You might need to deal with token timeouts specifically. For purists it also means that your REST implementation (or at least the authentication system) will be arguably "stateful".
What you should implement would depend on your situation. Personally I'd definitely go with the more secure option (the last one), but due to external constraints we were forced to implement the first option in our specific case (with the promise we'd revisit it and upgrade later - unfortunately later never comes).
I think your approach with using Basic HTTP Authentication in REST service and having your app authenticate with the service is perfectly fine. The only caveat here (which I am sure you are aware of), is that your REST service should run over SSL, as Basic HTTP authentication is not very secure - username and password are just Base64 encoded.