Мы создаем веб-приложение ASP.NET MVC3 для клиента.
В этом приложении клиент хотел бы, чтобы пользователь входил в систему, используя свою комбинацию имени пользователя и пароля.Однако, если пароль userName указан верно, одноразовый пин-код должен быть отправлен на мобильный телефон пользователя.Пользователь должен проходить аутентификацию только после того, как он введет правильный одноразовый пин-код (OTP).
Поэтому мне интересно, является ли безопасным следующее решение:
- Пользователь входит в системус его именем пользователя и паролем.Мы используем Membership.ValidateUser для проверки имени пользователя / пароля, но мы еще не установили Auth Cookie.
- Мы храним имя пользователя и пароль пользователя в сеансе.
- Мы храним тот факт, чтопользователь «наполовину» вошел в систему в сеансе.
- Мы перенаправляем обратно на страницу входа.
- Теперь пользователь получает возможность войти в OTP и во второй раз отправляет серверу.
- Мы проверяем комбинацию имени пользователя / пароля / OTP.
- Если она действительна, мы устанавливаем 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"].