I can implement Oauth in React-frontend(https://www.npmjs.com/package/react-google-login, input taken is only clientID) as well as SpringBootSecurity-backend(https://github.com/spring-guides/tut-spring-boot-oauth2, input taken is clientID as well as clientSecret). What is the difference between these two ways? More specifically how is the presence and absence of clientSecret affecting these two ways.
Without a client secret, the React frontend (perhaps a SPA: Single Page App) completely relies on the redirect uri that was registered with the auth server to provide some semblance of security. This uri was previously registered with the auth server. However, it is not as secure since the malicious app/user can tap into the communication on the redirect uri. Mobile apps suffer as well in this circumstance. And the client id is available just by inspecting the source in a browser. Therefore the malicious app has all the information to mount an attack and access the token. This is known as OAUTH "implicit" grant type flow. And it leads to token leakage or token replay.
To circumvent this issue, PKCE (Proof Key for Code Exchange) comes into the picture. Details here. Provides information on the reason for its existence in terms of shortcomings of the implicit flow that you document in your question.
The PKCE RFC here also details attack scenarios.
There is also this answer that answers very well on this aspect on this very site.
Related
I have an application that uses react to authenticate. With the Okta library, it by default stores the id token and access token in the local storage. I then grab the access token to make an .net api call that is protected by role authorization.
I'm having difficulty understand the issue with XSS attack. My understanding is that they can inject javascript code to do something with the access token. They are only able to get their own access token by logging in normally. Why is it an issue if they are doing something with their own access token? In addition, can't the access token be found in the network call, so it's not really hidden to begin with?
Can anyone provide me with an example or explain the gaps in my logic? Thanks!
My understanding is that the access token here will be stored in the browser (I'm not super clear on the differences between cookies and local storage but correct me if I'm wrong). When you do that .NET API call the browser knows to pass along the access token. The issue is that websites can include arbitrary JavaScript that runs on your browser, i.e. that arbitrary JavaScript can execute HTTPS requests from your browser using your access token.
In this way, the malicious agent wouldn't be creating their own access token, but instead using yours in arbitrary ways that might give them access to whatever private data you have stored behind your .NET API.
The avoid this, we limit the domains that can access our APIs. Typically, you might see APIs only allow requests from the same domain name. For example: if you API is accessible at mywebsite.com/api then it would only allow API requests from mywebsite.com.
edit:
Forgot to answer the "isn't the access token not hidden because it's included in a public HTTPS request" question. There's a couple of potential solutions here. On websites that use TLS (i.e. you're accessing with HTTPS), you know the public key of the website you're intending to send data to. You can use that public key to encrypt your access token and only the website will be able to decrypt it (with their private key). This way, your access token is kept secret between you and the .NET API.
In an XSS attack there is nothing that prevents the attacker from reading values in local storage. Unless there are countermeasures such as CSP to prevent exfiltration, an XSS attack can be used to steal access tokens.
When cookies have the HttpOnly flag set they are not accessible by script. The browser will attach them on relevant requests as intended.
When requests are encrypted using HTTPS the headers will be encrypted and thus hidden.
I've spent a few days trying to figure out a secure authentication method for SPA/React (client-side).
Most of the tutorials I've read in the wild contradict each other.
One says have to store in Cookies another in Local Storage, one says don't need to use refresh token, one says have to use a refresh token.
I'm building a React SPA app for the frontend and Express for the API (backend). Both are stored in the same domain:
React: example.com
Express: api.example.com or example.com/api
Is it enough to secure my application by using Cookie (access token JWT):
httpOnly:✅
secure: ✅
sameSite: strict
without refresh token
This matches the answer here: https://stackoverflow.com/a/57779076/11340631
The question is:
Is this safe enough?
How long does it take to set the expiration of the access token?
Is this as per Oauth recommendation?: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps
What if my access token is stolen? For example, my friend is using my PC and he stole my cookies and use it in his PC browser.
I really hope to get the answer here, any answer is appreciated.
It's safe against extracting the token with Cross Site-Scripting, but, without other security controls it might be prone to Cross Site Request Forgery (cookies are automatically attached to a request). Is API accepting key in the cookie or must it be sent in the Authorization Bearer header?
My concern is, that if you're not using refresh token, the access token must have a relative long expiration. OAuth2 was not intended to be used to authentication alone, but together with some session-like solution, for example OpenID Connect and SSO.
The shorter the better, unless it can be revoked any time server-side. If there's no way to revoke the key, the 5 minutes expiration date is, in my opinion maximum. That's why refresh token and session-like endpoint is the must.
OAuth is not designed for web application client's authentication at all. That's the common anti-pattern in many projects I've pentested. https://oauth.net/articles/authentication/
I'm glad for your awareness of such a threat. Access tokens must either live very shortly, or they must be revoked server-side in a some way, for example by utilizing some kind of revoke-list. Or the refresh token with server-side-like session endpoint should be utilized.
I'm developing the restful web app that using some popular web framework on the backend, say (rails, sinatra, flask, express.js). Ideally, I want to develop client side with Backbone.js. How do I let only my javascript client side interact with those API calls? I don't want those API calls to be public and be called by curl or simply by entering the link on browser.
As a first principle, if your API is consumed by your JS client, you have to assume, that it is public: A simple JS debugger puts an attacker into a position, where he can send a byte-for-byte identical request from a tool of his choice.
That said, if I read your question correctly, this is not, what you want to avoid: What you really don't want to happen is, that your API is consumed (on a regular basis) without your JS client being involved. Here are some ideas on how to if not enforce, then at least encourage using your client:
I am sure, your API has some sort of authentication field (e.g. Hash computed on the client). If not, take a look at This SO question. Make sure you use a salt (or even API key) that is given to your JS client on a session basis (a.o.t. hardcoded). This way, an unauthorized consumer of your API is forced into much more work.
On loading the JS client, remember some HTTP headers (user agent comes to mind) and the IP address and ask for reauthentication if they change, employing blacklists for the usual suspects. This forces an attacker to do his homework more thoroughly again.
On the server side, remember the last few API calls, and before allowing another one, check if business logic allows for the new one right now: This denies an attacker the ability to concentrate many of his sessions into one session with your server: In combination with the other measures, this will make an abuser easy detectable.
I might not have said that with the necessary clarity: I consider it impossible to make it completely impossible for an abuser to consume your service, but you can make it so hard, it might not be worth the hassle.
You should implement some sort of authentication system. One good way to handle this is to define some expected header variables. For example, you can have an auth/login API call that returns a session token. Subsequent calls to your API will expect a session token to be set in an HTTP header variable with a specific name like 'your-api-token'.
Alternatively many systems create access tokens or keys that are expected (like youtube, facebook or twitter) using some sort of api account system. In those cases, your client would have to store these in some manner in the client.
Then it's simply a matter of adding a check for the session into your REST framework and throwing an exception. If at all possible the status code (to be restful) would be a 401 error.
There's an open standard now called "JSON Web Token",
see https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token
JSON Web Token (JWT) is a JSON-based open standard (RFC 7519) for
creating tokens that assert some number of claims. For example, a
server could generate a token that has the claim "logged in as admin"
and provide that to a client. The client could then use that token to
prove that they are logged in as admin. The tokens are signed by the
server's key, so the server is able to verify that the token is
legitimate. The tokens are designed to be compact, URL-safe and usable
especially in web browser single sign-on (SSO) context. JWT claims can
be typically used to pass identity of authenticated users between an
identity provider and a service provider, or any other type of claims
as required by business processes.[1][2] The tokens can also be
authenticated and encrypted.[3][4]
Set a SESSION var on the server when the client first loads your index.html (or backbone.js etc.)
Check this var on the server-side on every API call.
P.S. this is not a "security" solution!!! This is just to ease the load on your server so people don't abuse it or "hotlink" your API from other websites and apps.
Excuse me #MarkAmery and Eugene, but that is incorrect.
Your js+html (client) app running in the browser CAN be set up to exclude unauthorized direct calls to the API as follows:
First step: Set up the API to require authentication. The client must first authenticate itself via the server (or some other security server) for example asking the human user to provide the correct password.
Before authentication the calls to the API are not accepted.
During authentication a "token" is returned.
After authentication only API calls with the authentication "token" will be accepted.
Of course at this stage only authorized users who have the password can access the API, although if they are programmers debugging the app, they can access it directly for testing purposes.
Second step: Now set up an extra security API, that is to be called within a short limit of time after the client js+html app was initially requested from the server. This "callback" will tell the server that the client was downloaded successfully. Restrict your REST API calls to work only if the client was requested recently and successfully.
Now in order to use your API they must first download the client and actually run it in a browser. Only after successfully receiving the callback, and then user entry within a short frame of time, will the API accept calls.
So you do not have to worry that this may be an unauthorized user without credentials.
(The title of the question, 'How do I secure REST API calls', and from most of what you say, that is your major concern, and not the literal question of HOW your API is called, but rather BY WHOM, correct?)
Here's what I do:
Secure the API with an HTTP Header with calls such as X-APITOKEN:
Use session variables in PHP. Have a login system in place and save the user token in session variables.
Call JS code with Ajax to PHP and use the session variable with curl to call the API. That way, if the session variable is not set, it won't call and the PHP code contains the Access Token to the API.
I have 4 angular applications one is a landing app which asks user to login and has to redirect the user according to its type
to one of the other 3 applications. I am unable to figure how to should i achieve that.
Have the three apps running on different subdomains. Upon login backend send a redirect response, figuring out what type of user it is?
But this leads to cors Error. Also i am not sure whether the cookie which i am setting will be accessible in all the subdomains or not.
Is there a way out?
You can do a redirect, but it seems like an unnecessary step (and kind of convoluted for this type of application).
Instead of returning a redirect based on login, it seems more straightforward to just return the address you want to redirect to in the response. Trigger a lookup to determine which app you should be directing to (however you're doing that) and then return the address of the app in the response data. From within Angular, you can extract the address from within response.data in $http. (see angular docs). The nice thing here is you also keep routing control and knowledge of state within Angular itself.
As for the apps themselves--instead of a subdomain, you can simply put the apps into different folders on your domain. This deals with CORS and the cookie issue.
Otherwise, you'd need to set a CORS header. You would do this on whatever backend you're sending the requests to--there's usually some sort of library to make it easy, for example, Flask CORS for Flask. If you need to share cookies in this case, this StackOverflow answer discusses one way of doing it (using an intermediary domain).
Generate a security key for the user session with some TTL in an authentication table when you authenticate the user with your App1
Redirect the user to any other app in any domain with this security key where they can query the authentication table and verify the user.
Let these other applications work on their own (in the front end) and communicate with the back-end with the security key when necessary.
Lot of PHP frameworks has built-in support for this mechanism. My favorite is Silex.
I'm trying to understand how an saml authentication flow could work in a mobile environment where the client (AngularJS based), api server (Node & passport based), and idp exist on different domains.
From what I've gathered the general practice is to have the server return a 401 to the client if there's no authentication present (i.e. the client didn't include a bearer token in the request). The client understands that a 401 response indicates to open up the login endpoint on the server. When the login endpoint is opened it makes a passport call to the auth provider (which redirects the user to the auth provider's site) and supplies a callback URL. When the user authenticates, the auth provider redirects to the provided callback URL, which allows the server to retrieve information from the auth provider's response and construct a token of some sort (e.g. JWT) that can be used by the client (i.e. included in the headers) when making REST calls to identify itself.
My question is: How does the client get the token from the server? Because we're in a redirect-based authentication flow, I can't just return token from the callback function; that would just display the token in the browser without handing it off of to the client. Does the server just issue a 302 redirect pointing back to the client domain and include the authentication token in a header? Maybe I should not redirect from the client to the server in the first place and instead window.open() and use window.opener.postMessage or is that too old fashioned/mobile-unfriendly?
This question talks about authentication against a SAML IDP, but I'm interested in getting more details specifically about that last bullet point and how it would work with an AngularJS-based client.
Many examples I've seen online are either a single domain using OAuth/SAML (passport-saml-example), which avoids the issue of having the client exist on a separate domain, or use two domains with basic authentication, which avoids the issue of redirecting to some third party for authentication, but I'm having trouble finding good examples that uses all the bits and pieces I'm trying to work with.
This blog post seems very close to what I'm trying to accomplish (see googleSignInCallback) and uses a 302 redirect like I imagined but that solution relies on explicitly knowing the client URL to redirect to, which seems like it could be problematic if I wanted to support multiple client types (i.e. Native applications) in the future.
Eventually I was able to work together a solution by having my application open a browser window (Cordova's InAppBrowser) to a SAML-enabled application, have that application complete the normal SAML flow, and then that SAML-enabled application generated a JWT. My mobile application was then able to extract the JWT string from the browser window with the InAppBrowser's executeScript functionality. Then I could pass that JWT string along to my API server, which was able to validate the JWT is properly signed and trusted.
After I implemented my solution I saw that there was similar functionality available on github:
https://github.com/feedhenry-templates/saml-service
https://github.com/feedhenry-templates/saml-cloud-app
https://github.com/feedhenry-templates/saml-cordova-app
Hopefully this helps anyone else trying to deal with this issue!