session fixation - ruby-on-rails

I am new to web development, and trying to get a hold on security issues. I went through this article on http://guides.rubyonrails.org/security.html these are some of the steps the author has mentioned how an attacker fixes session.
The attacker creates a valid session id: He loads the login page of the web application where he wants to fix the session, and takes the session id in the cookie from the response (see number 1 and 2 in the image).
He possibly maintains the session. Expiring sessions, for example every 20 minutes, greatly reduces the time-frame for attack. Therefore he accesses the web application from time to time in order to keep the session alive.
Now the attacker will force the user’s browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: <script> document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9"; </script>. Read more about XSS and injection later on.
The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim’s browser will change the session id to the trap session id.
As the new trap session is unused, the web application will require the user to authenticate.
From now on, the victim and the attacker will co-use the web application with the same session: The session became valid and the victim didn’t notice the attack.
I dont understand couple of points.
Why is user made to login in step5, since session is sent through?
I saw possible solutions on wiki, like user properties check and others. Why cant we just reset the session for the user whoever is login in when they enter username and password in step5?

1) The attacker receives a session in steps 1&2 which is not logged in yet. This is the trap session. At step 5 the victim logs in thinking that the session id is new (and 'secret'). At the moment when the victim is logged in the attacker is able to re-use the 'secret' session id and effectively is logged in as well.
So to answer your question: the victim is made to login because the trap session is not logged in yet in order to trick the victim to login using this session id.
2) After explaining the steps of session fixation, the first counter measure (section 2.8) is to create a new session and abandon the old on after logging in. Exactly what your idea was!

Related

Rails4 security: Session fixation possible at all using encrypted cookies?

After studying the rails guide and some other ressources I'm wondering how a session fixation attack on a user's session can actually happen. At least I'm sceptical it works as simple as depicted here in the guide, where an attacker...
1) ...creates a valid session by logging in
2) ...keeps the session alive
3) ...then forces the user to use his session's id e.g. by using some XSS vulnerability
All fine, but... how would the attacker be able to gather the value of his own session id? By default cookies are encrypted in Rails4+. So what to do as an attacker assuming I do not have access to secret_key_base or whatever is used to generate the encryption and signature keys? From what I understand I cannot tamper with the cookie without invalidating it (signature wrong) so somehow passing a self-created cookie to a possible victim is neither an option.
Is the secu guide kind of not up to date or am I missing a point here? If the latter then...
a) how [as an attacker] can I read encrypted cookie information
b) how does a vulnerability have to look like that allows me [the attacker] to inject that session id into the likewise encrypted cookie on another client? Would that be an XSS attack? The guide states that if an attacker uses code like
<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>
he might be able to fix that session. But again, why would rails reveal it's plain session to the client making it accessible via client-side processed javascript? It does not, which is why all my cookie-values are simple gibberish not being accessible by Javascript (can test that via console), right?
Thanks for any advice!
It's not so much about the cookie encryption (or signing). Without signing and/or encryption, the attacker wouldn't need to resort to session fixation with a site that stores session data in a cookie; they could just craft their own cookie.
Assume the attacker has a way to inject cookie-setting JavaScript onto a page that a victim will visit, i.e., an XSS vulnerability. Here's how the attack plays out:
The attacker visits the site and gets a session cookie.
The attacker crafts malicious JavaScript, exploits the XSS vulnerability, and waits for a user to visit (or lures a user to) the page containing the malicious JavaScript payload.
<script>document.cookie="_appname_session=(...attacker's session cookie...)";</script>
A victim comes along and visits the page with the malicious JavaScript, setting or overwriting their session cookie with the one from the attacker.
If they were logged in, the site will no longer recognize them as an authenticated user, and will probably redirect them to log in.
If they weren't logged in, they will be redirected to the login page.
They authenticate with their username and password.
At this point both the victim and the attacker have a cookie containing a session_id belonging to a user who has authenticated.
CookieStore, the Rails default session store
Normally you will set some value in the session to indicate that the user is authenticated. Even if it is as simple as session[:logged_in] = true, it will change the value of the cookie, and the attacker won't be able to access the site, even though the session_id is the same, because the attacker's cookie does not contain the additional data indicating an authenticated session.
Other session storage strategies
Here's where this attack is more feasible. Other session stores still use a cookie to hold the session_id, but they store session data elsewhere — in the cache, in a database, in memcached, etc. In this case, when the attacker visits the site after the victim has authenticated, the attacker's cookie — with the same session_id — will cause the session to be loaded.
HttpOnly
However, there is another major impediment to this attack — HttpOnly cookies.
Set-Cookie: _appname_session=v%2Ba...; path=/; HttpOnly
When a cookie is designated HttpOnly, as Rack/Rails session cookies are, the browser does not expose it through document.cookies. It can neither be read nor overwritten by JavaScript. I tried setting a known session cookie via document.cookie, but it was not possible unless I cleared the existing cookie(s) first. This means that an attacker would need a user who doesn't have a session cookie yet to visit the page with the XSS exploit (which would need to be on a page without a session cookie) before logging in.
As I understand it, session fixation won't work if the session details are stored in the cookie itself. The old fashioned way of doing sessions, the session data would be saved in some sort of database. The session id that got saved in the cookie would point to the record or file where the session data was saved. This means as the session changed the cookie wouldn't change at all. If a hacker had the same cookie as the user, when the user logged in they could potentially be able to hijack the login since their cookie would point to the session that now had a user_id (and potentially other data) attached to it. Under the new system, any change to the session also changes the cookie so the hackers old cookie would just have an empty session.
That being said, it's still a best practice to add reset_session to login, logout and registration endpoints (if you use something like devise this may be done for you) since if you or some future developer changes the session store to be database backed you could end up shooting yourself in the foot. The security guide also doesn't know what type of session store you are using so they have to include that advice.

