在页面之间传递数据的最佳实践

问题

在项目之间重复使用的堆栈中,我们在会话中传递了一些数据,以便在页面之间传递数据。 这在理论上是好的,因为它防止篡改,重放攻击等等,但是它创造了许多问题。

会话丢失本身是一个问题,虽然它主要通过实现会话状态服务器(或通过使用SQL Server)来处理。 更重要的是,让后退button正常工作是非常棘手的,而且还需要额外的工作来创build一个用户可以在三个选项卡中打开同一屏幕以处理不同logging的情况。

而这只是冰山一angular。

对于这些问题,大部分都有解决方法,但是随着我的磨砺,所有这些摩擦都让我觉得,使用会话在页面之间传递数据是错误的方向。

我真正想要做的是提出一个最佳实践,我的商店可以随时使用页面之间的数据传递,然后,对于新的应用程序,replace目前依赖于Session的堆栈的关键部分。

如果最终的解决scheme不会导致大量的样板代码,这也是很好的。

build议的解决scheme

会议

如上所述,倚重Session就好像是一个好主意,但是它打破了后退button,导致了一些其他的问题。

可能有办法解决所有的问题,但似乎有很多额外的工作。

有一件事使用会话是非常好的事实,篡改是不是一个问题。 与通过未encryption的QueryString传递所有内容相比,最终编写的守护代码要less得多。

跨页面发布

事实上,我几乎没有考虑这个选项。 我有一个问题,它是如何紧密耦合,使页面 – 如果我开始做PreviousPage.FindControl(“SomeTextBox”),这似乎是一个维护问题,如果我想要从另一个页面,可能没有这个页面一个名为SomeTextBox的控件。

在其他方面似乎也受到限制。 也许我想通过链接进入页面,例如。

请求参数

我现在正在倾向于这个策略,就像在古代那样。 但是我可能希望我的QueryString被encryption以使其难以被篡改,并且我也想要处理重放攻击的问题。

来自罗拉的4个人, 有一篇关于这个的文章 。

但是,应该可以创build一个HttpModule来处理所有这些操作,并从页面中删除所有的encryption香肠。 果然, Mads Kristensen有一篇文章发表了一篇文章。 然而,这些评论听起来像是在极其常见的情况下有问题。

其他选项

当然,这并不是对选项的看法,而是我正在考虑的主要选项。 此链接包含更完整的列表。 那些我没有提到的如Cookies和Cache不适合在页面之间传递数据的目的。

正在closures…

那么,你如何处理页面之间传递数据的问题呢? 你有什么隐藏的陷阱需要解决,是否有任何预先存在的工具可以完美地解决它们? 你觉得你有一个解决scheme,你完全满意吗?

提前致谢!

更新:为了防止我不够清楚,通过“在页面之间传递数据”我正在谈论,例如,从CustomerSearch.aspx页面传递CustomerID键到Customers.aspx,客户将被打开并可以进行编辑。

首先,你正在处理的问题涉及处理无状态环境中的状态。 你所遇到的困难并不是什么新鲜事,它可能是使网站开发比windows开发或可执行程序开发更难的事情之一。

