Россия |
Безопасность
Создание страницы регистрации
Страница регистрации предоставляет пользователю интерфейс для ввода имени и пароля, принимает их и сравнивает с удостоверениями, хранящимися на сервере. Если удостоверения хранятся прямо в конфигурационном файле, их извлечение и проверка достаточно просты. Не намного сложнее извлекать удостоверения, хранящиеся в любом другом внешнем хранилище.
Страница регистрации должна включать в себя поля ввода для получения от пользователя данных удостоверения. Для проверки достоверности пользовательских данных необходимо использовать валидаторы, генерирующие нужный 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 и являются бесполезными для злоумышленников. Зама же система при аутентификации приводит исходные пароли перед сравнением к хешированному виду по тому же самому алгоритму. Если исходный и оригинальный пароли правильные, то их хеши будут совпадать.