Session Fixation - Change sessionId on asp.net core 2 - session

Based on what i have understood we have
sessionId is stored in the cookie .AspNetCore.Session
Deleting the cookies and Clearing the session does nothing.
context.HttpContext.Session.Clear();
foreach (var cookie in context.HttpContext.Request.Cookies.Keys)
{
context.HttpContext.Response.Cookies.Delete(cookie);
}
So the question is can we change the sessionId somehow, or is there a way to protect us from Session-Fixing?

...or is there a way to protect us from Session-Fixing?
Yes there is! OWASP states:
Unfortunately, some platforms, notably Microsoft ASP, do not generate new values for sessionid cookies, but rather just associate the existing value with a new session. This guarantees that almost all ASP apps will be vulnerable to session fixation, unless they have taken specific measures to protect against it.
The same page recommends an approach for ASP.Net, which we used for all of our ASP.Net applications and which passed pen testing. I think it is still valid for ASP.Net Core:
The idea is that, since ASP prohibits write access to the ASPSESSIONIDxxxxx cookie, and will not allow us to change it in any way, we have to use an additional cookie that we do have control over to detect any tampering. So, we set a cookie in the user’s browser to a random value, and set a session variable to the same value. If the session variable and the cookie value ever don’t match, then we have a potential fixation attack, and should invalidate the session, and force the user to log on again.
This is a simplified example of how we approached this in .Net Core Razor Pages and should give you an idea of how to implement it yourself:
public IActionResult OnPost()
{
Login();
return Redirect("~/Login");
}
private void Login()
{
// Check the user's credentials and do all the other necessary stuff.
// ...
// Create the random value we will use to secure the session.
string authId = GenerateAuthId();
// Store the value in both our Session and a Cookie.
HttpContext.Session.SetString("AuthId", authId);
CookieOptions options = new CookieOptions()
{
Path = "/",
HttpOnly = true,
Secure = true,
SameSite = Strict
};
Response.Cookies.Append("AuthCookie", authId, options);
}
private string GenerateAuthId()
{
using(RandomNumberGenerator rng = new RNGCryptoServiceProvider())
{
byte[] tokenData = new byte[32];
rng.GetBytes(tokenData);
return Convert.ToBase64String(tokenData);
}
}
Check the content of the Session and Cookie wherever you need it. If they don't match, you should Clear the Session (I don't think Session.Abandon is still available in .Net Core) and log out the user.
public void OnGet()
{
string cookieValue = Request.Cookies["AuthCookie"];
string sessionValue = HttpContext.Session.GetString("AuthId");
if (cookieValue == null || sessionValue == null || cookieValue != sessionValue )
{
// Invalidate the session and log out the current user.
}
}

Session.Clear only removes all data from the session, it does not actually remove the session itself. That will occur when the timeout is hit. It was an odd choice, in my opinion, for the ASP.NET Core team to not have implemented Session.Abandon, as previously existed, since that actually would remove the actual session, itself.
As long as the actual session still exists, even if the data for it no longer does, it can still be retrieved by that session id, as a result, the problem shifts to the client-side.
Importantly, the server cannot actually make the client do anything. Calling Cookies.Delete really only sends a new Set-Cookie response header for the same cookie with an expiration date in the past. This should prompt the client (browser, most likely) to then remove that cookie, since it is now expired. However, that is totally 100% on the client, so if there's a bug or the client otherwise is not picking up the change or the client simply refuses to comply for whatever reason, the cookie will remain. Then, again, if the cookie still exists and the session identified by the session id it contains still exists, it can be restored.
Long and short, the code you have should work, and there's really not anything else you can do other than what you're already doing. If the session isn't being abandoned, there's some other issue somewhere (most likely with the client).

Related

What is the best way to manage a user's session in React?

