| Россия, г. Новочеркасск |
Безопасность
Создание страницы регистрации
Страница регистрации предоставляет пользователю интерфейс для ввода имени и пароля, принимает их и сравнивает с удостоверениями, хранящимися на сервере. Если удостоверения хранятся прямо в конфигурационном файле, их извлечение и проверка достаточно просты. Не намного сложнее извлекать удостоверения, хранящиеся в любом другом внешнем хранилище.
Страница регистрации должна включать в себя поля ввода для получения от пользователя данных удостоверения. Для проверки достоверности пользовательских данных необходимо использовать валидаторы, генерирующие нужный JavaScript -код на клиенте, а также выполняющие проверку на сервере.
-
Создайте новую страницу с именем MyLogin.aspx без отделенного кода -
Заполните страницу элементами управления и настройте их согласно таблице
Интерфейсная часть страницы MyLogin.aspx в режиме проектирования будет такой
Код страницы MyLogin.aspx будет таким
<%@ Page Language="C#" EnableViewState="false" %>
<script runat="server">
protected void LoginAction_Click(object sender, EventArgs e)
{
this.Validate();// Исполнить валидаторы на сервере
if (!this.IsValid)// Оценить флаг достоверности
return;// Отправить назад как есть
// Извлечь из web.config и сравнить с введенным
if (FormsAuthentication.Authenticate(UsernameText.Text, PasswordText.Text))
{
// Создать временный cookie-набор (второй параметр false),
// записать в него метку аутентификации и перенаправить
// на исходную запрошенную страницу или MyDefault.aspx
FormsAuthentication.RedirectFromLoginPage(UsernameText.Text, false);
}
else
{
HtmlGenericControl message = new HtmlGenericControl();
message.InnerHtml = "<h2 style='color: Red'>Неверное имя или пароль!</h2>";
form1.Controls.Add(message);
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div style="text-align: center">
<h2>
Введите свои имя и пароль</h2>
<asp:Panel ID="MainPanel" runat="server" BorderColor="Silver"
BorderStyle="Ridge"
BorderWidth="2px" Height="90px" Width="412px">
<table border="0" cellpadding="5" cellspacing="0" style="width: 100%">
<tr>
<td>
</td>
<td align="right" height="43" style="width: 167px">
Имя пользователя:</td>
<td>
<asp:TextBox ID="UsernameText" runat="server" />
</td>
<td>
<asp:RequiredFieldValidator ID="UsernameRequiredValidator"
runat="server" ControlToValidate="UsernameText"
Display="Dynamic"
ErrorMessage='Не заполнено поле "Имя пользователя"'
ToolTip="Пустое поле ввода">*
</asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="UsernameValidator"
runat="server" ControlToValidate="UsernameText"
Display="Dynamic" ErrorMessage="Неверное имя пользователя"
ToolTip="Допустимы буквы, цифры, пробелы и подчеркивания"
ValidationExpression="[а-яА-Я\w| ]*">*
</asp:RegularExpressionValidator>
</td>
</tr>
<tr>
<td>
</td>
<td align="right" height="43" style="width: 167px">
Пароль:</td>
<td>
<asp:TextBox ID="PasswordText" runat="server"
TextMode="Password" />
</td>
<td>
<asp:RequiredFieldValidator ID="PwdRequiredValidator"
runat="server" ControlToValidate="PasswordText"
Display="Dynamic" ErrorMessage='Не заполнено поле "Пароль"'
ToolTip="Пустое поле ввода">*
</asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="PwdValidator" runat="server"
ControlToValidate="PasswordText"
Display="Dynamic" ErrorMessage="Неверный пароль"
ToolTip="Используются недопустимые символы"
ValidationExpression='[а-яА-Я\w| !"$&/()=\-?\*]*'>*
</asp:RegularExpressionValidator>
</td>
</tr>
</table>
<asp:Button ID="Button1" runat="server" Text="Отправить"
OnClick="LoginAction_Click" />
</asp:Panel>
<asp:Label ID="lblResult" runat="server" />
</div>
<asp:ValidationSummary ID="ValidationSummary1" runat="server" />
</form>
</body>
</html>При такой инфраструктуре аутентификации любой пользователь, открывший сеанс с приложением, какую бы страницу он не запросил, будет направляться на страницу регистрации до тех пор, пока не введет свои данные, хранящиеся в удостоверении конфигурационного файла. После совпадения удостоверения будет создан cookie-набор аутентификации со скользящим временем жизни, в котором в зашифрованном виде будет записан мандат, и этот мандат будет действовать на протяжении всего сеанса или до истечения допустимого времени простоя сеанса.
Хеширование паролей в Web.config
В нашем файле Web.config до настоящего момента пароли хранились в виде открытого текста. В таком виде они легко уязвимы со стороны продвинутых пользователей, а также со стороны административного персонала сервера. Их было бы желательно защитить. На этот случай предусмотрена возможность хеширования, которая заключается в предварительной обработке исходного текста некоторой функцией, выход которой невозможно восстановить в обратную сторону.
В секции <credentials> имеется параметр passwordFormat. Он предназначен для указания ASP.NET, в каком формате хранятся значения паролей и какой алгоритм хеширования к ним применялся. Если пароли предварительно хешированы и сохранены в таком виде в конфигурационном файле, то ASP.NET при получении пароля от пользователя также его хеширует, прежде чем сравнить с храняшимся на сервере.
Параметр passwordFormat может принимать одно из трех следующих значений:
- Clear - пароль не хеширован и пользовательский пароль нужно сравнивать без предварительного хеширования
- MD5 - пароль хеширован алгоритмом MD5 и перед сравнением присланный пользовательзователем пароль хешировать тем же алгоритмом
- SHA1 - для хеширования применять алгоритм SHA1
Для предварительного хеширования паролей в Web.config применяется следующий метод
string hashedPwd = FormsAuthentication.HashPasswordForStoringInConfigFile(clearTextPassword, "MD5");
-
Добавьте к проекту страницу HashPasswordPage.aspx и наполните ее следующим кодом<%@ Page Language="C#" %> <script runat="server"> protected void btnHashedPwd_Click(object sender, EventArgs e) { // Загрузить содержимое корневого Web.config Configuration myConfig = System.Web.Configuration. WebConfigurationManager.OpenWebConfiguration("~/"); // Найти содержимое секции system.web ConfigurationSectionGroup systemWeb = myConfig.SectionGroups["system.web"]; // Найти содержимое секции authentication System.Web.Configuration.AuthenticationSection authSec = (System.Web.Configuration.AuthenticationSection) systemWeb.Sections["authentication"]; // Установить параметр passwordFormat, сообщающий, что было хеширование по MD5 authSec.Forms.Credentials.PasswordFormat = System.Web.Configuration.FormsAuthPasswordFormat.MD5; // Извлекаем из коллекции Users старые имена и пароли int count = authSec.Forms.Credentials.Users.Count; string[] name = new string[count]; string[] clearTextPwd = new string[count]; int i = 0; foreach (System.Web.Configuration.FormsAuthenticationUser user in authSec.Forms.Credentials.Users) { name[i] = user.Name; clearTextPwd[i] = user.Password; i++; } // Очищаем коллекцию Users authSec.Forms.Credentials.Users.Clear(); // Добавляем старые имена и новые хешированные пароли for (i = 0; i < count; i++) { // Хешируем исходный пароль string hashedPwd = FormsAuthentication.HashPasswordForStoringInConfigFile(clearTextPwd[i], "MD5"); // Добавляем в коллекцию Users authSec.Forms.Credentials.Users.Add( new System.Web.Configuration.FormsAuthenticationUser(name[i], hashedPwd)); } // Обновляем файл Web.config myConfig.Save(); // Отсылаем сообщение lblHashResult.Text = "Хеширование завершено.<br />" + "Повторно не выполнять - будет хеш на хеш!!!"; } </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div style="text-align: center"> <h1>Административная страница хеширования паролей в Web.config</h1> <p> <asp:Button ID="btnHashedPwd" runat="server" OnClick="btnHashedPwd_Click" Text="Хешировать" /></p> <p> <asp:Label ID="lblHashResult" runat="server"></asp:Label></p> </div> </form> </body> </html> -
Выполните страницу HashPasswordPage.aspx, но только один раз, чтобы повторно не хешировать уже хешированные пароли
В результате мы получим вариант конфигурационного файла с хешированными паролями
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" />
<authentication mode="Forms">
<forms
name="MyCookieName"
loginUrl="MyLogin.aspx"
defaultUrl="MyDefault.aspx"
protection="All"
timeout="20"
path="/"
requireSSL="false"
slidingExpiration="true"
cookieless="AutoDetect"
domain=""
enableCrossAppRedirects="false"
>
<credentials passwordFormat="MD5">
<user name="admin" password="FA03EB688AD8AA1DB593D33DABD89BAD" />
<user name="петя" password="B63974E3EE7B0920FE24DFB8E82FAE81" />
<user name="вася" password="44D4B2D42E830BE0DD43E6830D957C5D" />
<user name="user1" password="7C6A180B36896A0A8C02787EEAFB0E4C" />
<user name="user2" password="6CB75F652A9B52798EB6CF2201057C73" />
<user name="user3" password="819B0643D6B89DC9B579FDFC9094F28E" />
</credentials>
</forms>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>Исходные пароли, вводимые пользователями при регистрации, остались прежними. Но в конфигурационном файле они теперь храняться как хешированные по алгоритму MD5 и являются бесполезными для злоумышленников. Зама же система при аутентификации приводит исходные пароли перед сравнением к хешированному виду по тому же самому алгоритму. Если исходный и оригинальный пароли правильные, то их хеши будут совпадать.
