Компрометация и изменение сессионных данных

Встал вопрос о том, а могут ли сессионные данные скомпрометированы или же изменены на стороне клиента.

Допустим я сохраняю данные пользователя в сессии

HttpContext.Session.SetString(ROLE, "User")

И не хотелось бы при получении этих данных из сессии, получить роль не User, а допустим Admin

Ибо в моем случае данных из сессии используются для создания jwt.

Так вот, как я понимаю, юзеру не приходят сами данные, ему приходит лишь идентификатор сессии, и было бы логично предположить что данные не могут быть скомпрометированы или изменены, так как сами данные хранятся на сервере, а юзер имеет лишь идентификатор, и не взаимодействует с этими данными напрямую.

Но я не уверен в этом, возможно есть какие-то дыры, которых стоит опасаться, если такие есть, расскажите о таковых.

Буду премного благодарен любой информации.

Моя ситуация, почему я считаю что мне нужны сессии:

Мейн эндпоинт который валидирует данные, и в целом выполняет некоторую логику:

    [HttpPost("login")]
    public async Task<IActionResult> Login(UserModel userModel)
    {
        try
        {
            if (userModel.email is null || userModel.password is null)
                return StatusCode(422, new { message = AccountErrorMessage.InvalidUserData });

            var email = userModel.email.ToLowerInvariant();
            var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.email == email);
            if (user is null)
                return StatusCode(404, new { message = AccountErrorMessage.UserNotFound });

            bool IsCorrect = _passwordManager.CheckPassword(userModel.password, user.password!);
            if (!IsCorrect)
                return StatusCode(401, new { message = AccountErrorMessage.PasswordIncorrect });

            var clientInfo = Parser.GetDefault().Parse(HttpContext.Request.Headers["User-Agent"].ToString());

            if ((bool)!user.is_2fa_enabled)
                return await FactLogin(clientInfo, user);

            int code = _generateCode.GenerateSixDigitCode();
            var emailDto = new EmailDto
            {
                username = user.username,
                email = user.email,
                subject = EmailMessage.Verify2FaHeader,
                message = EmailMessage.Verify2FaBody + code
            };

            await _emailSender.SendMessage(emailDto);

            HttpContext.Session.SetString(ID, user.id.ToString());
            HttpContext.Session.SetString(EMAIL, email);
            HttpContext.Session.SetString(USERNAME, user.username!);
            HttpContext.Session.SetString(ROLE, user.role!);
            HttpContext.Session.SetString(CODE, code.ToString());

            return StatusCode(200, new { message = AccountSuccessMessage.EmailSended });
        }
        catch (UserException)
        {
            _logger.LogCritical("When trying to update the data, the user was deleted");
            _tokenService.DeleteTokens();
            _logger.LogDebug("Tokens was deleted");
            return StatusCode(404);
        }
        catch (Exception)
        {
            return StatusCode(500);
        }
    }

Эндпоинт верификации:

    [HttpPost("verify/2fa")]
    public async Task<IActionResult> VerifyTwoFA([FromQuery] int code)
    {
        int correctCode = int.Parse(HttpContext.Session.GetString(CODE));
        int userId = int.Parse(HttpContext.Session.GetString(ID));
        string? email = HttpContext.Session.GetString(EMAIL);
        string? username = HttpContext.Session.GetString(USERNAME);
        string? role = HttpContext.Session.GetString(ROLE);

        if (email is null || username is null || role is null)
            return StatusCode(422, new { message = AccountErrorMessage.NullUserData });

        if (!code.Equals(correctCode))
            return StatusCode(422, new { message = AccountErrorMessage.CodeIncorrect });

        var clientInfo = Parser.GetDefault().Parse(HttpContext.Request.Headers["User-Agent"].ToString());
        var userModel = new UserModel
        {
            id = userId,
            username = username,
            email = email,
            role = role
        };

        HttpContext.Session.Clear();
        return await FactLogin(clientInfo, userModel);
    }

Да конечно же можно второй раз запрашивать данные из бд, но мне не хочется лишний раз нагружать бд


Ответы (1 шт):

Автор решения: Pavel Mayorov

Состояние сеанса ("сессия") хранится либо в памяти сервера (по умолчанию), либо в СУБД, либо в каком-нибудь redis. Изменить его клиент не может никак.

Однако, ссылка на это состояние (идентификатор сессии) хранится в куках, и может быть использована злоумышленником с помощью XSRF-атак (cross-site request forgery, подделки межсайтовых запросов). Поэтому защищайте любые мутирующие действия анти-XSRF токенами, и ни в коем случае не ставьте политику CORS в режим "разрешать всё и всем".

→ Ссылка