就Web开发而言,就我所知,您有五种select来处理用户特定的状态,这些状态都可以相互结合使用。 你会发现,没有一个解决scheme的一切工作。 相反,您需要确定何时使用每个解决scheme:

  • 查询string – 查询string适合传递指向数据的指针(例如主键值)或状态值。 查询string本身不应被认为是安全的,即使由于重放而被encryption。 另外,有些浏览器对url的长度有限制。 然而,查询string有一些优点,例如可以通过书签和电子邮件发送给人,如果不与其他任何东西一起使用,它们本身就是无状态的。

  • cookies – cookies适合存储特定用户的微量信息。 问题是,cookies也有一个大小限制之后,它将简单地截断数据,所以你必须小心把自定义数据放入cookie中。 另外,用户可以杀掉cookie或者停止使用cookie(尽pipe这也会阻止使用标准的Session)。 与查询string类似,除非数据很小,否则cookie对于指向数据的指针比IMO更好。

  • 表单数据 – 表单数据可能需要相当多的信息,但是需要花费时间和在某些情况下重新加载时间。 ASP.NET的ViewState使用隐藏的表单variables来维护信息。 在使用ViewState之类的页面之间传递数据具有使用后退button更好的优势,但可以轻松地创build大小不一的页面,从而减慢用户的体验。 一般来说,ASP.NET模型在跨页面发布时不起作用(尽pipe这是可能的),而是在post回到同一页面并从那里导航到下一页面。

  • 会话 – 会话适用于与用户正在进行的进程或常规设置有关的信息。 您可以将相当多的信息存储在会话中,这是以服务器内存或数据库加载时间为代价的。 从概念上讲,Session通过从内存或状态服务器一次加载用户的全部数据来工作。 这意味着如果你有一个非常大的数据集,你可能不想把它放到会话中。 会话可以创build一些后退button问题,必须权衡用户实际要完成的事情。 一般来说,你会发现后退button可能是Web开发人员的祸根。

  • 数据库 – 最后一个解决scheme(也可以与其他解决scheme一起使用)是将数据库中的信息以适当的模式存储在一个指示项目状态的列中。 例如,如果您正在处理订单的创build,则可以将订单存储在订单表中,其中包含“状态”列,以确定订单是否是真实订单。 您可以将订单标识符存储在查询string或会话中。 网站将继续向表中写入数据以更新各个部分和子项目,直到最终用户能够声明它们完成,并且订单的状态被标记为真实订单。 这可能会使报告和查询复杂化,因为它们都需要将“真实”的项目与正在进行的项目区分开来。

您稍后链接中提到的其中一个项目是应用程序caching。 我不认为这是用户特定的,因为它是应用程序范围。 (它显然可以被视为是用户特定的,但我不会推荐)。 我从来没有把HttpContext中的数据传递给处理程序或模块,但是我会怀疑它与上面提到的解决scheme有什么不同。

一般来说,没有一个解决scheme来统治他们。 最好的方法是在每一页上假设用户可以从任何地方导航到该页面(而不是假定他们通过使用另一个页面上的链接到达那里)。 如果你这样做,后退button问题变得更容易处理(虽然还是一个痛苦)。 在我的发展过程中,我会广泛地使用前四种,有时候会在需要的时候诉诸最后的解决scheme。

好的,所以我想用这个来解释我的答案。 对于刚开始的人来说,托马斯显然有最准确和最全面的答案。 这个答案根本不是一回事。 我的答案来自“业务开发者”的立场。 众所周知, 有时花钱重写已经存在和“有效”的东西是不切实际的,至less不是一回事。 有时候最好是实施一个解决scheme,让你随着时间的推移而转移到一个更好的select。

我唯一能说托马斯缺less的是 客户端的JavaScript状态。 在我工作的地方,我们发现客户越来越期待“Web 2.0”types的应用程序。 我们也发现这些应用通常会带来更高的用户满意度。 通过一些练习,以及jQuery等一些非常棒的JavaScript库的帮助(我们甚至开始使用GWT,发现它非常棒),与WCF中实现的基于JSON的REST服务进行通信可能是微不足道的。 这种方法还提供了一个非常好的方法,开始朝着基于SOA的体系结构迈进,并清晰地分离UI和业务逻辑。

但是我离题了。

这听起来好像你已经有了一个应用程序,并且已经扩展了ASP.NET内置会话状态pipe理的限制。 所以…这里是我的build议(假设你已经尝试了ASP.NET的进程外会话pipe理,它比在进程/在线会话pipe理显着增加,听起来就像你有,因为你提到它); NCACHE。

NCache为您提供了ASP.NET的会话pipe理选项的“插入式”替代品。 这是非常容易实现的,并且可以“帮助”你的应用程序,而不是足够让你通过 – 没有任何重大的投资来立即重构你现有的代码库。

