feat: add user agent verification to session
This commit is contained in:
parent
caceb0fe4c
commit
d38167bb97
@ -17,6 +17,7 @@ internal sealed class SessionConfiguration : IEntityTypeConfiguration<Session>
|
|||||||
builder.Property(e => e.Updated).IsRequired();
|
builder.Property(e => e.Updated).IsRequired();
|
||||||
builder.Property(e => e.LastAccessed).IsRequired();
|
builder.Property(e => e.LastAccessed).IsRequired();
|
||||||
builder.Property(e => e.Expires).IsRequired();
|
builder.Property(e => e.Expires).IsRequired();
|
||||||
|
builder.Property(e => e.UserAgent).HasMaxLength(255).IsRequired();
|
||||||
builder.Property(e => e.UserId);
|
builder.Property(e => e.UserId);
|
||||||
builder.Property(e => e.IpAddress).HasConversion<IPAddressToBytesConverter>().IsRequired();
|
builder.Property(e => e.IpAddress).HasConversion<IPAddressToBytesConverter>().IsRequired();
|
||||||
builder.Property(e => e.RequiresTotp).IsRequired();
|
builder.Property(e => e.RequiresTotp).IsRequired();
|
||||||
|
@ -49,6 +49,12 @@ public interface ISession
|
|||||||
/// <value>The update timestamp.</value>
|
/// <value>The update timestamp.</value>
|
||||||
DateTimeOffset Updated { get; }
|
DateTimeOffset Updated { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the user agent string associated with this session.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The user agent string.</value>
|
||||||
|
string UserAgent { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user ID associated with the session.
|
/// Gets the user ID associated with the session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -25,6 +25,9 @@ internal sealed class Session : ISession
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public DateTimeOffset Updated { get; set; }
|
public DateTimeOffset Updated { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string UserAgent { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Guid UserId { get; set; }
|
public Guid UserId { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,8 @@ internal sealed class SessionService : BackgroundService, ISessionService
|
|||||||
Updated = now,
|
Updated = now,
|
||||||
LastAccessed = now,
|
LastAccessed = now,
|
||||||
Expires = now + TimeSpan.FromDays(1),
|
Expires = now + TimeSpan.FromDays(1),
|
||||||
RequiresTotp = !string.IsNullOrWhiteSpace(user.Totp)
|
RequiresTotp = !string.IsNullOrWhiteSpace(user.Totp),
|
||||||
|
UserAgent = request.Headers.UserAgent.ToString()
|
||||||
};
|
};
|
||||||
EntityEntry<Session> entry = context.Sessions.Add(session);
|
EntityEntry<Session> entry = context.Sessions.Add(session);
|
||||||
context.SaveChanges();
|
context.SaveChanges();
|
||||||
@ -203,16 +204,29 @@ internal sealed class SessionService : BackgroundService, ISessionService
|
|||||||
if (!remoteIpAddress.TryWriteBytes(remoteAddressBytes, out _) ||
|
if (!remoteIpAddress.TryWriteBytes(remoteAddressBytes, out _) ||
|
||||||
!session.IpAddress.TryWriteBytes(sessionAddressBytes, out _))
|
!session.IpAddress.TryWriteBytes(sessionAddressBytes, out _))
|
||||||
{
|
{
|
||||||
|
_logger.LogWarning("Failed to write bytes for session {Id}", session.Id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!remoteAddressBytes.SequenceEqual(sessionAddressBytes))
|
if (!remoteAddressBytes.SequenceEqual(sessionAddressBytes))
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("Session {Id} has IP mismatch (wanted {Expected}, got {Actual})", session.Id,
|
||||||
|
session.IpAddress, remoteIpAddress);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userAgent = request.Headers.UserAgent.ToString();
|
||||||
|
if (session.UserAgent != userAgent)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Session {Id} has user agent mismatch (wanted {Expected}, got {Actual})", session.Id,
|
||||||
|
session.UserAgent, userAgent);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_userService.TryGetUser(session.UserId, out _))
|
if (!_userService.TryGetUser(session.UserId, out _))
|
||||||
{
|
{
|
||||||
|
_logger.LogWarning("User {Id} not found for session {Session} (client {Ip})", session.UserId, session.Id,
|
||||||
|
remoteIpAddress);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user