Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 37:

Безопасность: аутентификация с помощью форм

< Самостоятельная работа 36 || Самостоятельная работа 37: 12345678

Упражнение 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 запустите ее на выполнение

Вначале будет предложена страница регистрации, поскольку конфигурация сайта настроена именно так.

  • Введите в странице регистрации MyLogin.aspx учетную запись user1 и password1

Исходные пароли, вводимые пользователями при регистрации, остались прежними. Но в конфигурационном файле они теперь храняться как хешированные по алгоритму MD5 и являются бесполезными для злоумышленников. Сама же система при аутентификации приводит исходные пароли перед сравнением к хешированному виду по тому же самому алгоритму. Если исходный и оригинальный пароли правильные, то их хеши будут совпадать.

Здесь есть одно слабое звено: при регистрации учетная запись по нешифрованному каналу связи может быть перехвачена злоумышленником. В этом случае хранение удостоверений в хешированном виде становится бесполезным.

Естественно, что подобная страница хеширования паролей относится к системе администрирования и не должна быть доступна обычным пользователям. Ею может пользоваться только обслуживающий персонал сайта.

Упражнение 3. Закрепление за броузером постоянной аутентификации форм

До сих пор мы использовали временные cookie-наборы аутентификации для конкретного пользователя, которые действуют только на период сеанса и сразу удаляются броузером после его завершения. Это обеспечивает разумную безопасность. Но иногда может потребоваться закрепить аутентификацию не за пользователем, а за броузером. В этом случае при первой регистрации пользователя можно разрешить ему создать на броузере постоянный cookie-набор, по которому бы узнавался сам броузер.

Постоянные cookie-набор можно создать

  • в странице регистрации при первой посещении пользователя установкой второго параметра в значение true (вместо false) в методе

    FormsAuthentication.RedirectFromLoginPage( строка_имя , true);

  • в любом другом месте открытого сеанса выполнением метода

    FormsAuthentication.SetAuthCookie( строка_имя , true);

  • в любом другом месте открытого сеанса выполнением кода

    HttpCookie authCookie = FormsAuthentication.GetAuthCookie( строка_имя , true);

    this.Response.Cookies.Add(authCookie);

Установленный таким способом 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 нужно выполнитиь следующие шаги:

  1. Сконфигурировать аутентификацию форм в корневом каталоге приложения и авторизацию в защищенных каталогах
  2. Создать и настроить базу данных для хранения удостоверений пользователей
  3. Занести в хранилище пользователей
  4. Создать страницу регистрации
< Самостоятельная работа 36 || Самостоятельная работа 37: 12345678
Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000