ASP. NET Основная пользовательская настройка входа в систему - PullRequest
1 голос
/ 01 августа 2020

У меня есть ситуация, когда мы используем ASP. NET Core Identity Framework для системы Intr anet с подключениями к старой базе данных CRM (эту базу данных нельзя изменить без колоссальных усилий!).

Однако у нас есть клиенты, входящие в отдельный DBContext с использованием структуры идентификации, с идентификатором для обратной ссылки на CRM. Он находится в отдельном веб-приложении с общими проектами между ними.

Это громоздко и вызывает проблемы, когда клиенты объединяются в CRM или добавляются дополнительные люди в учетную запись et c. Кроме того, нам не нужно использовать роли или какие-либо дополнительные функции для входа в систему клиента.

Итак, я подумал сохранить имя пользователя и пароль в CRM с помощью следующего процесса:

  1. Сгенерируйте случайный случайный пароль.
  2. Используйте ID внутренней базы данных в качестве соли.
  3. Сохраните Sha256 ha sh «соль + пароль» в поле пароля.

Когда клиент входит в систему, мы:

  1. Проверяем Sha256 ha sh на соответствие соли и заданному паролю
  2. В случае успеха сохраняем сеансового кулинара ie с учетом того, что клиент вошел в систему: _session.SetString("LoggedIn", "true");
  3. Каждый запрос к моей учетной записи будет использовать ServiceFilter для проверки сеанса Cook ie. Если не найдено, перенаправьте на экран входа в систему.

Вопросы:

  1. Достаточно ли это безопасно?
  2. Должны ли мы генерировать случайная соль? Если он хранится в таблице клиентов, чем он будет отличаться от внутреннего (20 символов) идентификатора клиента?
  3. Есть ли способ подделки ie сеанса сервера? Должны ли мы хранить ha sh в сеансе, который мы также проверяем для каждого действия?

Ответы [ 2 ]

3 голосов
/ 04 августа 2020
  1. Достаточно ли это безопасно?

Как правило, собственная безопасность - плохая идея, потому что она не будет подвергаться такой тщательной проверке в качестве отраслевого стандарта, например Identity Framework. Если ваше приложение не предназначено для жизни или смерти, может быть, этого достаточно.

Должны ли мы генерировать случайную соль?

Да, соли всегда должны быть случайными. Одна из причин заключается в том, что когда пользователь меняет свой пароль обратно на предыдущий пароль, если соль тоже постоянна, вы снова получите тот же ha sh, который может быть обнаружен. Другая причина в том, что мы не хотим, чтобы соли были предсказуемыми или последовательными. Это упростило бы хакерам создание радужных таблиц.

Если бы он сохранялся в таблице клиентов, как бы он отличался от внутреннего (20-значного) идентификатора клиента?

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

Есть ли способ подделать файл Cook сеанса сервера ie?

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

Должны ли мы хранить ha sh в сеансе, который мы также проверяем при каждом действии?

Не думаю, что это поможет. Ваше значение _session.SetString("LoggedIn", "true") уже хранится на сервере и полностью недоступно для клиента. У клиента есть доступ только к куку сеанса ie, который является случайным идентификатором. Если это значение сеанса LoggedIn истинно, то ha sh не сделает его дополнительным истинным.

2 голосов
/ 11 августа 2020

В прошлом году я сделал собственный магазин IUserPasswordStore для клиента. В этом решении задействован Microsoft.AspNetCore.Identity.UserManager, который обрабатывает хеширование паролей за кулисами, никакой специальной обработки паролей не требуется. Вы будете нести ответственность за хранение хешированного пароля в базе данных вместе с другими свойствами пользователя.

Я не могу опубликовать sh код целиком, это не моя собственность, но я могу набросать основные части.

Во-первых, нам нужен IdentityUser:

public class AppIdentityUser : IdentityUser<int>
{
    public string Name { get; set; }
}

Затем реализация if IUserPasswordStore

public class UserPasswordStore : IUserPasswordStore<AppIdentityUser>
{
    private readonly IUserRepo _userRepo; // your custom user repository
    private readonly IdentityErrorDescriber _identityErrorDescriber;

    public UserPasswordStore(IUserRepo userRepo, IdentityErrorDescriber identityErrorDescriber)
    {
        _userRepo = userRepo;
        _identityErrorDescriber = identityErrorDescriber;
    }

    public Task<IdentityResult> CreateAsync(AppIdentityUser user, CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();
        if (user == null)
        {
            throw new ArgumentNullException(nameof(user));
        }

        // if email exists, fail
        if (_userRepo.GetByEmailAddress(user.Email) != null)
        {
            return Task.FromResult(IdentityResult.Failed(_identityErrorDescriber.DuplicateEmail(user.Email)));
        }

        // ... convert AppIdentityUser to model class
        // 
        _userRepo.Save(userModel);
        return Task.FromResult(IdentityResult.Success);
    }

    ... implementation of the rest of IUserPasswordStore<AppIdentityUser> comes here
}

Вставьте это в код для CRUD-операций пользователя, например, контроллер управления пользователями :

UserManager<AppIdentityUser>

Пример кода для смены пароля (извините за вложение)

        var result = await _userManager.RemovePasswordAsync(identityUser);
        if (result.Succeeded)
        {
            result = await _userManager.AddPasswordAsync(identityUser, model.Password);
            if (result.Succeeded)
            {
                var updateResult = await _userManager.UpdateAsync(identityUser);
                if (updateResult.Succeeded)
                {
                   ... do something
                }
            }
        }

Вставьте это в LoginController:

SignInManager<AppIdentityUser>

Нам также нужна реализация

IRoleStore<IdentityRole>. 

Если авторизация не требуется, оставьте все методы пустыми.

В Startup # ConfigureServices:

services.AddIdentity<AppIdentityUser, IdentityRole>().AddDefaultTokenProviders();
services.AddTransient<IUserStore<AppIdentityUser>, UserPasswordStore>();
services.AddTransient<IRoleStore<IdentityRole>, RoleStore>();
services.Configure<CookiePolicyOptions>(options => ...
services.Configure<IdentityOptions>(options => ...
services.ConfigureApplicationCookie(options => ...

В Startup # Configure:

app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();

См. Также https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity-custom-storage-providers?view=aspnetcore-3.1

...