How do you prevent replay attacks with Thinktecture IdentityModel token? - asp.net

I have two sites on separate domains. I'm implementing SSO using the Thinktecture IdentityModel.
A user logs into Site A. At some point they click a link to take them to site B. Site A redirects the user to site B/Login.aspx?token=< token > with a JWT token. Site B then validates the token by calling an API on Site A to authenticate the user. If authenticated, the user is automatically logged into site B.
By default Thinktecture tokens last for 10 hours, with no way to kill a token(as far as I can tell). If the user logs out of the site, the token is still valid. I can look at the browser history and get the "Login.aspx?token=< token >" url and be automatically logged back in. Is there a way to kill all of a users tokens when they logout? Should the token not be passed as part of the querystring? What is the best way to prevent a replay attack?

As commented on your question by #leastprivilege, you can easily achieve SSO for both your sites just by defining both sites as RP's (relying parties) trusting the same IDP. That would of course simplify your authentication solution architecture.
Having said that, passive authentication using WS-Fed, is still vulnerable to replay attacks. Although the token is posted to your site, hitting "back" on your browser a couple of times (even after sign out) will re-post the token to your site and will sign the user back in.
Fortunately, WIF has a way to mitigate that attack. By configuring:
<identityConfiguration>
.......
<tokenReplayDetection enabled="true" />
.....
</identityConfiguration>
Wif then caches the used token on the server and makes sure it is used only once. (A proper exception is raised if a replay attack is detected SecurityTokenReplayDetectedException).
This cache of course will not survive a process recycle and won't be enough in a web farm scenario. If you want to mitigate this attack for these scenarios as well, you would need some kind of distributed & persistent cache for it.
I implemented one as a contribution to Thinktecture.IdentityModel, you could look into it and use it.

Sounds like POSTing tokens should resolve the issue, at least in this most obvious scenario you describe. Haven't used JWT tokens but SAML tokens are usually POSTed. I bet the server can be configured to post jwt tokens as well.

Related

Owin Authentication: SSO token vs ID token

I have implemented sign-in to Microsoft to my ASP.NET web application. Everything works as intended, but I am struggling to comprehend how the sessions work. I am using OWIN middleware and OpenID connect.
What is the difference between the SSO-Token and the ID-token? Which
one keeps me logged in?
What happens if I try to access claims ( e.g.
userClaims?.FindFirst(System.Security.Claims.ClaimTypes.sid)?.Value)
from an expired ID token?
How does !Request.IsAuthenticated realize that the current user is
Authenticated after the microsoft login? Is this because The Generic
Identity, is now a Claims Identity, that returns true?
If I am logged in, and keep refreshing the site, at what point will
I be forced to Authenticate again? And what controls this time?
I understand what an ID-token is, and that it carries claims, and how I access and use the claims. I am just confused about how the session works after a user has logged in with their Microsoft account.
There is no SSO token. The id token represents proof of authentication and some basic user info is included in it. So your web app can get name, email etc.
Expiry is based on an auth cookie that the MS libraries issue. This is tied to another token, the refresh token, which represents the session time.
The id token has a digital signature that is cryptographically verified. Also your app supplies a client secret to help ensure that tokens can be trusted.
The cookie is given an expiry related to the refresh token. When the cookie expires the user has to login again.
FOR BETTER UNDERSTANDING
I would strongly recommend tracing messages, via a tool such as Fiddler, as in this blog post of mine.
Personally I prefer Single Page Apps, which only use tokens and not cookies. They make OAuth aspects easier to understand and code can be simpler, though there are still plenty of subtleties.

Refreshing token with Hybrid Flow

I'm sure I'm missing something.
I have an MVC app & an SSO site that uses Thinktecture Identity Server. The MVC app use hybrid flow to authenticate users on the SSO site. The MVC site uses the Microsoft OpenIdConnect OWIN client to talk to SSO. My tokens have quite a short lifespan - about 5 mins, but I have refresh tokens so the user is constantly re-authenticated. This is a quite useful feature.
However when the token needs refreshing, the user is bounced via the SSO site, which breaks form posts, ajax calls, etc. This is less useful.
Can I not do this renewal on the server, rather than having the user-agent do it? I can't see a way to do this.
I'm also about to look into sliding expiration to try to solve this problem, although I'd been lead to believe sliding expiration was a bad think from a security point of view.
I was missing something. I was getting confused about who was responsible for various activities.
The user should be bounced via the SSO site when their token has expired. I now have sliding expiration on the cookie with an absolute time limit. Ideally this limit should correspond with the expiration of the tokens, but I have a refresh token, so that could be used to refresh the tokens from the server.
Once the relying party has received a valid response, it is responsible for keeping the user logged in, not the SSO site. The SSO site can be used once the tokens need refreshing.