Good Method To Prevent Session Hijacking?

Scenario:
Upon starting a session on my site, I generate a rand token that is shown to the user that once. Say they “store” it away for later use.
I then, INSERT the md5(token) into SQL with timestamp.
When the user visits other pages like login, they would have to pass the token via URL as part of the validation process. I would check to see if the token exist and maybe UPDATE userid to this token.
So. Even if someone steals a user’s PHPSESSID cookie, wouldn’t it do ANY good to the hacker since they can’t access any of these pages without knowing the token?
You are right that they won't be able to access the pages without the token, but as an added point, sometimes I'd like to use IP tracking or browser tracking used concurrently as well.
The rationale being that even if someone gets a PHPSESSID cookie and the token, he would have to be coming from the same IP source as well as use the same browser. Then again these are just means of security by obscurity.
I recommend if you are really concerned about security, you can try looking at using a HTTPS connection. Hope it helped. Cheers!

Should the SessionID in the QueryString or the Cookie of a GET request take precedence?

If I receive a request to the url host.com/site-directory/page-slug.html?session={someValidNonExpiredSessionGuid} and I detect a session cookie with the value: {someOtherValidNonExpiredSessionGuid}, then
Which session is the correct session to associate with the request?
Here's some background:
The pattern I am using for maintaining state across HTTP requests is to store a unique ID in the querystring, form collection and/or cookie. Then, on each request, I locate the unique Id and pull date from a database table. If the id is not valid, or the session is expired, a new session will be created (with a new id, a new cookie, etc).
The default behavior is that all forms will have a field:
<input type="hidden" name="session" value="{someGuid}" />
All links to other pages on the site will have an appended querystring parameter
a sample link
And, if the user's browsing device supports cookies, a cookie will be set having the session's value.
If I have validated that the user's browsing device supports cookies, then my form and querystring will no longer require the the session id field/parameter.
However, I am having a conceptual issue in deciding whether the session parameter of the querystring should take precedence over the cookie value or vice-versa. It seems like I could potentially get bad data in either circumstance. I could get data with a bad querystring parameter if the user bookmarked a page with the session parameter included in the URL. I could also get bad data from the cookie, if a user closes the browser without terminating the session, and the session expire-window has not yet closed. It also seems like both options could be vulnerable to a malicious user intercepting the request and sending a request with the same session information.
So, once again, my question is
If I receive a request to the url host.com/site-directory/page-slug.html?session={someValidNonExpiredSessionGuid} and I detect a session cookie with the value: {someOtherValidNonExpiredSessionGuid}, then Which session is the correct session to associate with the request?
I am leaning towards the cookie session, because it seems like the most common scenario will be a bookmark with the session included. I've already decided that the form post data should take the greatest precedence, because a page will always render the form with the correct ID, and the only possible situation with a wrong, non-expired ID is a very quickly implemented XSS attack, which is circumvented by including a request-scoped anti-forgery token field.
In addition to the primary question I appreciate any insight to any security-related or logical oversights I have expressed in this description. I apologize for the long post, but felt it was necessary to explain the situation. Thank you very much for your input.
Also, it is not necessarily relevant to the question, but I am using ASP.NET MVC in most situations, and setting my cookies manually with Response.Cookies.
From a security standpoint sessions should not be stored in query strings.
For example:
If sessions are stored in queries and you link to a remote host on the same page, the users valid session could be sent to the remote host via the referer header.
Sessions should always be stored in cookies.
You should try to store it in the cookie (looking the the browser caps to see if the browser supports cookies) and then have a fall back for query string.
I too would lean towards using the cookie session ID in case of ambiguity. This primarily because I'd trust the cookie implementation to be more well baked, more well tested, and more idiot-proof than my own home brewed session tracking implementation. For e.g. there are cases where ASP.NET automatically knows to clear the session cookies, renew them etc.
Also, I would design it so the cookies aren't persistent to minimize the edge cases. If the user closes the browser, then the session is closed.
The other simplification I would consider is to have either cookies or URL based tracking and not both. If the browser supports cookies, there is really no reason to also track the session through a URL.
Thoughts?
Curious ... What were your reason to rule out using the stock ASP.NET cookieless session implementation? - http://msdn.microsoft.com/en-us/library/aa479314.aspx#cookieless_topic2
If I receive a request to the url
host.com/site-directory/page-slug.html?session={someValidNonExpiredSessionGuid}
and I detect a session cookie with the
value:
{someOtherValidNonExpiredSessionGuid},
then Which session is the correct
session to associate with the request?
To answer your specific question, I'd recommend putting session management in the cookies as opposed to the querystring. As has been mentioned, cookies can be set to expire whereas the querystring cannot. This allows your thin-clients to assist in their own session maintenance by removing their own expired cookies. Moreover, since cookies are dropped to specific browsers, you reduce the chances of another browser spoofing the original browser session.
The only way I would use the querystring to pass session information would be as a backup method to re-establish a browser session onto a new browser instance. Here's a scenario: you have an active session using browser A on machine A which suffers some catastrophic error. You want a way to re-establish that same session on another browser instance on either the same machine or on another machine. If your code-behind can recognize that the session cookie doesn't exist, but that a valid session id exists in the querystring, you could initiate a challenge-response to verify the integrity of that session id and then drop a new session cookie on the new machine. Kinda extreme in my humble opinion, but the functionality might be useful in certain situations.
ADDED: I understand that you may want to accommodate users who have turned cookies off on their browsers, and while you can use the querystring to hold the session id I'd recommend against it. But if you must, encrypt that sucker using browser-machine specific information.