I have a doubt about how to manage a user's session in React, for example in MVC .NET you only just do this using the Session object (e.g. Session["test"] = "";), but obviously React can not do this.
I was reading about using the component state, I suppose that sets the state at the principal component and passes this state to other components using props. Also I saw people recommending the use the browser's localStorage or cookies, but I don't know if this if a good idea or practice.
Is there a better way to manage sessions variables in React than localStorage or cookies?
I would avoid using component state since this could be difficult to manage and prone to issues that can be difficult to troubleshoot.
You should use either cookies or localStorage for persisting a user's session data. You can also use a closure as a wrapper around your cookie or localStorage data.
Here is a simple example of a UserProfile closure that will hold the user's name.
var UserProfile = (function() {
var full_name = "";
var getName = function() {
return full_name; // Or pull this from cookie/localStorage
};
var setName = function(name) {
full_name = name;
// Also set this in cookie/localStorage
};
return {
getName: getName,
setName: setName
}
})();
export default UserProfile;
When a user logs in, you can populate this object with user name, email address etc.
import UserProfile from './UserProfile';
UserProfile.setName("Some Guy");
Then you can get this data from any component in your app when needed.
import UserProfile from './UserProfile';
UserProfile.getName();
Using a closure will keep data outside of the global namespace, and make it is easily accessible from anywhere in your app.
There is a React module called react-client-session that makes storing client side session data very easy. The git repo is here.
This is implemented in a similar way as the closure approach in my other answer, however it also supports persistence using 3 different persistence stores. The default store is memory(not persistent).
Cookie
localStorage
sessionStorage
After installing, just set the desired store type where you mount the root component ...
import { ReactSession } from 'react-client-session';
ReactSession.setStoreType("localStorage");
... and set/get key value pairs from anywhere in your app:
import { ReactSession } from 'react-client-session';
ReactSession.set("username", "Bob");
ReactSession.get("username"); // Returns "Bob"
This not the best way to manage session in react you can use web tokens to encrypt your data that you want save,you can use various number of services available a popular one is JSON web tokens(JWT) with web-tokens you can logout after some time if there no action from the client And after creating the token you can store it in your local storage for ease of access.
jwt.sign({user}, 'secretkey', { expiresIn: '30s' }, (err, token) => {
res.json({
token
});
user object in here is the user data which you want to keep in the session
localStorage.setItem('session',JSON.stringify(token));
To name a few we can use redux-react-session which is having good API for session management like, initSessionService, refreshFromLocalStorage, checkAuth and many other. It also provide some advanced functionality like Immutable JS.
Alternatively we can leverage react-web-session which provides options like callback and timeout.

How to migrate a cached ServiceStack session to a new "version"

When we add new properties to our custom AuthUserSession based session DTO, we either need to invalidate users active sessions and force them to re-login, or migrate their sessions (either in mass, or in lazy fashion). If this is not done, expected properties will not be filled, and adds a lot more complexity to the code relying on those properties.
I dug around and looked for any events around hydration of sessions from cache, but didn't see any easy place to tie in and determine if the session should be refreshed.
Any suggestions on where to plug in such logic in the flow where it will always happen before some session object is used by a ServiceStack Service or Razor view?
For Caching providers that implement ICacheClientExtended you can access all Sessions with:
var sessionPattern = IdUtils.CreateUrn<IAuthSession>(""); //= urn:iauthsession:
var sessionKeys = Cache.GetKeysStartingWith(sessionPattern).ToList();
var allSessions = Cache.GetAll<IAuthSession>(sessionKeys);
Otherwise I've just added a custom hook to be able to filter a session (in this commit), by overriding OnSessionFilter() in your AppHost, e.g:
public override IAuthSession OnSessionFilter(IAuthSession session, string id)
{
return base.OnSessionFilter(session, id);
}
This change is available from v4.0.49 that's now available from MyGet.

Real Dilemma when using Sessions, Cookies in Yii

I have set sessions for my properties/methods in WebUser like following
public function getRole(){
$user = $this->loadUser(Yii::app()->user->id);
$this->setState('roleId', $user->roles_id);
return $user->roles_id;
}
In the config, I have set autostart sessions to 'true', cookieMode to 'only'. I understand that when i 'setState', the cookie with the same name is also created along with the session variable. Currently I am calling these variables using Yii::app()->user->roleId;
My question is this:
a) To utilize from the cookies and/or the session variables already set, should i call them using Yii::app()->request->cookies['roleId']; or Yii::app()->session['roleId']?
b) Will calling Yii::app()->user->roleId get me the value if it is already set as Cookie or Session instead of running the whole method again?
I appreciate your support!
I would only use sessions for that. Cookies can be easily tampered with and a user could probably assign himself another role id. Session is somewhat safer.
Use your WebUsers getRole() for that, which caches it in the session like you have above. This is fine. Just put a check at the top, if there is a session var roleId instantly return it. If not, load the user and get it there like you already have.

Security: Session Identifier Not Updated in tcl