您可以利用额外的时间和金钱,通过使用新方法(例如其他答案中提供的任何替代方法或我的方法),将新的开发重点放在具有直接商业价值的事物上,从而开始减less技术债务。

只是我的想法。

几个月之后,我想我会用我最后一次使用的技术来更新这个问题,因为它的结果非常好。

在玩更多涉及会话状态处理(导致大量的折​​返button等)后,我结束了自己的代码来处理encryption的QueryStrings。 这是一个巨大的胜利 – 我所有的问题场景(后退button,同时打开多个选项卡,丢失会话状态等)都得到了解决,复杂度最低,因为使用非常熟悉。

这对于所有的事情来说仍然不是什么神奇的东西,但是我认为对于大约90%的情况来说,这是有好处的。

细节

我build立了一个名为CorePage的类,它inheritance自Page。 它具有称为SecureRequest和SecureRedirect的方法。

所以你可以打电话:

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

CorePageparsing出QueryString并将其encryption成一个名为CoreSecure的QueryStringvariables。 所以实际的请求看起来像这样:

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

如果可用,则将当前login的用户ID添加到encryption密钥中,因此重放攻击不是那么严重的问题。

从那里,你可以打电话给:

 X = SecureRequest("ClientID") 

结论

一切都可以无缝运行,使用熟悉的语法。

在过去的几个月中,我也调整了这些代码,以处理边缘情况,例如触发下载的超链接 – 有时您需要在具有安全的QueryString的客户端上生成超链接。 这真的很好。

让我知道,如果你想看到这个代码,我会把它放在某个地方。

最后一个想法:接受我自己的答案,而不是其他人在这里提出的一些非常深思熟虑的post,但这确实确实似乎是我的问题的最终答案。 感谢所有帮助过我的人。

我永远不会这样做。 我从来没有任何问题存储数据库中的所有会话数据,加载它基于用户的cookie。 就任何事情而言,这是一个会议,但我保持对此的控制。 不要放弃您的会话数据控制到您的Web服务器…

通过一些工作,您可以支持子会话,并允许在不同的选项卡/窗口中进行多任务处理。

经历了所有上述情况和答案和这个链接数据pasing方法我最后的build议是:

COOKIES用于:

  • ENCRYPT [用户标识的]
  • ENCRYPT的[ProductID]
  • ENCRYPT [xyzIds ..
  • ENCRYPT [等等。]

DATABASE for:

  • 数据集BY COOKIE ID
  • 数据表BY COOKIE ID
  • 所有其他大块BY COOKIE ID

我的build议还取决于下面的统计数据和这个链接的详细信息数据pasing方法 :

在这里输入图像说明

作为一个起点,我发现使用关键数据元素(如Customer ID)最好放入查询string中进行处理。 您可以轻松地追踪/过滤这些元素中的不良数据,还可以与电子邮件或其他相关站点/应用程序进行集成。

在以前的应用程序中,查看员工或涉及他们的请求logging的唯一方法是login到应用程序,search员工或search最近的logging以查找有问题的logging。 当有关部门的人员为了审计目的而需要对logging进行简单的观察时,这就变得有问题,并且时间大大缩短。

在重写中,我做了员工ID,并通过基本URL“ViewEmployee.aspx?Id = XXX”和“ViewRequest.aspx?Id = XXX”来请求Ids。 该应用程序被设置为A)过滤掉坏ID和B)在允许用户访问这些页面之前对用户进行authentication和授权。 主要应用程序用户所做的事情是通过电子邮件中的URL将简单的电子邮件发送给审计人员。 当他们非常匆忙的时候,他们处于大量的处理时间,他们只需点击一个URL列表,然后做适当的处理。

其他与会话有关的数据,例如修改date和维护用户与应用程序交互的“状态”会稍微复杂一些,但希望这可以为您提供一个启动点。