When does the .NET FormAuthentication ticket get checked and how do I tap into this event?

We are attempting to integrate an ASP.NET MVC site with our client's SSO system using PingFederate. I would like to use the built in FormsAuthentication framework to do this. The way I've gone about it so far is:
Set up my Web.config so that my FormsAuthentication LoginURL goes to my site's "BeginAuthentication" action on a "Security" controller. From this action, I set up some session variables (what URL was being accessed, for example, since Ping won't send this info back to me), and then redirect to our client's login page on an external site (www.client.com/Login for example).
From here, the authentication takes place and a cookie is generated on the same domain as the one that our application is running on which contains the unique identifier of the authenticated user, I've set it up so that once this happens, the Ping server will redirect to my "EndAuthentication" action on my "Security" controller.
In this action, I call my membership class's "ValidateUser" method which takes this unique identifier from the cookie and loads in the user on our application that this ID refers to. I save that logged in user in our Session (Session["LoggedInAs"], for example) and expire the cookie that contains the id of the authenticated user that the SSO system provided for me.
All of this works well. The issue I'm wondering about is what happens after our user has already authenticated and manually goes back to our client's login page (www.client.com/login) and logs in as another user. If they do that, then the flow from #2 above to number 3 happens as normal - but since there already exists an authenticated user on our site, it seems as though the FormsAuthentication system doesn't bother kicking off anything so I don't get a chance to check for the cookie I'm looking for to login as this new user. What I'd like to do is, somewhere in my Global.asax file (probably FormsAuthenticate_OnAuthenticate), check to see if the cookie that the SSO system sends to me exists, and if so, sign out of the application using FormsAuthentication.SignOut().
Another issue that seems to be related is that if I let my Session expire, the FormsAuthentication still seems to think I am authenticated and it lets me access a page even though no currently logged in user exists in my Session, so the page doesn't render correctly. Should I tap into the Session_End event and do FormsAuthentication.SignOut() here as well?
Basically, I want to know when the authentication ticket created by
System.Web.Security.FormsAuthentication.SetAuthCookie(..) gets checked in the flow of a request so that I can determine whether I need to SignOut() and force revalidation or not.
Thanks for any help. Sorry for the length of this message, trying to be as detailed as possible.
Mustafa
Welcome to the small section of Hades that is mixing session with formsauth.
If your needs are as complex as presented, you would get more sleep if you implement a full provider stack to share amongst the participating sites. Easier said than done, I know.
But to address your question:
from http://www.codeproject.com/Articles/39026/Exploring-Web-config-system-web-httpModules.aspx
On the way in....Check ticket and set identity #
app.AuthenticateRequest += System.Web.Security.FormsAuthenticationModule.OnEnter-->OnAuthenticate
On the way out... set the ticket and redirect as necessary
app.EndRequest += System.Web.Security.FormsAuthenticationModule.OnLeave
Reflector is your friend. ;-)
I don't know about a specific event for when the cookie is checked, but you could place the appropriate logic in Application_BeginRequest() and check the user's authentication state there.
Another issue that seems to be related
is that if I let my Session expire,
the FormsAuthentication still seems to
think I am authenticated and it lets
me access a page even though no
currently logged in user exists in my
Session, so the page doesn't render
correctly.
The life of the cookie (how long until ASP.NET feels it needs to ask for a password again) and how you are managing state are unrelated. The ASP.NET authentication is cookie based so that, should a developer want to, he could turn off viewstate, session, use no query strings or hidden fields and authentication still works.
If you want to tie the interval at which you request the password to how you are persisting data, then you will want your session expiration to be roughly the same as the cookie expiration, but they will never quite match up. It would be better to have two policies (one for how fast you throw away a users session data and one for how long you are willing to wait before you need to reask for a password)

