Рекомендации по передаче данных между страницами

Проблема

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

Потеря сеанса сама по себе является проблемой, хотя в основном она обрабатывается приложением Session State Server (или с использованием SQL Server). Что еще более важно, сложно сделать обратную кнопку работать правильно, а также сделать дополнительную работу, чтобы создать ситуацию, когда пользователь может, скажем, открыть один и тот же экран на трех вкладках, чтобы работать с разными записями.

И это только верхушка айсберга.

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

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

Было бы неплохо, если бы окончательное решение не привело к горам кода сантехники.

Предлагаемые решения

Session

Как уже упоминалось выше, тяжелая атака на сессию кажется хорошей идеей, но она прерывает кнопку "Назад" и вызывает некоторые другие проблемы.

Там могут быть способы обойти все проблемы, но это кажется большим количеством дополнительной работы.

Одна вещь, очень приятная в использовании сеанса, заключается в том, что подделка - это просто не проблема. По сравнению с передачей всего через незашифрованный QueryString, вы в конечном итоге пишете гораздо меньше защитного кода.

Отправка перекрестных страниц

По правде говоря, я почти не рассматривал этот вариант. У меня возникла проблема с тем, насколько сильно он связан с страницами - если я начинаю делать Prep.FindControl( "SomeTextBox" ), это похоже на проблему обслуживания, если я когда-либо захочу перейти на эту страницу с другой страницы, которая, возможно, не имеет элемент управления SomeTextBox.

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

QueryString

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

На 4 парня из Rolla, есть статья об этом.

Тем не менее, должно быть возможно создать HttpModule, который позаботится обо всем этом, и удалит все шифрование сосисок со страницы. Разумеется, У Мэдс Кристенсена есть статья, в которой он выпустил один. Однако комментарии звучат так, будто у него проблемы с чрезвычайно распространенными сценариями.

Другие параметры

Конечно, это не exaustive взгляд на варианты, а скорее основные варианты, которые я рассматриваю. Эта ссылка содержит более полный список. Те, которые я не упомянул, такие как Cookies и Cache, не подходят для передачи данных между страницами.

В закрытии...

Итак, как вы справляетесь с проблемой передачи данных между страницами? Какие скрытые искатели вам приходилось работать, и есть ли какие-либо ранее существовавшие инструменты вокруг этого, которые решают их все безупречно? Считаете ли вы, что у вас есть решение, которым вы полностью довольны?

Спасибо заранее!

Обновление: На всякий случай, когда я не достаточно ясен, "передавая данные между страницами", о которых я говорю, например, передавая ключ CustomerID с страницы CustomerSearch.aspx, чтобы Client.aspx, где Клиент будет открыт и может быть изменен.

Ответ 1

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

После игры с более сложной обработкой состояния сеанса (что привело к большому количеству сломанных кнопок и т.д.), я закончил свой собственный код для обработки зашифрованных QueryStrings. Это была огромная победа - все мои проблемные сценарии (кнопка "Назад", открытые несколько вкладок одновременно, потерянное состояние сеанса и т.д.) Решены, а сложность минимальна, поскольку использование очень хорошо известно.

Это все еще не волшебная пуля для всего, но я думаю, что это хорошо для примерно 90% сценариев, с которыми вы столкнулись.

Подробнее

Я построил класс под названием CorePage, который наследуется от страницы. Он имеет методы под названием SecureRequest и SecureRedirect.

