Безопасно ли хранить имя пользователя / пароль в состоянии сеанса для одноразовой регистрации? - PullRequest
2 голосов
/ 06 июня 2011

Мы создаем веб-приложение ASP.NET MVC3 для клиента.

В этом приложении клиент хотел бы, чтобы пользователь входил в систему, используя свою комбинацию имени пользователя и пароля.Однако, если пароль userName указан верно, одноразовый пин-код должен быть отправлен на мобильный телефон пользователя.Пользователь должен проходить аутентификацию только после того, как он введет правильный одноразовый пин-код (OTP).

Поэтому мне интересно, является ли безопасным следующее решение:

  1. Пользователь входит в системус его именем пользователя и паролем.Мы используем Membership.ValidateUser для проверки имени пользователя / пароля, но мы еще не установили Auth Cookie.
  2. Мы храним имя пользователя и пароль пользователя в сеансе.
  3. Мы храним тот факт, чтопользователь «наполовину» вошел в систему в сеансе.
  4. Мы перенаправляем обратно на страницу входа.
  5. Теперь пользователь получает возможность войти в OTP и во второй раз отправляет серверу.
  6. Мы проверяем комбинацию имени пользователя / пароля / OTP.
  7. Если она действительна, мы устанавливаем Cookie для проверки подлинности с помощью форм.

PS: все это произойдет в SSL.

Гипотетическая страница входа в систему может выглядеть следующим образом (обратите внимание на три состояния):

<h2>Log On</h2>
<div>
    @if (User.Identity.IsAuthenticated)
    {
        <p class="green bold">
            You are logged-on fully. Your UserName and Password match, and the OTP you have entered was correct.
        </p>
        <form action="/Account/LogOff">
            <input type="submit" value="Log Off" />
        </form>
    }
    else if (ViewBag.AwaitingOTP)
    {
        <p>
            Hi @ViewBag.UserName
        </p>
        <p class="orange">
            Step 2/2: Please enter the OTP sent to your cell phone.
        </p>
        <form method="post" action="/Account/VerifyOTPAndLogOn">
            <input name="otp" type="text" placeholder="One-Time Pin" />
            <input type="submit" />
        </form>
    }
    else
    {
        <p>
            Hi stranger!
        </p>
        <p class="orange">
            Step 1/2: Please enter your username and password.
        </p>
        <form method="post" action="/Account/LogOnHalfwayAndRequestOTP">
            <input name="userName" type="text" placeholder="userName" />
            <input name="password" type="password" placeholder="password" />
            <input type="submit" value="Log On" />
        </form>
    }

</div>

Код контроллера выглядит следующим образом:

public class AccountController : ControllerBase
{

    public bool HalfwayLoggedOnStillAwaitingOTP
    {
        get
        {
            if (Session["AwaitingOTP"] != null)
                return (bool)Session["AwaitingOTP"];

            return false;
        }
        set
        {
            Session["AwaitingOTP"] = value;
        }
    }


    public ActionResult LogOn()
    {
        ViewBag.AwaitingOTP = HalfwayLoggedOnStillAwaitingOTP;
        ViewBag.UserName = Session["UserName"] ?? null;

        return View();
    }


    public ActionResult LogOnHalfwayAndRequestOTP(string userName, string password)
    {
        //Authenticate user, but not fully... (i.e. we're not setting FormsAuthentication.SetAuthCookie yet)
        if (Membership.ValidateUser(userName, password))
            HalfwayLoggedOnStillAwaitingOTP = true;
        else
            HalfwayLoggedOnStillAwaitingOTP = false;

        ViewBag.AwaitingOTP = HalfwayLoggedOnStillAwaitingOTP;
        ViewBag.UserName = Session["UserName"] ?? null;

        //...
        //...Call service that sends OTP to the user's cellPhone.
        //...

        return View("LogOn");
    }


    public ActionResult VerifyOTPAndLogOn(string otp)
    {
        string userName = (string) Session["UserName"];
        string password = (string) Session["Password"];
        if (OTPIsValid(otp, userName, password))
        {
            //Set the Forms Auth cookie...
            FormsAuthentication.SetAuthCookie(userName, false);

            return RedirectToAction("Index", "Home");
        }
        else
        {
            //Display a nice error message here.
            return View();
        }


    }

    private bool OTPIsValid(string otp, string userName, string password)
    {
        //...
        //...Validate OTP here. For now we assume the user entered the correct OTP. 
        //...
        return true;
    }
}

Есть ли какие-либодыры в безопасности в этой реализации?Я не уверен, насколько безопасно хранить имя пользователя / пароль в сеансе или безопасно ли верить, что пользователь действительно аутентифицирован, когда установлено значение Session ["AwaitingOTP"].

1 Ответ

1 голос
/ 07 июня 2011

Я отвечу на свой вопрос информацией, которую я собрал за последние 24 часа. Надеюсь, это правильно.

Что меня беспокоило в предлагаемом решении, так это короткий период времени, когда мы полагаемся исключительно на состояние сеанса, чтобы сохранить факт аутентификации пользователя. (потому что только после ввода OTP мы используем правильную проверку подлинности с помощью форм).

Ключ сеанса ASP.NET хранится в файле cookie. Он зашифрован, поэтому является относительно безопасным. Но он все еще уязвим к тем же угрозам, что и стандартные формы проверки подлинности:

  • XSS
  • Атаки "Человек посередине" (SSL защитит от этого)
  • Кража печенья

Я бы изменил предлагаемое решение, чтобы не хранить пароль пользователя в сеансе (и хранить только его имя пользователя). И я бы удостоверился, что используется SSL.

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