| Украина, Киев |
Безопасность: аутентификация с помощью форм
Упражнение 2. Хеширование паролей в конфигурационном файле
В нашем файле Web.config до настоящего момента пароли хранились в виде открытого текста. В таком виде они легко уязвимы со стороны продвинутых пользователей, а также со стороны административного персонала сервера. Их было бы желательно защитить. На этот случай предусмотрена возможность хеширования, которая заключается в предварительной обработке исходного текста некоторой функцией, выход которой невозможно восстановить в обратную сторону.
В секции <credentials> имеется параметр passwordFormat. Он предназначен для указания ASP.NET, в каком формате хранятся значения паролей и какой алгоритм хеширования к ним применялся. Если пароли предварительно хешированы и сохранены в таком виде в конфигурационном файле, то ASP.NET при получении пароля от пользователя также его хеширует, прежде чем сравнить с храняшимся на сервере.
Параметр passwordFormat может принимать одно из трех следующих значений:
- Clear - пароль не хеширован и пользовательский пароль нужно сравнивать без предварительного хеширования
- MD5 - пароль хеширован алгоритмом MD5 и перед сравнением присланный пользовательзователем пароль хешировать тем же алгоритмом
- SHA1 - для хеширования применять алгоритм SHA1
Для предварительного хеширования паролей в Web.config применяется метод FormsAuthentication.HashPasswordForStoringInConfigFile().
-
Добавьте
к проекту страницу HashPasswordPage.aspx с
встроенным скриптом и наполните ее следующим кодом
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Web.Configuration" %>
<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
AuthenticationSection authSec =
(AuthenticationSection)
systemWeb.Sections["authentication"];
// Установить параметр passwordFormat, сообщающий, что было хеширование по MD5
authSec.Forms.Credentials.PasswordFormat = FormsAuthPasswordFormat.MD5;
// Извлекаем из коллекции Users старые имена и пароли
int count = authSec.Forms.Credentials.Users.Count;
string[] name = new string[count];
string[] clearTextPwd = new string[count];
int i = 0;
foreach (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 FormsAuthenticationUser(name[i], hashedPwd));
}
// Обновляем файл Web.config
myConfig.Save();
// Отсылаем сообщение
lblHashResult.Text = "Хеширование завершено.<br />"
+ "Повторно не выполнять - будет хеш на хеш!!!";
}
</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">
<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>
Листинг
37.10.
Код страницы HashPasswordPage.aspx хеширования паролей в Web.config
-
Выполните
страницу 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>
Листинг
37.11.
Файл Web.config после выполнения процедуры хеширования паролей
-
Откройте
в редакторе оболочки страницу Default.aspx
и командой File/View in Browser запустите
ее на выполнение
Вначале будет предложена страница регистрации, поскольку конфигурация сайта настроена именно так.
Исходные пароли, вводимые пользователями при регистрации, остались прежними. Но в конфигурационном файле они теперь храняться как хешированные по алгоритму MD5 и являются бесполезными для злоумышленников. Сама же система при аутентификации приводит исходные пароли перед сравнением к хешированному виду по тому же самому алгоритму. Если исходный и оригинальный пароли правильные, то их хеши будут совпадать.
Здесь есть одно слабое звено: при регистрации учетная запись по нешифрованному каналу связи может быть перехвачена злоумышленником. В этом случае хранение удостоверений в хешированном виде становится бесполезным.
Естественно, что подобная страница хеширования паролей относится к системе администрирования и не должна быть доступна обычным пользователям. Ею может пользоваться только обслуживающий персонал сайта.
Упражнение 3. Закрепление за броузером постоянной аутентификации форм
До сих пор мы использовали временные cookie-наборы аутентификации для конкретного пользователя, которые действуют только на период сеанса и сразу удаляются броузером после его завершения. Это обеспечивает разумную безопасность. Но иногда может потребоваться закрепить аутентификацию не за пользователем, а за броузером. В этом случае при первой регистрации пользователя можно разрешить ему создать на броузере постоянный cookie-набор, по которому бы узнавался сам броузер.
Постоянные cookie-набор можно создать
- в странице регистрации при первой посещении
пользователя установкой второго параметра в значение
true (вместо false) в методе
FormsAuthentication.RedirectFromLoginPage( строка_имя , true);
- в любом другом месте открытого сеанса выполнением метода
FormsAuthentication.SetAuthCookie( строка_имя , true);
- в любом другом месте открытого сеанса выполнением кода
HttpCookie authCookie = FormsAuthentication.GetAuthCookie( строка_имя , true);
Установленный таким способом cookie-набор будет существовать на компьютере пользователя "вечно", если только мы не удалим его методом
FormsAuthentication.SignOut();
Можно также изменить временной статус постоянного cookie-набора на любой странице. Покажем это
-
Добавьте
к проекту страницу ModifyPersistentCookieAuth.aspx без файла отделенного
кода и заполните ее так
<%@ Page Language="C#" EnableViewState="false" %>
<script runat="server">
Label message;
protected void Page_Load(object sender, EventArgs e)
{
// Дескриптор центрирования
HtmlGenericControl center = new HtmlGenericControl("center");
form1.Controls.Add(center);
// Текстовая метка с заголовком
Label label = new Label();
center.Controls.Add(label);
label.Text = "<h2>Закрепить аутентификацию за броузером</h2>";
// Кнопки
Button createPersistentCookie = new Button();
center.Controls.Add(createPersistentCookie);
createPersistentCookie.Text = "Создать бессрочный AuthCookie";
createPersistentCookie.Click += new EventHandler(createPersistentCookie_Click);
center.Controls.Add(new HtmlGenericControl("br"));
Button createTemporaryCookie = new Button();
center.Controls.Add(createTemporaryCookie);
createTemporaryCookie.Text = "Создать срочный AuthCookie";
createTemporaryCookie.Click += new EventHandler(createTemporaryCookie_Click);
center.Controls.Add(new HtmlGenericControl("br"));
Button deleteCookie = new Button();
center.Controls.Add(deleteCookie);
deleteCookie.Text = "Удалить AuthCookie";
deleteCookie.Click += new EventHandler(deleteCookie_Click);
center.Controls.Add(new HtmlGenericControl("br"));
// Текстовая метка с сообщением
message = new Label();
center.Controls.Add(message);
message.Text = String.Empty;
}
void createPersistentCookie_Click(object sender, EventArgs e)
{
// Создать бессрочный cookie
HttpCookie authCookie = FormsAuthentication.GetAuthCookie("xx", true);
// Отослать на броузер
this.Response.Cookies.Add(authCookie);
// Сообщить пользователю
message.Text = "Бессрочный AuthCookie создан!";
}
void createTemporaryCookie_Click(object sender, EventArgs e)
{
// Создать вначале бессрочный cookie
HttpCookie authCookie = FormsAuthentication.GetAuthCookie("xx", true);
// Настроить его как временный сроком на 10 дней
authCookie.Expires = DateTime.Now.AddDays(10);
// Отослать на броузер
this.Response.Cookies.Add(authCookie);
// Сообщить пользователю
message.Text = "Срочный AuthCookie создан!";
}
void deleteCookie_Click(object sender, EventArgs e)
{
// Удалить cookie-набор регистрации
FormsAuthentication.SignOut();
// Сообщить пользователю
message.Text = "AuthCookie удален!";
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
</form>
</body>
</html>
Листинг
37.12.
Страница создания на броузере постоянного cookie-набора аутентификации
Интерфейс страницы в режиме выполнения будет таким
При закреплении cookie-набора за броузером при соединении с сайтом страница регистрации пользователю предъявляться не будет, пока не закончится срок действия (если cookie-набор срочный).
API Membership является готовым механизмом в ASP.NET, предназначенным для организации управления аутентификацией пользователей. Он базируется на аутентификации форм. Единственное отличие, что хранение пользователей будет осуществляться не в конфигурационном файле, а в базе данных. И для управления задействуются классы Membership.
Чаще всего к корневому каталогу сайта допускаются все анонимные пользователи без регистрации, а защищенные ресурсы, требующие аутентификацию, размещаются в подкаталогах со своими файлами Web.config. Если кто-то запрашивает защищенный ресурс из подкаталога, система автоматически перенаправляет пользователя на страницу регистрации.
Для использования API Membership нужно выполнитиь следующие шаги:
