How does AntiForgeryToken work - csrf

I'm in trying to protect from CSRF and have two scenarious:
Doing POST from within another site and it fails when I enable AntiForgeryToken
I have tried from my "malicious" Javascript (running on another site) to first do GET of the page, parse it and extract RequestVerificationToken and then do a POST. This also fails but it is unclear to me why?
Can anyone please explain why?

Here's a good tutorial on CSRF:
http://youtu.be/vrjgD0azkCw
Here is the general gist: You are logged in to your bank's website. Your bank puts a cookie on your machine so it can authenticate you. Every time you make a request to (ie. load a page from) yourbank.com, the browser sends the cookie to the web server and the code on the web server checks the cookie to make sure you're authenticated. Great.
However, while the cookie hasn't yet expired, you check your mail and open an email from a Nigerian Prince telling you to click on a link. You click on it (who can resist) and instead of taking you to the page the Prince has described, the link takes you to this URL:
http://yourbank.com/transfer.aspx?amt=1000000&from=myAccount&to=princeAccount
Because you're already authenticated at your bank (through the cookie), it thinks you're actually asking to transfer the money, so it does it.
This is obviously a bit of a contrived example, but it gets the point across. More realistically, the link might submit a request that changes your email address on a forum website that you belong to or something, so that they can get access to it.
So NOW, on to answering your specific question:
One way to combat this (used by Ruby and .NET and others) is to include an anti-forgery-token. Basically, when you request a page, the server includes a hidden field with an encrypted value. And when you submit the form, the website looks at the cookie to make sure you're authenticated, but it also looks at the encrypted value that the browser sends and make sure it's valid. The encrypted token would realistically be a session id that your account is tied to. So the server sees the cookie, identifies you as user 123, and then checks the encrypted form field token, decrypts the value and makes sure that unencrypted value matches your session or user id or something. If it does, it knows to proceed.
The Nigerian prince who sent you the link won't know what your session id is, and even if he did, he wouldn't be able to encrypt it with the same key and algorithm that the website is using.
And there you have it. Thwarting Nigerian princes one anti-forgery-token at a time.
(Nothing against Nigeria or Nigerians here. I'm sure they're lovely people. It's just their princes sometimes behave a bit poorly.) :)

For security reasons, you cannot retrieve content from another domain using AJAX.
Therefore, other sites cannot get your token.

Related

How to authenticate without hitting the database?

A comment below an answer about state and REST recently piqued my interest. For clarity I'll quote the comment in full:
Nothing in my answer implies a solution based on database access on every request, if you think it does, it is a failing on your part to understand authentication and authorization at that scale. The authentication can be implicit in the state, do you think that facebook does a "database access" on every request of its REST API? Or Google for that matter? hint: no
I tried to think how one might authenticate without checking a user-provided value against a centrally-held one, even if one to know what data to display to the user, and came up blank. i freely admit this is a failing on my part to understand authentication and authorization at that scale. My question is therefore: how do sites like Facebook and Google accomplish this?
One way is claims based authentication. Simplified and somewhat loosely interpreted, it boils down to this;
Instead of the server application authenticating the user itself, an un-authenticated user is redirected to a separate authentication server.
The authentication server validates the user in any way it wants to (login+password, certificate, domain membership etc) and creates a signed "document" with the relevant user info (user id, name, roles, ...) It then redirects the user back to the server application with the document enclosed.
The server application validates the signature of the document, and if it trusts the signature, it can use the document contents to assume who the user is instead of accessing the database.
Normally, the server application caches the document in a cookie/session or similar so that the next access to the application does not have to bounce through the authentication server.
In this way, the server application does not need to concern itself with how the user is authenticated, just whether it trusts the judgement of the authentication server. If the authentication server (and possibly the client unless it's a browser) adds Facebook login support, the server application will automatically "just work" with the new login type.

Questions regarding authentication workflow with REST, and Backbone

I am currently working on a website built with Backbone.js. The site has a RESTful API built in Symfony with FOSRestBundle. Developing was going fine, until I stumbled in to some user-related tickets.
From what I understand, the best way to handle this type of problem is with a token based system, where the user gets an access token after an approved login. I will describe my current perception of the workflow, and ask questions along the way. More importantly, please correct me if I have misunderstood.
First, the user the accesses the login form, then the user types in credentials, and an AJAX request is send to the server. From what I understand this should all be handled with SSL, but with Backbonejs, you can't simply say that the login page should be accessed with HTTPS, as Backbone is a one-page framework. So will this force me to use HTTPS through out the application?
In the next step, the REST server validates the credentials, and they are approved, then the REST server sends an access token to the client. Is this token saved (on the client-side) in local storage or a cookie?
Also is the login stored at the server, so that the REST server can log the user out after a certain amount of time?
Now, the client sends this access token along with other request, so that the server can identify the client, and approve the request or not. So the access token is also stored on the REST server?
Lastly is this what the smart people call "oauth", or does it relate to it?
Thank you.
Let's take your questions one at a time.
From what I understand this should all be handled with SSL, but with Backbonejs, you can't
simply say that the login page should be accessed with HTTPS, as Backbone is a one-page
framework. So will this force me to use HTTPS through out the application?
Ok, there's a lot to unpack there. Let's start with SSL/HTTPS. HTTPS is a protocol; in other words it defines how you send packets to/from the server. It has nothing whatsoever to do with whether your application is single or multi-page; either type of site can use either HTTP or HTTPS.
Now, that being said, sending login info (or anything else containing passwords) over HTTP is a very bad idea, because it makes it very easy for "bad people" to steal your users' passwords. Thus, whether you're doing a single-page or a multi-page app, you should always use HTTPS when you are sending login info. Since it's a pain to have to support both HTTP and HTTPS, and since other, non-login data can be sensitive too, many people choose to just do all of their requests through HTTPS (but you don't have to).
So, to answer your actual question, Backbone isn't forcing you to use HTTPS for your login at all; protecting your users' passwords is forcing you.
In the next step, the REST server validates the credentials, and they are approved, then
the REST server sends an access token to the client. Is this token saved (on the
client-side) in local storage or a cookie?
While any given framework might do it differently, the vast majority use cookies to save the token locally. For a variety of reasons, they're the best tool for that sort of thing.
Also is the login stored at the server, so that the REST server can log the user out
after a certain amount of time?
You've got the basic right idea, but the server doesn't exactly store the login ... it's more like the server logs the user in and creates a "session". It gives that session an ID, and then whenever the user makes a new request that session ID comes with the request (because that's how cookies work). The server is then able to say "oh this is Bob's session" and serve the appropriate content for Bob.
Now, the client sends this access token along with other request, so that the server can
identify the client, and approve the request or not. So the access token is also stored
on the REST server?
If you're running two separate servers they're not going to magically communicate; you have to make them talk to each other. For this reason your life will be easier if you can just have one (probably REST-ful) server for your whole app. If you can't, then your REST server is going to have to ask your other server "hey tell me about session SESSION ID" every time it gets a request.
Lastly is this what the smart people call "oauth", or does it relate to it?
Kind of, sort of, not really. OAuth is an authorization standard, so it's sort of tangentially related, but unless your login system involves a whole separate server you have no reason to use it. You could use OAuth to solve your "two servers, one REST-ful one not" problem, but that would probably be overkill (and regardless it's outside the scope of what I can explain in this one Stack Overflow post).
Hope that helps.