Итак, вы можете позвонить:

 SecureRedirect(String.Format("Orders.aspx?ClientID={0}&OrderID={1}, ClientID, OrderID)

CorePage анализирует QueryString и шифрует его в переменную QueryString под названием CoreSecure. Таким образом, фактический запрос выглядит так:

Orders.aspx? CoreSecure = 1IHXaPzUCYrdmWPkkkuThEes% 2fIs4l6grKaznFGAeDDI% 3d

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

Оттуда вы можете позвонить:

X = SecureRequest("ClientID")

Заключение

Все работает без проблем, используя привычный синтаксис.

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

Сообщите мне, хотите ли вы увидеть этот код, и я поставлю его где-нибудь.

Одна последняя мысль: странно принимать мой собственный ответ на некоторые из очень вдумчивых сообщений, которые другие люди здесь прикладывают, но это действительно кажется окончательным ответом на мою проблему. Спасибо всем, кто помог мне туда добраться.

Ответ 2

Во-первых, проблемы, с которыми вы имеете дело, связаны с управлением состоянием в среде без учета состояния. Борьба, с которой вы сталкиваетесь, не нова, и это, вероятно, одна из вещей, которая делает веб-разработку сложнее, чем разработка Windows или разработка исполняемого файла.

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

  • Строка запроса - строки запроса хороши для передачи указателей на данные (например, значения первичного ключа) или значений состояния. Строки запроса сами по себе не должны считаться безопасными, даже если они зашифрованы из-за повтора. Кроме того, некоторые браузеры имеют ограничение на длину URL-адреса. Тем не менее, строки запросов имеют некоторые преимущества, такие как то, что они могут быть помечены в закладки и отправлены по электронной почте людям и по сути являются лицами без гражданства, если они не используются ни с чем другим.

  • Cookies - Cookies хороши для хранения очень небольшого количества информации для конкретного пользователя. Проблема в том, что файлы cookie также имеют ограничение по размеру, после чего он просто усекает данные, поэтому вам нужно быть осторожным с помещением пользовательских данных в файл cookie. Кроме того, пользователи могут убивать файлы cookie или останавливать их использование (хотя это также предотвратит использование стандартного сеанса). Подобно строкам запросов, файлы cookie лучше, IMO, для указателей на данные, чем для самих данных, если данные не являются крошечными.

  • Данные формы. Данные формы могут принимать довольно много информации, но за счет затрат времени и в некоторых случаях перезагрузки. ASP.NET ViewState использует скрытые переменные формы для хранения информации. Передача данных между страницами с использованием чего-то вроде ViewState имеет то преимущество, что лучше работает с кнопкой "назад", но может легко создавать ginormous страницы, которые замедляют работу для пользователя. В общем, модель ASP.NET не работает при перекрестном размещении (хотя это возможно), но вместо этого работает с сообщениями на одной странице и оттуда переходит на следующую страницу.

  • Сессия - сеанс хорош для информации, относящейся к процессу, с которым выполняется пользователь, или для общих настроек. Вы можете хранить довольно много информации в сеансе за счет объема памяти сервера или времени загрузки из баз данных. Концептуально сеанс работает, одновременно загружая всю информацию о пакете для пользователя либо из памяти, либо из государственного сервера. Это означает, что если у вас очень большой набор данных, вы, вероятно, не хотите вводить его в сеанс. Сессия может создать некоторые проблемы с кнопками на задней панели, которые должны быть сопоставлены с тем, что на самом деле пытается выполнить пользователь. В общем, вы обнаружите, что кнопка "Назад" может быть бичем веб-разработчика.

  • База данных. Последнее решение (которое снова может использоваться в сочетании с другими) заключается в том, что вы храните информацию в базе данных в соответствующей схеме со столбцом, который указывает состояние элемента. Например, если вы обрабатывали создание заказа, вы могли сохранить заказ в таблице Order с столбцом "state", который определяет, был ли он реальным или нет. Вы сохранили бы идентификатор заказа в строке запроса или сеансе. Веб-сайт будет продолжать записывать данные в таблицу для обновления различных частей и дочерних элементов до тех пор, пока пользователь не сможет объявить, что они выполнены, и состояние заказа отмечено как реальный заказ. Это может усложнить отчеты и запросы тем, что все они должны различать "реальные" элементы от тех, которые находятся в процессе.

Одним из элементов, упомянутых в вашей последней ссылке, был Application Cache. Я бы не счел это специфичным для пользователя, поскольку он является широко используемым приложением. (Очевидно, что он может быть обучен обувью, но он не рекомендовал бы этого). Я никогда не играл с хранением данных в HttpContext за пределами передачи его обработчику или модулю, но я бы скептически относился к тому, что он отличался от вышеупомянутых решений.

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

Ответ 3

Хорошо, поэтому я хочу предисловие к моему ответу; У Томаса явно есть самый точный и исчерпывающий ответ, который до сих пор остается для людей, начинающих свежими. Этот ответ не в том же духе. Мой ответ исходит с точки зрения "бизнес-разработчика". Как мы все знаем слишком хорошо; иногда просто невозможно провести деньги, переписывая что-то, что уже существует и "работает"... по крайней мере, не все одним выстрелом. Иногда лучше всего реализовать решение, которое позволит вам перейти к лучшей альтернативе с течением времени.

Единственное, что я сказал бы, что Томас не хватает; клиентское javascript состояние. Где я работаю, мы обнаружили, что клиенты все больше ожидают применения приложений типа "Web 2.0". Мы также обнаружили, что подобные приложения обычно приводят к гораздо более высокой удовлетворенности пользователей. С небольшой практикой и поддержкой некоторых действительно замечательных библиотек javascript, таких как jQuery (мы даже начали использовать GWT и обнаружили, что это AWESOME), общение с JST-сервисами REST, реализованное в WCF, может быть тривиальным. Этот подход также обеспечивает очень хороший способ начать переход к архитектуре на основе SOA и чистое разделение пользовательского интерфейса и бизнес-логики.

Но я отвлекся.

Мне кажется, что у вас уже есть приложение, и вы уже расширили границы встроенного управления сеансом ASP.NET. Итак... здесь мое предложение (предполагая, что вы уже пробовали управление сеансом ASP.NET вне процесса, которое масштабируется значительно лучше, чем управление сеансом in-process/on-box, и похоже, что у вас есть, потому что вы упомянули Это); NCache.

NCache предоставляет вам "drop-in" замену для параметров управления сеансом ASP.NET. Он очень прост в реализации и может "помочь вам", чтобы ваше приложение было более чем достаточно, чтобы вы могли пройти, без каких-либо существенных инвестиций в рефакторинг вашей существующей кодовой базы сразу.

Вы можете использовать дополнительное время и деньги, чтобы начать сокращать свой технический долг, фокусируя новую разработку на вещах, имеющих непосредственную ценность для бизнеса, - используя новый подход (например, любые альтернативы, предлагаемые в других ответах или мои).

Просто мои мысли.

Ответ 4

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

С небольшой работой вы можете поддерживать вспомогательные сеансы и разрешать многозадачность в разных вкладках/окнах.

Ответ 5

Пройдя все приведенные выше сценарии и ответы и эту ссылку Методы определения данных Мой последний совет:

COOKIES для:

  • ENCRYPT [userId's]
  • ENCRYPT [productId]
  • ENCRYPT [xyzIds..]
  • ENCRYPT [и т.д..]

БАЗА ДАННЫХ для:

  • наборы данных по идентификатору COOKIE
  • datatables BY COOKIE ID
  • все другие большие куски BY COOKIE ID

Моя консультация также зависит от ниже статистики и этой ссылки. Методы определения данных:

enter image description here

Ответ 6

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

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

В переписании я сделал идентификатор сотрудника и запрос идентификаторов доступным через базовый URL-адрес "ViewEmployee.aspx? Id = XXX" и "ViewRequest.aspx? Id = XXX". Приложение было настроено на A) отфильтровать неверные идентификаторы и B) аутентифицировать и авторизировать пользователя, прежде чем разрешать им эти страницы. То, что это позволило пользователям в первую очередь сделать это, - это отправить простые электронные письма аудиторам с URL-адресом в электронном письме. Когда они были в большой спешке, они находились в процессе массового обработки, они смогли просто щелкнуть список URL-адресов и выполнить соответствующую обработку.

Другие связанные с сеансом данные, такие как даты модификации и поддержание "состояния" взаимодействия пользователя с приложением, становятся немного более сложными, но, надеюсь, это обеспечивает отправку для вас.