using System;
namespace Core {
public class SessionContext {
public string UserName { get; set; }
public string SessionID { get; set; }
}
}
Evitar las sesiones concurrentes.
A continuación se describen las circunstancias bajo las cuales la siguiente solución tiene sentido:
Un aplicativo permite iniciar sesión desde varias ubicaciones con el mismo usuario.
Al momento de desarrollar aplicaciones web que utilizan sesiones, es muy importante que por diseño el sistema sea capaz de detectar cuando un usuario ha iniciado sesión de forma simultánea desde diferentes IP. Es en este momento que la aplicación debe tomar medidas para evitar que este escenario ocurra al implementar acciones efectivas.
Cuando se presenta una sesión concurrente, las acciones recomendadas incluyen [2]:
Terminar inmediatamente la sesión abierta anteriormente.
Informar al usuario (ya sea el que inicio la sesión nueva, la sesión antigua o en ambas sesiones) acerca del evento.
Durante estos eventos es altamente recomendado que la aplicación implemente características para terminar las sesiones de forma manual y registre información de la sesión, almacenando detalles del cliente como: dirección IP, User-Agent, fecha y hora de inicio de sesión, tiempo de inactividad, etc. A continuación mostraremos cómo limitar el número de sesiones concurrentes en ASP.NET
Esta solución aplica cuando no es posible utilizar las características de IIS para controlar las sesiones. En caso de que no pueda modificar el comportamiento de IIS, esta es una posible solución para dotar a SharePoint de esta funcionalidad. La solución se basa en interceptar las peticiones al servidor implementando el módulo httpModule. Para que pueda funcionar se ha de crear la clase auxiliar que permitirá almacenar el contexto de sesión del usuario:
using System;
namespace Core {
public class SessionContext {
public string UserName { get; set; }
public string SessionID { get; set; }
}
}
La clase SessionManagerModule se encarga de procesar las solicitudes. Note que en el método Init se crea la colección que permitirá llevar rastro de las sesiones y de los estados.
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
namespace Core {
public class SessionManagerModule :IHttpModule {
public SortedDictionary<string, SessionContext> ASPNETContext { get; set; }
#region IHttpModule Members
public void Init(HttpApplication context) {
// Initializes the Application variable
if (context.Application["sessionSortedList"] == null) {
ASPNETContext = new System.Collections.Generic.SortedDictionary<string, SessionContext>();
context.Application["sessionSortedList"] = ASPNETContext;
}
context.PostAcquireRequestState += new EventHandler(context_PostAcquireRequestState);
}
El método context_PostAcquireRequestState se encarga de validar si las sesiones coinciden o si han cambiado (en caso de que se trate de una sesión válida en otro navegador).
void context_PostAcquireRequestState(object sender, EventArgs e) {
HttpApplication application = (HttpApplication)sender;
// Get the Application Context variable
var ASPNETContext = (SortedDictionary<string, SessionContext>)application.Application["sessionSortedList"];
HttpContext context = application.Context;
string filePath = context.Request.FilePath;
string fileExtension = VirtualPathUtility.GetExtension(filePath);
if (fileExtension.Equals(".aspx")) {
if (application.Context.Session != null) {
// Get the User Name
string userName = (application.Session != null) ? (string)application.Session["userName"] : string.Empty;
userName = userName ?? string.Empty;
//Try to get the current session
SessionContext currentSessionContext = null;
ASPNETContext.TryGetValue(userName, out currentSessionContext);
if (currentSessionContext != null) {
// Validates old sessions
bool session = currentSessionContext.SessionID == application.Session.SessionID;
if (!session) {
// Sing out
FormsAuthentication.SignOut();
// Remove from Session
application.Session.Clear();
application.Session.Abandon();
application.Context.Response.Cookies["ASP.NET_SessionId"].Value = "";
// Redirect
FormsAuthentication.RedirectToLoginPage();
}
}
}
}
}
public void Dispose() { }
#endregion
}
}
Cuando el usuario inicie sesión se ha de crear una nueva variable del tipo SessionContext que sobrescriba la anterior y la haga inválida, para lograr esto, se debe añadir el siguiente código al eventoLoggedIn:
void Login1_LoggedIn(object sender, EventArgs e) {
if (HttpContext.Current.Session != null) {
string sessionID = Session.SessionID;
string userName = Encoder.HtmlEncode(Login1.UserName);
DateTime dateStarted = DateTime.Now;
Session["userName"] = userName;
// Get the Application Context variable
var ASPNETContext = (SortedDictionary<string, SessionContext>)Application["sessionSortedList"];
// Create a new SessionContext variable
var sContext = new SessionContext() { SessionID = sessionID, UserName = userName };
// Refresh the object to the Application
if (ASPNETContext != null) {
ASPNETContext[userName] = sContext;
Application["sessionSortedList"] = ASPNETContext;
}
}
}
Al cerrar sesión se debe remover la sesión. Para lograr esto, se ha de adicionar el siguiente código al evento LoggingOut:
void LoginStats_LoggingOut(object sender, LoginCancelEventArgs e) {
string userName = (string)Session["userName"];
userName = userName ?? string.Empty;
// Get the Application Context variable
var ASPNETContext = (SortedDictionary<string, SessionContext>)Application["sessionSortedList"];
//Try to get the current list
SessionContext currentSessionContext = null;
if (ASPNETContext != null) {
ASPNETContext.TryGetValue(userName, out currentSessionContext);
// Refresh the object to the Application
if (currentSessionContext != null) {
ASPNETContext.Remove(userName);
Application["sessionSortedList"] = ASPNETContext;
}
}
FormsAuthentication.SignOut();
Session.Clear();
Session.Abandon();
HttpContext.Current.Response.Cookies["ASP.NET_SessionId"].Value = "";
}
Finalmente, en web.config se debe habilitar el módulo recién creado:
<system.web>
<httpModules>
<!-- any other modules above -->
<addname="SessionManagerModule"type="Core.SessionManagerModule, Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=TYPEYOURKEYHERE" />
</httpModules>
</system.web>
<system.webServer>
<modulesrunAllManagedModulesForAllRequests="true">
<!-- any other modules above -->
<addname="SessionManagerModule"type="Core.SessionManagerModule, Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=TYPEYOURKEYHERE" />
</modules>
</system.webServer>
Puedes descargar el código fuente pulsando en el siguiente enlace:
Copyright © 2021 Fluid Attacks, We hack your software. All rights reserved.