Implementing sessions in rails

I'm doing a first pass at rolling my own authentication and sessions in rails and am not sure that I understand the session support that is present. (By first pass, I mean I'm initially authenticating via http, not https. Production code will use https.)
My understanding of secure sessions is that you pass a token to the browser via a cookie over SSL, and then compare that token with the token stored on the server to see if it's really the user you think it is. I was hoping you guys could check my understanding of secure sessions, which is as follows:
User gets login page and submits login name and password (POST via SSL).
Server checks protocol and then checks sha1 of password (+ salt, usually) against existing hash in db. If they match, generate a session id, put it both in a(n SSL) cookie with the user id and in a server-side session store. Redirect user to the secured area of the site.
That session id remains the same throughout the user's logged in session --or-- the server issues a new session id after each secure operation, sending it via an SSL cookie and storing the new value in the db.
Any actions that involve private or secure data checks the session store for the existence of a session id for this user and, if present, compares the cookie's session_id against the session store before performing the action. If we're rotating session ids, issue a new session id (SSL cookie and server-side store) after the action.
User logs out, which tells the server to remove the session id from the session store and clear the cookie. Or the cookie expires on the browser and/or on the server and re-authentication is required.
Are there any glaring errors in the above? Also, it seems like Rails' session[] support wouldn't prevent MITM attacks if the token in the cookie was merely a session id. Is that correct?
I would suggest having a look at restful_authentication. This is the defacto standard auth library for Rails.
You don't actually need to generate the session_id yourself ... Rails handles all of this for you - checking the session id against the value provided by the browser. You can actually just store the user id in Rails session collection and then check that this exists.
You would technically be vulnerable to MITM attack if you do not use an SSL connection.
You seem to be confusing 'the session' and 'being logged in'. The session object in Rails is just a hash, stored in a cookie, and it is always present—regardless of whether or not the user has logged in.
As you outline, the most common procedure is to store the user's ID in the session.
The restful_authentication plugin does a lot of things. Perhaps you find my Blank Rails App more helpful, as it does something similar with a lot less code. Take a look at the sessions controller and lib/authentication, where the authentication related controller code is defined.
Try this web site, http://www.quarkruby.com/2007/10/21/sessions-and-cookies-in-ruby-on-rails. It appears to have a pretty comprehensive coverage of the subject.
One suggestion that I would have would be to not only use SSL but also encrypt and encode (Base 64) the session and other cookies that you send. Include a nonce (random value) with the session id so that the encrypted/encoded version changes every time you send it. If you are genuinely concerned about the session being hijacked you could also regenerate the session id periodically to limit the exposure of a hijacked cookie, although encrypting it should protected you if the cookies aren't persistent.
You should be able to use the encryption/encoding idea even if you use query parameters for the session id instead of cookies.

Resources