I want to get your opinion on a security concern regarding Facebook SSO (Or any SSO provider, for that matter).
When a user preforms FB SSO on the mobile and by that performs a sign-in to our app, we pass the token received from FB mobile app to our server, and the server preforms a request to FB to authenticate that the token is valid, and this is not a stolen request.
This is done only for the first time. Theoretically, on every call to our server from now on, we still need to call FB server and keep authenticating the token, as Facebook is our identity server. This obviously not ideal, since every request to our server can not be synchronized with FB server request constantly, performance-wise and for many other reasons.
However, from a security point of view, although all requests are SSL'd, our server does not know that this user token is still valid, and the only way for it to make sure, it to call FB server. (A good example for this is user doing SSO and then removed the app on FB settings.)
What are your thoughts on this issue?
Related
I am implementing authentication in Django using SimpleJWT, and have a few questions regarding the same. To give some background I have multiple domains with my backend, some with normal login (username and password), and some with SSO logins.
Question 2:
Suppose, I store the access tokens in local storage and send the access token to all APIs, and I'm also refreshing it before it expires. But what will happen if the user closes the browser, and we are not able to refresh the access token. The access token expires and the user gets logged out. How can we keep the user logged in for a certain amount of time (say 30 days)?
When the Access token expires, you use the Refresh token to obtain a new Access token.
This works because Refresh token has a long life, typically up to 30 days (but can be even longer if you want).
Example:
User closes browser
Comes back 10 days later
User sends a request to the server
Server will return 401 Unauthorized response because Access token has expired
Your app will send a request to obtain a new Access token using the Refresh token
If the Refresh token is valid, server will return a new Access token
If the Refresh token is expired, server will return a 401 response. That means user needs to login again.
Security considerations
Personally, I think JWT for most web apps is not an suitable idea because of conflicting opinions and advice on how to securely store the tokens.
Since a Refresh token is really powerful, it is not advised to store it in the browser. So where do you store it? And that's when this misleading idea of "backendless" web services powered by JWT starts to fall apart.
Paradoxes regarding storing tokens:
Store it in localstorage: Vulnerable to XSS attacks.
This is really serious because the XSS vulnerabilities can also come from third party JS libraries, not just from your own code. Hackers can hijack a third-party library on NPM to inject malicious code and you might be unknowingly using it in your project (it might be a dependency of a dependency of another dependency...).
Store it in httponly cookies: Safe from XSS attacks but requires a first-party backend server (because third-party auth servers can't set cookies for another domain).
If you stop to think about it, you'll notice that this case is exactly similar to the regular session auth where a session token is saved in the cookie. So why not just use session auth instead of this complicated JWT setup?
I'm going to advise you to thoroughly research this and decide whether you really need JWT for your web apps.
JWT auth using cross-origin cookies
Since you mention that your frontend apps connect to an API server in another domain, using JWT seems alright.
If you control the API server, you can setup CORS headers to allow the API server to set cookies on your apps' domains.
Important:
Since this involves Cookies, it is vulnerable to CSRF attacks. But > that is easier to prevent using CSRF tokens.
That means, with every POST request, you'll need to send CSRF token
and the API server must also validate that CSRF token
Here's a diagram I make of the auth flow in that case:
For Question 2, add this code on your settings.py file
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(days=30),
'REFRESH_TOKEN_LIFETIME': timedelta(days=30),
}
I have two servers.
Server A - this is whole bussines logic and API for mobile application.
Server B - in simply words, this is a webpage.
And now, I need to authenticate user on B but, by the 'user-data' from A.
E.G.
On A server I have user with loggin/password. And I need to use this same login/password on B server. There is some nice solution for that? Or just use tokens?
Presumed that you have an authentication mechanism in your server A.
You have to use your server A as an Identity provider. Request to your B-server should have a session header. If this session is not valid in B-server then you have to ask for credential from the web user and forward this request to your Identity Provider(Server-A). If Server-A can identify the given credential, initiate a session in server-B for this user for a particular time frame. You have to manage this session in the Server-B.
When this user logged out from server-B just destroy the session.
tokens should be fine such as a bearer token on the Authorization header. There are different strategies such as opaque tokens vs JWTs, etc.
I actually did a write up on API authentication tutorial and security holes:
https://www.moesif.com/blog/technical/restful-apis/Authorization-on-RESTful-APIs/
I am developing several Web Services that will be accessed by a mobile application. I have several requirements:
Each user will need to sign in with their own User ID and Password (the same User ID and Password they use to sign into the website).
Every Web Service request will need to be authenticated to ensure that the request is coming from the mobile app(s).
Every Web Service request will need to authenticate the user, since there is user-specific fucntionality built in, and access will need to be blocked if the user's account is disabled.
Let's assume that OAuth is not an option.
In order to ensure that Web Service requests are coming only from the mobile app(s), I am planning to use HTTP Basic Authentication in IIS (the mobile app(s) will need to have a User Account setup in Windows Server and the mobile app will need to store the User Name & Password and pass these in the header).
Next is the User Authentication for each Web Service request. Would it be suitable to encrypt the User ID, Password, and some shared secret key (a "pepper", of sort) with AES-256, pass that encrypted string as a parameter with each request (over HTTPS, of course), and then decrypt and parse it on the server to authenticate? This is the existing plan, but something just doesnt seem right about it - like it's not "secure enough".
What else can I do to properly authenticate users for Web Service requests?
I recently went through this problem and asked opinions from a group of senior people about how they solve the problem. Opinions were varied, but one consistent feeling is that your level of security depends on the use case of your application. Are you doing online banking or storing medical records? Then your security needs may be quite high. Social networking? Maybe not so much.
Basic Authentication is generally fine when encrypted over SSL, ColdFusion works well with it. If you use Basic Auth, make sure to encrypt your traffic with 1024-bit keys or better. Don't authenticate every request with username/password - that's unnecessary. Authenticate the first request, set a session token, and rely on the session token for your identification of users.
Set a polling mechanism from the client to the server to keep the session alive - set the session timeout to 30 minutes and the polling frequency at 25 minutes, for example. Otherwise you may need to re-authenticate expired sessions. Again, how you approach this part of the solution depends on your paranoia level, which depends on what kind of data/app you are dealing with.
Cookies, and therefore sessions, should work fine in iOS apps. If you use sessions to verify identity after authentication, make sure your session cookies are memory-only (set at the server level).
Check the SSL implementation of your server against the Qualysis SSL Test:
https://www.ssllabs.com/ssltest/
The report will give you a surprising amount of detail about the strength of your SSL implementation.
Lastly, consider implementing two-factor authentication to combat password theft.
If you ignore the SSL advice and plan on encrypting your password and communicating over an insecure channel, look at the Kerberos protocol for a well-known example of how to authenticate securely:
http://en.wikipedia.org/wiki/Kerberos_%28protocol%29
Yes, you can use Basic Authentication but that means the client will need to store the username/password in plain text, and also send them over in plain text. Sending part is sort of fine if it's under HTTPS, but storing username/password in plain text may not be a good idea, unless you're using some secure key store.
Let's assume you have decided that Basic Authentication is the way to go, and you want to make use of the official CF way of supporting that, then you can use CFLOGIN.name & CFLOGIN.password. You may also check out Ask Ben: Manually Enforcing Basic HTTP Authorization In ColdFusion. In the remote cfc side, always validate the username/password, or return some sort of token and asks the client to use that token going forward. The token can be cfid+cftoken if you like, or even roll your own that never expires. If you use cfid+cftoken, and send them over as cookie or in body along with your web service call, I believe you can resume the session if you so choose.
I have a scenario where a user will use the same Facebook account on multiple devices with our app. As part of the FB authorization, we ask for "extended data permissions" which makes teh FB oauth token long lived.
I'm trying to figure out whether our server needs to specifically support multiple devices or whether Facebook will return the same oAuth token to all the devices for the same FB account.
If it does, then it means that support 1 or N devices should be the same for me.
If not, then it means I have to track N oauth tokens on our server and differentiate between device IDs (UDIDs).
Facebook generates one token per app per user, if you request offline_access when you authenticate your app (see https://developers.facebook.com/docs/reference/api/permissions/). So, it doesn't matter on which device the user logs in, Facebook will give you the same token every time.
I'm working on an iPhone app that uses xAuth to login to Twitter. The app also communicates with my own web service. Rather than maintain a user model inside the web service, I'd like to just allow anyone who's already authenticated via Twitter to make requests.
The high-level use case is this: the user logs into and interacts with Twitter through the app. They can also interact with my web service through the app. The web service itself never interacts with Twitter. Instead of maintaining a separate authentication system on my side, I'd like the server to say "OK, if Twitter says you're #joshfrench then you can have access."
I'm not sure how I should validate requests on the server side, though. How would I pass some proof of authentication from the mobile client to my web service? Can I send along the existing Twitter token and verify it from the server? Or somehow sign the request with my Twitter app's credentials? Is this even a valid use of OAuth?
If you store your twitter app key and secret on both he iphone app and your server, and then somehow transmit the user's oauth token (also called "access token") key/secret from the iphone app to the server, then you can do the same type of api calls from the server.
consumer = OAuth::Consumer.new(app_key, app_secret, …)
access_token = OAuth::AccessToken.new(consumer, user_key, user_secret)
response = access_token.get('/stuff.xml')
So, is it Okay to transmit that info from the app to the server? If you do it securely, and it's within the user's expectation for how the app behaves, then it's a perfectly fine use of oauth.
It's possible that it's not allowed by Twitter's terms of service -- I could imagine there being something that says you can't transfer a user's access secret across the network, or some such thing. (total wild speculation, I don't think it's particularly likely that that's the case)