App attest seems to sign the payload of a request with the private key of a key pair.
App check handles different providers than app attest:
DeviceCheck or App Attest on Apple platforms
Play Integrity or SafetyNet (deprecated) on Android
reCAPTCHA v3 or reCAPTCHA Enterprise on web apps
I would like to know:
Does firebase app check signs the payload on those 3 providers ?
Where is the private key stored with the recaptcha version ? I can understand a semi secure storage mechanism on mobile, but it's harder to grasp in a browser.
If indeed the payload is signed on all platform, firebase app check doc is a bit vague on the security it provides, it says it prevent some attack vectors but not all.
What are those attack vectors ?
The payload cannot be tampered with, thanks to the key signature, but
How is the private key content protected since it is on device ?
If on the other hand the payload is not signed:
What the heck does it protect against and how ? Recaptcha monitors human behaviors, so maybe it monitors that a request was indeed sent after a click / user input and not via curl by periodically requesting the human / bot score and adding a token to the request ? This is conjecture, this is obscure is all I'm saying.
Related
Let me clarify my use case:
I have a next.js application which is a plattform for listing real estate objects. I have several api routes which im using inside my next.js app. for example:
/api/createpost ->
Takes informations from my form on my next.js app and creates a database entry to perform a new post
/api/getposts ->
fetching all the real estate posts from my database and displays it
/api/login ->
logs in a user by checking the credentials in the database and sends a jwt
/api/register ->
registers a user by taking the credentials from a form from my next.js app, registering a user and creating an entry in my database
Now in order to secure my apis I want to make sure to check if there is a valid user session if anybody is calling one of the apis (except the register/login api) to get the expected result. Im doing this by calling the /api/login route and getting a valid user session. Until here everything just works fine. Apis like the /api/createpost can only be called if we have a valid user session.
Now I want to create a mobile app and I want to use my api routes from above to provide full functionality in my mobile app too. It should work the same, if i want to call the /api/createpost on my mobileapp for example, i need a valid user session.
But I want to restrict my api by asking for a key in my database which is pointing to my app and saying okay if you call the /api/createpost api, first of all i need to verify that its the mobile app asking. The mobile app will provide the key in the request then.
I didnt try this yet, but it should work i think. Now the big mess: If we call the /api/createpost and the api wants a valid token to check in the database, which will work for the mobile app, because we are giving it a valid token to check in the database, how can we provide a token if we are calling the api from inside our next.js application? Since I have to do the api call clientside, there is no way for me to provide a secret key or something to validate that the call is coming from my next.js application.
If your application is private
(to be used only by you or a few select people)
You can send a private API key over SSL with each request from your application to the server and verify it. Or you can limit your API to only accept requests from certain IPs.
If your application is public
Unfortunately there's no way to determine where the request is coming from, since anything your app can send, an attacker can send it manually.
Think about it, if your app is trying to make a request to your API, any user can intercept this request before its sent out of his/her machine, and send the exact same request from a different app on the same machine.
You might say, well I can encrypt the requests and responses so that they are of no use to the attacker. But such an encryption will require either a key that's already agreed upon, or some way to provide a new key at the beginning of each session.
If the key is already agreed upon, the app must contain it, as you've already guessed in the question, the attacker can retrieve this key no matter how well you try to hide it.
If the encryption key is a new key provided at the beginning of each session, that's almost how SSL works, your browser handles this transaction. Your server sends a public key to your browser to encrypt the requests which the server can then decrypt with a private key. In this case you've circled back to the same problem, how can you verify to whom you give out an encryption key? What would stop an attacker from requesting the encryption key?
There has to be some way you'd be able to design apps that don't require this restriction. I think the question you should be asking isn't how to restrict your api to a certain app, but how to design apps that don't require this restriction.
We might be able to help you out if you could tell us why you need this restriction.
Update
There is actually a way to verify that requests are coming from your app, but not with an api key.
For Webapps
You can use Google's reCAPTCHA to verify a user on your /register and '/login` routes, and provide an access token or start a valid user session on successful captcha response. With reCAPTCHA v3, you could even verify every user action without interrupting the user. This eliminates both the problems I mentioned in my answer above -
You don't have to store an api key into the app/web app.
The request can't be spoofed as it requires human user interaction within your app. The captcha verification success will arrive to your API from Google's reCAPTCHA server, not from your client app. This communication will be authenticated with a pre-mediated private API key shared by Google to you, which works in the same way as to how you authenticate your external domains.
For Android apps
A similar way to achieve the same thing would be via Android SafetyNet Attestation API. This checks the runtime environment and signs the response with a dynamically generated nonce that your app provides the SafetyNet API.
Please read its docs carefully to understand how you could create potential security loopholes and how to avoid them while using this API.
For iOS apps
DeviceCheck works in a similar way, except the device validity is provided to you by Apple server.
Important edit: "secured" is not the right word here! You cannot tell that a request comes from your app just because the domain is yours. The domain name is not a safe information, as it can be altered easily. See #Mythos comments below.
Initial answer:
Web applications access is secured not based on an API key, but based on a whitelist of domains. That's how we achieve security, because only you have access to the domain where you host your own application: so the request has to be coming from an app you own.
If you try some 3rd party services that provides API for web apps, that's often how they'll work: they will let you configure a set of whitelisted domains that can access your data.
If they provide you an API key, this API key is always meant to be used by a server, not a client-only app.
So if I understand you question correctly, you would do like this for each request:
Check the domain. If it's in the whitelist, perfect, you can keep going. This is meant for web apps (look for "CORS").
If not, check for a valid API token in the headers. This is meant for any app that can store this API token securely (another server for instance, or a mobile app in your scenario though I don't know mobile enough to tell how you store such a key)
I'm setting up a Rest API for both native (mobile apps) and browser-based applications (react etc.). I'm using express.js and passport.js with LocalStrategy and JwtStrategy.
I've researched about this topic and there are a lot of different conversations or tutorials. Most of the tutorials just creates an access token and never talks about how to refresh it. And a lot of others just uses providers like Okta or Auth0. I don't want to reinvent the wheel but I think I should be able to create a simple authentication mechanism.
My current process is like this;
* Create an access and refresh token on login. Return them as response.
* Client stores it. In react I use localStorage to store the tokens.
* Add Authorization: Bearer <access_token> header to requests.
* When the access_token expires, get new tokens by using the current refresh_token.
I'm storing refresh tokens to DB on the server. So, a users can track all of their current sessions or an admin can invoke them when there is a security issue.
After a lot of research I see that there is a big disagreement on either using localStorage to store tokens on the browser, or return tokens as httpOnly cookies.
And when I examined some popular websites I saw that, websites like Facebook, Github, Youtube, 9gag use cookies to keep you signed in. They don't send an Authorization: Bearer <access_token> header. There are mainly information about UI states in the localStorage. But when you delete the SID cookie, all of them logs you out. Are they using session-based authentication?
When you login to TMDb (the movie database), it sets 2 cookies named as access_token (which is just a JWT) and session. I guess this is an implementation which the server returns the access token and some sort of a "persistance" information (session) as cookies.
Firebase (one of my favorites about this topic) just stores both the access and refresh token to localStorage. It actually uses indexedDB but I've read it falls back to localStorage when it can't use indexedDB.
But OWASP recommends that "browser-based applications should never retrieve a refresh token". I guess this means when the access token is expired, authorization server should be checked to see if there is still a session going on and then a new access token is retrieved. (Silent renew)
The only exception that I've seen is Azure Portal. It sends bearer tokens in the Authorization header. It stores the refresh token in the localStorage. And a lot of "security sensitive" corporations use it to deploy/maintain their applications or databases etc.
So, Firebase and Azure Portal are examples to access/refresh tokens saved to localStorage on the browser. TMDb is an example to getting tokens in httpOnly cookies. And Facebook, Youtube etc. are using some sort of authentication mechanism that I couldn't understand. Cookies and sessions I think?
Returning access and refresh tokens to both native and browser-based applications has a really simple logic and implementation. Storing them in localStorage always felt like it is a big risk. But I didn't want to set cookies for web applications and return JSON response for mobile applications. I felt like they should be the same. And after seeing examples like Firebase and Azure Portal, I don't feel like it is that much wrong.
But is it really safe even if there are a lot of disagreement and articles about this? And even if Firebase and Azure Portal are good examples to this strategy, why are websites like Facebook, 9gag, Youtube mainly use cookies (and sessions I think) for authentication?
I know this is a big topic. I know there may be a lot of different approaches. But I think I need some sort of a cornerstone idea to implement authentication for simple applications.
I'm developing a REST web API that will be used by mobile app clients. I don't want any other client to be able to access the API. Should I just require a password/token that will be used by the mobile apps? Isn't there a way for people to find that password by decompiling my app?
Yes, you cannot create an app with a secret embedded and expect the secret to stay secret.
If you ship the app with the secret (token, user/pass, private key, etc), that information is available in the binary, and someone motivated could extract it.
The normal practice is to install the app, then let the user of the application log in, and store a unique credential for future requests.
You could use OWIN OAUTH where a user of the client is required to authenticate and a Bearer authorization token is returned to the client that must be passed in to all secure requests on the WebAPI (a secure request on the WebAPI uses the Authorize attribute)
Take a look at this link http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/#comments
Like the Facebook application, you only enter your credentials when you open the application for the first time. After that, you're automatically signed in every time you open the app. How does one accomplish this?
There's a commom line in all auto-login implementations
Upon an initial login, a token is received and stored on the client side
Upon subsequent visits, if token is available on the client side, the server resolves the identity and logs in automatically
Now concrete implementation variations can be numerous. The token can be a session ID (encripted or not), OAuth token, custom token, username and password should be avoided. Storing token can be on within a browser cookie, browser local storage, can have a server counter-part. Security is the major concern. Generally about the topic you can read more here https://softwareengineering.stackexchange.com/questions/200511/how-to-securely-implement-auto-login
You have an interesting explanation of how does Stackoverflow do it https://meta.stackexchange.com/questions/64260/how-does-sos-new-auto-login-feature-work.
I am trying to create a REST service using asp.net web api and everything is working fine but I have now come across what to do with authentication.
I am a little confused of where to start, here is what I have been thinking.
I have an REST api that consist of a number of resources, each resource will need the user to be registered, so what is the best action for doing this? Should I just send the username and password in the header on each call to the service so I can authenticate on the server using
AuthorizationFilterAttribute
I should at least encrypt it though? I would be interested to know what others are doing, I know there is a concept of creating a token (which I presume will be short-lived) so hence the user would authenticate and then would receive a token, this token would then be sent on further calls to the service. So how would I handle the problem when the token expires?
I also have a resource that is used to register a new user, actually the only things that will be calling this is my clients (Android, iPhone). SO should I leave it FREE of any authentication methods or put a hard coded password or something similar so that at least nobody else can register new users? Bearing in mind that the service will be public on the internet.
I just don't seem to be able to find the correct way of doing this, I certainly want to try and get it right the first time so I don't have to refactor the service completely.
The following link appears to cover some sensible DIY options http://codebetter.com/johnvpetersen/2012/04/02/making-your-asp-net-web-apis-secure/. The "Tokens based on Public/Private Keys" section covers an approach I have used effectively in the past and would maybe be of assistance to you.
At the moment though I am using http://identityserver.codeplex.com/ the Thinktecture IdentityServer with OAuth bearer tokens ("Resource Owner Password Credential" grant type)... I am finding this a very good set of code and examples to work from and have IOS clients obtaining tokens and calling the WebApi.
If you really must secure your registration screen you could maybe use client certificates installed on the devices to authenticate... again the Thinktecture service could help here https://identity.thinktecture.com/idsrv/docs/default.htm?RequestingatokenusingOAuth2.html. Although if you registration process is secure What are best practices for activation/registration/password-reset links in emails with nonce e.g. email confirmations and activations etc. it may be safe to leave publicly accessible - this all depends on your business requirements and desired sign up workflow.
You should at least use Transport Level security SSL but as you suggest message level security e.g. encrypting any tokens is very advisable - the OAuth spec has something to say about this http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html#mitigation.
Regarding expiring tokens - we tend to expire our tokens with the same frequency as our password changing policy; although keeping the validity time down is important (to minimise impact of token theft) and a consideration to balance against your requirements. OAuth has the concept of refresh tokens Why Does OAuth v2 Have Both Access and Refresh Tokens? some debate and links around this topic here, we are not currently using this approach as the ID server we are using doesn't currently support this.
Keeping your tokens safe is also a consideration e.g. we are using the KeyChain in IOS, but also think about Mobile Device Management policies if possible as if these tokens or passwords are one the device they could be stolen, perhaps look into jailbreak detection, lock screen enforcement etc.