Россия |
Управление состоянием ASP.NET
Упражнение 4
-
Добавьте к проекту новую страницу (без файла отделенного кода) с именем DisplayViewState.aspx и установите ее стартовой
-
Удалите из интерфейсной части страницы дескриптор <div></div>
-
Включите трассировку, добавив в директиву @ Page страницы параметр Trace=true
-
Добавьте в блок скриптов кодовую часть, чтобы окончательно страница стала такой
<%@ Page Language="C#" Trace="true" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { // Объекты создаем каждый раз заново Label label = new Label(); this.form1.Controls.Add(label); this.form1.Controls.Add(new HtmlGenericControl("br")); Button button = new Button(); this.form1.Controls.Add(button); if (!this.IsPostBack) { // Один раз настроили, а дальше работает состояние вида label.Text = "Привет всем!!!"; button.Text = "Отправить"; } } protected void Page_PreRender(object sender, EventArgs e) { // Вывод на страницу строки состояния if (this.IsPostBack) { // Извлекаем строку состояния string strViewState = this.Request.Form["__VIEWSTATE"]; // Добавляем вывод к родительской форме Label label = new Label(); this.form1.Controls.Add(label); label.Text = "<p><b>Строка состояния как есть:</b><br />" + strViewState + "</p>"; label.EnableViewState = false;// Чтобы не влияла на результат // Преобразуем строку из Base64 в массив ASCII-символов byte[] ascii = Convert.FromBase64String(strViewState); // Вставляем в отклик Response.Write("<b>Строка состояния в формате ASCII:</b><br />"); Response.BinaryWrite(ascii); // То же самое, только по турецки... // Десериализация и отображение строки //string decodedViewState = System.Text.Encoding.ASCII.GetString(ascii); //Response.Write(decodedViewState); } } </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>
-
Запустите страницу DisplayViewState.aspx и повыполните обратную отсылку
HTML-отклик на стороне клиента, сгенерированный страницей DisplayViewState.aspx при обратной отсылке, будет выглядеть примерно так
Мы видим, что некоторая информация, сохраняемая на клиенте в строке состояния вида, может быть частично расшифрована. Злоумышленник может изменить ее нужным для себя образом и попытаться отправить на сервер.
Поскольку состояние вида формирует только серверная сторона, то перед включением строки в скрытое поле HTML-вывода ASP.NET вычисляет контрольную сумму и прячет ее в ту же самую строку. При получении этой хэшированной строки от клиента система десериализует ее, вновь вычисляет контрольную сумму и сравнивает с ранее спрятанной. Несовпадение легко обнаружить. Подсчет контрольной суммы включается в директиве @ Page параметром EnableViewStateMac="true".
Для большей защиты строки состояния вида можно использовать встроенное шифрование, которое включается на странице параметром ViewStateEncryptionMode="Always" директивы @ Page или установкой в конфигурационном файле секции
<pages viewStateEncryptionMode="Always">
-
Включите шифрование и выполните страницу DisplayViewState.aspx. Сгенерированный отклик на обратную отсылку станет примерно таким
Теперь строка состояния стала зашифрованной и ее трудно расшифровать. Однако не рекомендуется без надобности шифровать данные состояния вида. Это негативно скажется на производительности, поскольку сервер должен будет выполнять операцию шифрования и дешифрования при каждой отсылке и получении данных.
Скрытые поля
Во вкладке Standard панели Toolbox имеется элемент управления HiddenField, который генерирует скрытое поле c единственной переменной, определяемой его свойством Value. Этот элемент не поддерживает шифрование, хэширование и хранение по частям. Поэтому клиенты в исходном коде HTML-вывода могут просматривать эти данные. Данные в скрытом поле хранятся до тех пор, пока пользователь не перейдет к другой странице.
Упражнение 5
-
Добавьте к проекту новую страницу с именем HiddenFieldTest.aspx без файла отделенного кода и назначьте ее стартовой
-
Переведите страницу в режим Design и двойным щелчком создайте в кодовой части обработчик Page_Load()
-
Поместите на Web-форму из вкладки Standard панели Toolbox два элемента управления HiddenField и присвойте им имена beginTime и countRequest
-
Отключите для всех элементов страницы механизм сохранения состояния вида, добавив в директиву @ Page параметр EnableViewState="false"
-
Заполните страницу следующим кодом
<%@ Page Language="C#" EnableViewState="false" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { // Создаем текстовую метку lblTime = new Label(); div1.Controls.Add(lblTime); div1.Controls.Add(new HtmlGenericControl("br")); // Создаем кнопку CurrentTime Button button = new Button(); div1.Controls.Add(button); // Подписываемся на событие кнопки button.Click += CurrentTimeClick; button.Text = "Текущее время"; // Добавляем промежуток между кнопками Literal literal = new Literal(); literal.Text = " "; div1.Controls.Add(literal); // Создаем кнопку OldTime button = new Button(); div1.Controls.Add(button); // Подписываемся на событие кнопки button.Click += OldTimeClick; button.Text = "Начальное время"; // Инициализируем скрытые поля и метку при первом запросе if (!this.IsPostBack) { beginTime.Value = System.DateTime.Now.ToLongTimeString(); OldTimeClick(null, EventArgs.Empty); } else { // Ведение счетчика запросов страницы int.TryParse(countRequest.Value, out count); count++; // Или то же самое // count = int.Parse(countRequest.Value) + 1; } countRequest.Value = count.ToString(); } // Вынесены в поля класса для видимости в обработчиках int count = 0; Label lblTime; void CurrentTimeClick(object sender, EventArgs e) { lblTime.Text = "Текущее время: " + System.DateTime.Now.ToLongTimeString(); lblTime.Text += "<br />Ответ № " + count.ToString(); } void OldTimeClick(object sender, EventArgs e) { lblTime.Text = "Начальное время: " + beginTime.Value; lblTime.Text += "<br />Ответ № " + count.ToString(); } </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" id="div1" runat="server"> <h1 style="color: Red"> Испытание элемента HiddenField </h1> <asp:HiddenField ID="beginTime" runat="server" /> <asp:HiddenField ID="countRequest" runat="server" /> </div> </form> </body> </html>
-
Исполните страницу и убедитесь, что скрытые поля, генерируемые элементом HiddenField, в пределах одной страницы работают исправно