WIF - optional authentication

I'm working on a proof of concept app. The basic functionality works, where I can log into one website, link to another site that shares the same STS, and the partner site picks up the credentials properly.
However, the partner site only requests the token if the page that we link to requires authentication (which kind of makes sense I guess).
Ideally, I'd like to link to a partner page that does not require you to be authenticated, BUT if the user IS already authenticated, I'd like to at least be able to recognize them on the partner site.
Currently, if my partner landing page does not require authentication, it doesn't appear that the user is logged in when they arrive. As soon as the user requests a page on the partner site that does require authentication, it then grabs the token without requiring the user to log in.
I've tried playing around with the SecurityTokenReceived and RedirectingToIdentityProvider events, but so far I'm stumped.
Any thoughts are appreciated.
So, the problem you are running up against is in dealing with the SessionAuthenticationModule hijacking the request. This module is responsible for detecting if the user has a valid session (based on a cookie that is written upon a successful redirect from the STS) and if not, to redirect the user to the STS to fetch a valid token. The WSFederationAuthenticationModule supplies the eventing necessary to hook into various stages of the redirection/authentication process.
Based on your description, it sounds like you want the following to happen:
User clicks on a link that redirects to the partner site
At the partner site, the request is intercepted and the system determines if the user is signed-in to the STS or anonymous
If the user has a valid session with the STS, then pull the claims for that user
The problem is, your RP cannot know that the user has a valid session without sending the user to the STS first (the RP's do not talk to each other or the STS. The user's brower is used as the means of communication between the RP's and the STS in the form of WS-Fed directives and SAML tokens passed in the url during redirects). If the user is sent to the STS, then they must authenticate, which could be a problem for anonymous users.
So, I do not think there is a "trick" that you can pull via configuration or interception of the request to determine if the user has a valid session with the STS. You might be able to pass a hint, however, from the referrer that is intercepted by the partner site. This hint could take the form of a parameter on the url that indicates to the partner site that the current user has a valid session and to go ahead and redirect to the STS (absence of this hint would indicate an anonymous user). You could also build a system to "hand-off" knowledge of the signed-in user using a resource that both sites have access to (i.e. database).
As you are sure to learn soon, more often than not, WIF offers pieces to the puzzle, but every situation is different and you have to supply the other pieces on your own.
Hope this helps!

How to make a specific web page inaccessible, except to those who get there by a redirect

I have a webpage on a Joomla based website that I am trying to make inaccessible to anyone but those who have been redirected there through a redirect page.
Basically, they would purchase something on a form on my page which is integrated with Paypal, and when Paypal payment is complete I have them redirected to this specific page. I don't want anyone to be able to just copy this url and be able to come back to the page later. Is there a way to do this?
Then you have to store some "token" in your database, which is invalidated after the first time a returning client accesses your "thank you" page.
The token should be given to the client (in the URL) when you redirect him to Paypal and when he comes back after a valid payment, the token must still be in URL.
As far as I remember from the time I tried to use PayPal in one of my projects, it is possible to pass something like this to Paypal and get it back.
Checking a redirect is a poor way to do this. Such things can be easily spoofed. Instead have the pages you require a redirect from to create a session record of some kind and pass the ID of that record in the query string to the restricted page. The restricted page can deny if the session ID does not exist in the database or is too old.
It's been a while since I worked with Joomla. You might be able to look at the Server variables and check the Referring URL. If it's not one of your web pages or paypal, then you can redirect the user to the page of your choice.
I would include a specific token on the redirect. Maybe a Guid that has a limited life and is assigned to that specific user.
Paypal has a feature called Express Checkout that does just what you're looking for.
If you only care that the link expires shortly after it is used, then I think you should create a one-time URL for the content you are trying to protect. Have the action of purchasing create a unique key or token, store the value of the token on your server, and then reference that token in your link:
example.com/purchased_content?token=59803475203658902345089
When the link is clicked, check against your stored values. You can expire them based on whatever criteria you want.
If you also want to prevent copying the URL to somewhere else, you can have the action of purchasing set a cookie with the token value. Then check the cookie when the link is clicked. This is not foolproof since a knowledgeable user can copy the cookie too.

Cookie based SSO

How can I implement a cookie based single sign on without a sso server?
I would to share the user logged in across multiple applications using
only a cookie on the browser.
In my mind it's working like this:
user logs in an application
the application verifies the credentials and then it setting up a cookie on
the browser storing the username (that could be coded with a private key)
if the user opens another application, it searches the cookie and reads
the username on the value (using the key for decode the string)
In this solution a user may see the browser cookie (of a another user)
and take the string codified of the username. Then he could adding it on
an own cookie (no good!).
There's some secure way to do this? With a timestamp based control or
something like this?
Thanks in advance.
Bye
P.S.
I know that my english isn't very well.. sorry for this!
This is impossible. Cookies are unique to each domain, and one domain cannot read another domain's cookies.
I think the answer comes a little late, but maybe I can help someone.
You can have a cookie / localStorage in an intermediate domain connected to the home page using an iframe
1) Login
The login form in any of your domains deposits the identification token in a cookie on sso.domain.com by an event (postMessage)
2) Verification
domain1 and domain2 include a iframe pointing to sso.domain.com, which reads the token and notifies the home page
To simplify development, we have released recently a cross domain SSO with JWT at https://github.com/Aralink/ssojwt
There is a simple solution without using an sso server, but not with 1 common cookie, as we know that cookie's are not shared between domains.
When the user authenticates on site-a.com, you set a cookie on site-a.com domain. Then on site-b.com, you link a dynamic javascript from site-a.com, generated by server side script (php, etc) who has access to the created cookie, and then copy the same cookie on site-b.com on the client-side using js. Now both sites have the same cookie, without the need of asking the user to re-login.
You may encrypt/encode the cookie value using a method that both site-a and site-b knows how to decode, so that site-b will be able to validate his cookie copy. Use a common shared secret that without it will be impossible to encode or decode.
You see that on the 1st page load of site-b.com, the cookie is not present, therefore if you see necessary, you may want to do a page reload after setting the cookie.
I have done something similar. There is a PHP application where the user logs in, the system contact a web service and then the service checks the user's credentials on the Active Directory. When the user is authenticated, his PHP session is stored in the DB. Another web application can read the PHP session from the cookies and uery a web service in the PHP applicaiton, the PHP application check the session in the database and return the user id. In this way I have a SSO using SOA.
Do not rely on the user id stored in the browser, is a security error, at least encrypt the id.
The best solution would be to put the login form and session storage in the same application, then this application can provide services to other applications.
And use HTTPS for the kind of infomation exchange.
The cookies can be read only if the belongs to the same domain, for instance:
intranet.example.com
crm.example.com
example.com/erp
You can access cookies across subdomains, but I do not think using browser cookies is a great solution. You really don't need a "SSO server" to implement a single sign-on. It is fairly easy to come up with a payload that both applications recognize. I have seen custom SSO solutions that transmit the payload using XML over HTTPS.
Here is a solution (which will hopefully get heavily scrutinized by security gurus on here):
Have each domain store user data in a similar cookie, and when a user want to jump from one domain to another without authenticating themselves on the new domain, provide a "jumplink" with an encrypted token in the query string. The new domain would decrypt the cookie, and figure out who the user is, then issue them a new cookie for that domain. You would want the "jumplink" to have a very short expiration date, so I would not generate them right into the page, but generate links to a "jumplink" generator and re-director.
This might not be necessary, but the receiving page for the "jumplink" could make a web service call back to the originating domain, to verify the authenticity of the encrypted token and the whether it's expired.
I think this solution would be susceptible to man-in-the-middle attacks (not sure if it would be more so than other auth mechanisms which are currently popular), but you could incorporate a client MAC address and IP address into the encrypted token for extra security.