I'm writing a mostly ajax-driven web application and I'm looking at how to protect the user from CSRF attacks. I'm planning to run the pages of the application where the user is logged in to do his work in HTTPS mode.
Does running the page on HTTPS work to protect against CSRF attacks?
No, running a page on HTTPS does not protect it from CSRF. The fact that the communications between the browser and server is encrypted has no bearing on CSRF.
I suggest reading the OWASP guidance on preventing CSRF.
A general, golden rule woule be:
Never trust that the incoming client request is a legitimate one. Be always suspicious and assume that the request could be maliciously forged.
Few specific rules beyond the mentioned OWASP article:
if your data needs authentication/authorization, avoid generic interfaces on the server, like the CRUD interface. easy to code, difficult to authorize specific requests coming from clients. instead, offer a SOA-style interface with explicit methods dedicated to specific use cases where you will have direct control over requests and their parameters.
http://msdn.microsoft.com/en-us/library/ms954638.aspx
even if the framework provides some control over the request validity (ASP.NET viewstate), check again if the user is authorized to pass the set of incoming parameters.
I'll try to explain:
• HTTPS prevents from someone on the same network to get your Session KEY/ID. Say they got your session identification key/id, then they can fake your IP if needed and send all POST requests they want back to server.
With HTTPS all HTTP body (the whole "HTML") is encrypted. Hence no session key is being guessed.
• What happens in CSRF is that the user is clicks a link, which also creates a request to another server and communicates with it, say using user's session but NOT ON THE SAME NETWORK. Means that it cannot listen to what the server replies back to user. If the attacker knows the replies and can communicate them, voila. No problem. No money's left on the user account. But if the server sends a random token to the IP associated with the session, then the attacker cannot guess it on a different network!
The best possible solution is to include secret tokens - to identify the user - in form submissions to the server. Refer to the following links for more information.
http://en.wikipedia.org/wiki/Cross-site_request_forgery
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
http://www.codinghorror.com/blog/2008/10/preventing-csrf-and-xsrf-attacks.html
http://seclab.stanford.edu/websec/csrf/
https doesn't safeguard your app from xss attacks. You need csrf token which should be (1) encrypted (2) expiring after some time (3) CSRF token based on page & time
Related
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.
I've just started working on an aspx web from login page for AspNet.Identity.
I have my fields, username and password (textmode="Password") and a submit button (asp:button) as usual with my code behind to do login, etc.
My question is, when my user clicks submit, how is the password sent to the server? Do I need to be on SSL to ensure that the password isn't sent in cleartext?
Edit
StackOverflow's login page isn't over HTTPS - how do they (and other sites that don't use HTTPS) manage password transmission?
One can say that all data submitted from the browser is sent in cleartext (that is, neither browser itself encrypt it, nor when data arrives to your server-side script it requires decryption). All the encryption (if any) is performed at the protocol level.
Plain HTTP doesn't encrypt any information sent over it, which allows for simple inspection (man-in-the-middle attack, eavesdropping). On the other hand, HTTPS creates a secure channel over an otherwise insecure network and protects from said attacks reasonably well.
One caveat to that is using GET to send data to the server. This information can easily end up in server logs.
Depending on the form method GET or POST values are sent to the server.
By default in asp.net the form method is POST so it is send in the body of the request.
If the form method is GET then it sent in the url.
Edit 1
When you use HTTPS the channel is secured. But some time it can be slower than HTTP because HTTPS requires an initial handshake which can be very slow.
Some useful links
Difference between http and https
HTTP vs HTTPS performance
Main problem is that if anyone is able to listen to the traffic from your client to your server, then they will also be able to manipulate what your server sends to client. This issue invalidates all attempts to do some javascript magic to hide it out will be lost effort.
In other words, there is for the time being only SSL to help you out.
For username/pwd verification - the good websites use https - to avoid sending cleartext password over the wire. If I have a site where I want to do this - i.e. login over https. However - after logging in the rest of the stuff should be over http. Is this possible - if yes, why don't we see too many websites doing this. If not, why not?
You might want to read up on Firesheep. The short form is that this technique allows malicious people to hijack the session.
if yes, why don't we see too many websites doing this
The usual excuse for not using end-to-end TLS/SSL is that it causes the web app to take a performance hit, slow response times etc. This is a very flawed argument for https-sometimes security policy. Not entirely unfounded, but still unjustifiable.
If not, why not?
The thinking is that the only inherently vulnerable aspect of user access control is the authentication phase, i.e. where you supply your username and password to prove you are who you say you are. Organizations are aware of the risk of transmitting the credentials in clear text. After this process however, authorization is carried out server side and the web app trusts you from there on out and there are no credentials to protect any more.
Or are there?
As jszakmeister pointed out very succinctly, the session cookie is every bit as security critical as a username/password pair. Should someone get a hold of that, they might as well have seen the password and username on post-it.
So feel free to not only answer this question but to throw out suggestions or improvements. I've never put together a large scale web application before. Here's my thought process:
Persistence Layer: Standard Database (MySQL right now)
Business Logic Layer: REST-like structure (PHP, Java Servlets, etc...)
Presentation Layer: Web Browser, Android devices (application not browser), and others
The reason I selected this architecture is so that devices can devise their own custom UI's and tap into the REST-like functionality by using GET, POST, and what not to interact with the server.
Problem 1:
The problem is, how do you secure user's information? You can authenticate the user over an SSL connection and return a special HASH so that the user can manipulate their account but if someone is listening on the network, all they have to do is listen for a REST call and steal the HASH. One solution is that all REST-like calls have to be over SSL, but this causes another problem.
Problem 2:
If the REST procedures are in SSL, the browser has to use SSL for everything which from my understanding can be slow and cumbersome when unnecessary. Also, SOP makes it impossible to use SSL ajax calls to the REST procedures from an unsecure browser. HTTP and HTTPS are considered different origins even though its the same origin, different protocol.
Is this solution viable? How would I solve these two problems? Or possibly (probably) is there a better architecture I should look into for my web application. Thanks in advance for all suggestions.
If you want to secure the information you have to use SSL, since anybody can listen the network, and see the user information. If you want to secure the access, then use HTTP authentication RFC2617. Over SSL, Basic is secure enough, but if you don't want to use SSL for every request, Digest is the way to go:
your application can be stateless: i.e. more restful, easier load balancing, ...
the authentication token can hardly be reused if listen (no session hijacking)
almost every HTTP client (browser or lib) can use basic or digest HTTP authentication.
As it turns out, there is actually no great solution out there for this answer. You can either protect everything with SSL or devise your own home brew authentication system. A common method is to send the user a unique HASH, store the HASH in the database and in a cookie on the client's machine. Then only that user's IP, User-Agent, etc.. will be authenticated to that cookie.
So the answer is yes, the solution is viable. Extra security precautions will need to be maintained in order to disallow account hijacking. SSL for login will protected the password. A unique hash will allow the user to continue being authenticated without giving away their password to the account. Storing a large amount of information about the user such as IP, browser agent, etc... will disallow easy hijacking of an account.
The purpose of using a Javascript proxy for the Web Service using a service reference with Script Manager is to avoid a page load. If the information being retrieved is potentially sensitive, is there a way to secure this web service call other than using SSL?
If your worried about other people access your web service directly, you could check the calling IP address and host header and make sure it matches expected IP's addresses.
If your worried about people stealing information during it's journey from the server to the client, SSL is the only way to go.
I would use ssl it would also depend I suppose on how sensitive your information is.
I would:
Use SSL for the connection
Put a time and session based token in the request
Validate the inputs against expected ranges on the server
SSL prevents man-in-the-middle
Tokenized requests verify that the request is coming from an active and authenticated session, within a reasonable amount of time from the last activity within the session. This prevents stale requests being re-submitted and verifies that it came from the source of the session (store the IP address, user-agent, etc on the server for session management).
Validating that the inputs are within expected ranges verifies that the request has not been doctored by the party that you are talking to.
Though SSL would be best, there are a number of client-side cryptography libraries that could alleviate some of the security concerns - see https://github.com/jbt/js-crypto for a nice collection