OpenAM, OpenId, REST API, In-House applications: how do I connect them all?

I'm having trouble tying all of this together. Partially due to lack of understanding, and partially because I've not use OpenAM before.
I'm trying to implement Single Sign-on. Here are the players.
OpenAm. https://www.forgerock.com/en-us/products/access-management/
A 3rd party proprietary app that can use it's own username/password database, or authenticate against an SAML or OpenId provider.
Several In-house applications written in either angularjs or .net webforms.
An in-house REST API written in nodejs.
I need to be able to have a user sign-on/register in openam, and then they don't sign-in to any of the other applications. We see this all over the web, so the use-case is pretty normal, but I've never actually implemented it myself before.
See what I'm trying to do using the image below for starters.
Here's what I'm stuggling with:
For SSO purposes, OpenAM seems to store the authenticated user information in a cookie. How does my Proprietary app pick up this cookie and use it if it can only authenticate via openid or saml? It can't use the openam API by going through the /json/* endpoints.
With the in-house apps, I'm assuming I can just pass the cookie along and the appropriate parties can validate the cookie's session info or token and that's that. Is this correct, or am I looking at this wrong?
Can I have the user login to the OpenAm login page, and then use the /oauth2/* endpoints to validate the user's requests? I could see this working better, but am unsure if this is how it's supposed to happen.
Basically, I feel like I've scrambled my brain this last week trying to sort this out. I need some help to get some direction here. As I said above, a good portion of this is new. I've done front-end->rest api->database using a token, but this SSO scenario has given me a real headache.
Any help would be appreciated.
It sounds to me that you miss the "redirection" aspect of SAML SSO. I'll try to explain how it works in a nutshell:
Step 1:
When a user sends a request to one of your in house applications (call it the Service Provider, SP, from here), the SP detects that this is an unauthenticated request and redirects the browser to the OpenAM server (call it the Identity Provider, IdP, from here).
Step 2:
The IdP analyses the redirection request and expects to find a "SAML authnResponse", this is encoded XML metadata added in the redirection request by the SP. It finds out that your SP wants to authenticate a user. The IdP will respond to the request by showing a login page. Here the user can authenticate to the IdP. After the user succesfully authenticated to the IdP, it will redirect him back to the SP adding a "SAML authnResponse" to the request.
Step 3:
The SP will analyse this "SAML authnResponse", which is again just a form of XML metadata. If the validation of the signature is OK,find out which user successfully authenticated, create a session for him and redirect him to the resource he initially tried to access.
Remark 1:
In Step 2, if the user already authenticated to the IdP before, he will have an active session to the IdP. The IdP will not require him to login again but just inmediately redirect him back to the SP with a valid "SAML authnResponse". In this way the user will barely notice all these redirects and it will look like he 'seamlessly' got access to the SP.
Remark 2:
So don't worry to much about cookies, they're used by the IdP to recognize already authenticated user sessions etc. but you should only bother with redirects and analyzing the SAML Responses and Requests. Does this make sense?
Remark 3:
The way how the browser (GET 302 or JS POST) of the user will be redirected depends on your chosen "SAML Profile".

Does Forms Authentication protect from session hijacking?

I have ASP.NET MVC app that uses Forms Authentication. After user is authenticated, in response he will receive forms cookie that contains auth information. Now regarding the forms cookie: It is encrypted by a machine key and it is protected from tampering by signature. I also use HTTPS... However, what if somehow I get the cookie and try to make request from another client (meaning that the request will be made from another IP address)?
It seems to me that this scenario will work. Are there any ways to defend from this kind of attack?
If you are using HTTPS everywhere on your site and set requireSSL="true" on your system.web/authentication/forms element in web.config, you are instructing the browser to only pass that cookie back over an HTTPS connection. This will protect against the vast majority of traffic sniffing-based session hijacking attacks and you should definitely use it if your site is HTTPS only.
Forms Authentication is inherently stateless. The server is encrypting the following information and storing it client-side: CookiePath, Expiration, Expired, IsPersistent, IssueDate, Name, UserData, Version. Assuming your machineKey hasn't been compromised, the client will just see this as a blob of encrypted data. When it presents that blob to the server again, the server decrypts it and converts it back into a FormsAuthenticationTicket, validates the fields in the ticket against config, verifies that the ticket isn't expired, etc. and decides whether to treat the request as authenticated. It doesn't 'remember' anything about which tickets are outstanding. Also note that it doesn't include the IP address anywhere.
The only real attack vector I can think of if you are HTTPS-only, take care to protect your machineKey, and set the forms auth cookie to requireSSL would be for an attacker to target the client's browser and/or computer. Theoretically they could steal the cookie from memory or disk out of the browser's space. It might be possible for a virus/trojan to do this or even a malicious browser extension. In short, if a user could get their hands on a valid, non-expired Forms Auth cookie, they could present it from any machine they wanted to until it expired. You can reduce the risk here by not allowing persistent auth cookies and keeping your timeouts to a minimum.
If they had the machineKey, they could create FormsAuth cookies from scratch whenever they wanted to.
Oh.. Can't forget Heartbleed. If you had a load balancer or reverse proxy that was using an insecure version of OpenSSL, it's possible an attacker could compromise your private key and intercept traffic over HTTPS connections. ASP.NET doesn't use OpenSSL, so you're safe from this in a pure-MS stack. If you ever hear anything about a vulnerability in MS' SSL implementation, you'd want to patch it ASAP and get your passwords changed and certificates re-issued.
If you are concerned about the browser/machine based hijacking, you might want to take a look at a project I started [and abandoned] called Sholo.Web.Security (https://github.com/scottt732/SholoWebSecurity). It's goal was to strengthen Forms Authentication by maintaining state on the server at the expense of some overhead on each request. You get the ability to do things like revoke tickets server-side (kick/logout a user) and prevent users from moving tickets between IP addresses. It can get annoying in the traveling mobile user scenario that Wiktor describes (it's optional). Feel free to fork it or submit pull requests.
The Anti-CSRF features that 0leg refers to apply to the UI/form mechanism that initiates the login process, but to my knowledge there is nothing in the Forms Authentication process itself that relates to CSRF. That is, once the cookie is issued to the client, the only thing protecting it from being bounced between servers is the fact that cookies are restricted to the domains/subdomain they were issued for. Your stackoverflow.com cookies won't be presented to serverfault.com. The browser takes care of that stuff for you.
Are there any ways to defend from that kind of attacks?
You shouldn't. Years ago we have had implemented such feature and abandoned it soon. It turned out that:
a single user making requests from the very same browser/machine but switching between http/https can sometimes be seen from different IP adresses
a single user traveling and using her mobile phone sometimes makes consecutive requests from different IP addresses when her phone switches between BTSes
Just to clarify the terminology, session hijacking is usually referred to the vulnerability where an unauthorized user accesses the session state on the server.
Authentication cookies are different from session cookies. ASP.NET puts a great deal more precautions in safeguarding authentication cookies. What you describe is better described by the term CSRF (Cross Site Request Forgery). As #Wiktor indicated in his response, restricting access by IP is not practical. Plus, if you read how CSRF works, the exploit can run in the user browser from the original IP address.
The good news is that ASP.NET MVC has built in support for CSRF prevention that is pretty easy to implement. Read here.

ASP.NET FormsAuthentication exclusive login

I'm working on a website where I get a feed of usernames / hashed passwords from another service. When someone sucesfully logs in I set a forms authentication cookie with FormsAuthentication.SetAuthCookie.
My client doesn't like multiple people logged with the same credentials. They would like a log in to invalidate any currently logged in clients.
There isn't a method on FormsAuthentication to tell the server "invalidate any other cookie under this name". KB900111 suggests the server doesn't maintain a list of valid cookies. So my approach isn't sounding good.
What's the alternative? Time to ditch forms auth?
Not necessarily. Forms auth still provides quite a bit of baked-in functionality you might want. Maybe you can generate and issue a Guid the first time each user logs in, and store that on the server-side, and in a cookie (security ticket preferably). Every time a request is made, you check to make sure the user is using not only the correct credentials, but also the same machine and browser (based on the cookie you issued the user when the user logged in). You would of course have to make sure that your Guid expires at some point, and also make sure you clear it out when the user signs out.

Resources