I'm working on open-source application "Project-Open" and during the scanning I got the following vulnerability:
[Medium] Session Identifier Not Updated
Issue: 13800882
Severity: Medium
URL: https://<server_name>/register/
Risk(s): It is possible to steal or manipulate customer session and cookies, which might be used to impersonate a legitimate user,allowing the hacker to view or alter user records, and to perform transactions as that user
Fix: Do not accept externally created session identifiers
though the fix is mentioned but it is not sufficient for me to understand it completely.please guide me how should I remove this.Also let me know if any further details are needed to understand the question.
The project source code is in tcl
I found the following code which does the same but it's in java.
public HttpSession changeSessionIdentifier(HttpServletRequest request) throws AuthenticationException {
// get the current session
HttpSession oldSession = request.getSession();
// make a copy of the session content
Map<String,Object> temp = new ConcurrentHashMap<String,Object>();
Enumeration e = oldSession.getAttributeNames();
while (e != null && e.hasMoreElements()) {
String name = (String) e.nextElement();
Object value = oldSession.getAttribute(name);
temp.put(name, value);
}
// kill the old session and create a new one
oldSession.invalidate();
HttpSession newSession = request.getSession();
User user = ESAPI.authenticator().getCurrentUser();
user.addSession( newSession );
user.removeSession( oldSession );
// copy back the session content
for (Map.Entry<String, Object> stringObjectEntry : temp.entrySet()){
newSession.setAttribute(stringObjectEntry.getKey(), stringObjectEntry.getValue());
}
return newSession;
}
P.S. I'm newbie in TCL.
please let me know if you need any further explanation.
There is a fix in OpenACS 5.9 that addresses your scanning reports. Please see the following discussion on OpenACS.org for reference.
http://www.openacs.org/forums/message-view?message_id=5332821
The problem that the OWASP report is talking about is the inability to migrate a session to use a new ID, making it easier for an attacker to discover the ID and reuse it. The protection against this is to change the session ID from time to time (no, I don't know how often!) and that Java code is involved in doing just that.
A session is represented as a token stored in the browser, usually in a cookie (and this is what cookies are designed to do). That token is then used to look up the database record corresponding to the session, which holds serializations of the key/value mappings in the session. It's a simple mechanism, but very powerful. The Java code for doing all this will be fairly complex behind the scenes because of the serialization, etc., but Tcl values are (usually, and always for built-in types) naturally serializable and so should prove much less of a problem in this; copying a session to a new key could be done without having to deserialize in the first place.
The exact code for doing this depends on the framework in use. I don't know what ]project-open[ uses, so that's as far as we can drill right now. You need to talk to other people actually working on PO…
For all that, the best way would be to make the key given to clients not be the primary key, so that you can change the session key without having to delete things. Just have a session key column (with an index!) and you'll be able to make things work fine. This is a more sophisticated approach though; it might not be practical to implement in your environment..

Manage multiple calls of Membership.GetUser().ProviderUserKey;

I was thinking yesterday how to solve this issue, because everything what i give or check about user is depended of his ProviderUserKey (ID).
So i made one static function like
public static Guid GetUserID()
{
string UserID = string.Empty;
if(HttpContext.Current.Session["UserID"] != null)
{
UserID = HttpContext.Current.Session["UserID"].ToString();
}
if(!string.IsNullOrEmpty(UserID))
{
return new Guid(UserID);
}
UserID = Membership.GetUser().ProviderUserKey.ToString();
HttpContext.Current.Session["UserID"] = UserID;
return new Guid(UserID);
}
Main point of this class is to reduce database connections to check/get user ID.
My problem with this function is not that this is not working, my problem is what if logged user log out and log with another account?
Or Is it better to add session value on log in and clear session value on log out?
Where you can see any other problem with this kind of "Get User ID"?
If you log the user out then you should also be killing the session.
When you login as another user you would also have the session reinitialized.
Note you'll want to keep the session and forms auth timeouts (assuming you are using forms auth) in sync with each other:
How can I handle forms authentication timeout exceptions in ASP.NET?
This should help keep the session in line with the forms auth token. You'll in turn need to kill the session on logout and intialize it upon login.
Another alternative is to implememt your own membership provider that caches this key to prevent constant db hits.
have you tried using the ProfileProvider?
you can use and customize with special properties and that's is managed by session each user.
example to get values:
HttpContext.Profile.GetPropertyValue["CustomProperty"]
In this video you can lean to implement it, create, configure and use...
http://www.asp.net/web-forms/videos/how-do-i/how-do-i-create-a-custom-profile-provider

Resources