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

Bri*_*Kay 64 asp.net encryption webforms query-string

问题

在我们在项目之间重用的堆栈中,我们在会话中放置了一些过多的数据,用于在页面之间传递数据.这在理论上是好的,因为它可以防止篡改,重放攻击等,但它会产生尽可能多的问题.

会话丢失本身是一个问题,尽管它主要通过实现会话状态服务器(或使用SQL Server)来处理.更重要的是,使后退按钮正常工作非常棘手,而且创建一种情况也是额外的工作,用户可以在三个选项卡中打开相同的屏幕来处理不同的记录.

这只是冰山一角.

大多数这些问题都有解决方法,但是当我磨砺掉时,所有这些摩擦让我觉得使用session在页面之间传递数据是错误的方向.

我真正想要做的是提出一个最佳实践,我的商店可以一直使用它来在页面之间传递数据,然后,对于新的应用程序,替换当前依赖于Session的堆栈的关键部分.

如果最终解决方案不会导致大量的样板管道代码,那也很好.

提出的解决方案

会议

如上所述,严重依赖Session 似乎是一个好主意,但它会打破后退按钮并导致其他一些问题.

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

使用会话非常好的一件事是篡改不是问题.与通过未加密的QueryString传递所有内容相比,您最终编写的守护代码更少.

跨页发布

事实上,我几乎没有考虑过这个选择.我有一个问题,它如何使页面紧密耦合 - 如果我开始做PreviousPage.FindControl("SomeTextBox"),这似乎是一个维护问题,如果我想从另一个页面可能没有到达此页面一个名为SomeTextBox的控件.

它似乎也受到其他方面的限制.也许我想通过链接访问该页面.

请求参数

我现在正倾向于这种策略,就像在过去那样.但我可能希望我的QueryString被加密以使其更难以篡改,我也想处理重放攻击的问题.

来自Rolla的4个人,有一篇关于此的文章.

但是,应该可以创建一个HttpModule来处理所有这些并从页面中删除所有加密香肠.果然,Mads Kristensen有一篇文章,他发布了一篇文章.但是,这些评论听起来似乎有极其常见的情况.

其他选择

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

在结束...

那么,您如何处理页面之间传递数据的问题?你需要解决什么隐藏的陷阱,是否有任何预先存在的工具可以完美地解决它们?难道你觉得你已经得到了你和完全满意的解决方案?

提前致谢!

更新:以防万一我不够清楚,通过'在页面间传递数据'我正在谈论,例如,将CustomerID密钥从CustomerSearch.aspx页面传递给Customers.aspx,客户将在那里打开并且可以进行编辑.

Tho*_*mas 41

首先,您处理的问题涉及在无状态环境中处理状态.您所遇到的困难并不是新的,这可能是使Web开发比Windows开发或可执行文件开发更难的事情之一.

关于Web开发,据我所知,您有五种选择来处理特定于用户的状态,这些状态可以相互结合使用.你会发现没有一个解决方案适用于所有事情.相反,您需要确定何时使用每个解决方案:

  • 查询字符串 - 查询字符串适用于将指针传递给数据(例如主键值)或状态值.即使由于重放而加密,也不应假定查询字符串本身是安全的.此外,某些浏览器对网址的长度有限制.但是,查询字符串具有一些优点,例如可以将它们加入书签并通过电子邮件发送给人们,如果不与其他任何内容一起使用,则本质上是无状态的.

  • Cookie - Cookie适用于为特定用户存储非常少量的信息.问题是cookie也有一个大小限制,之后它会简单地截断数据,因此你必须小心将自定义数据放入cookie中.此外,用户可以杀死cookie或停止使用cookie(尽管这也会阻止使用标准Session).与查询字符串类似,对于指向数据的指针而言,cookie比数据本身更好,除非数据很小.

  • 表单数据 - 表单数据可能需要相当多的信息,但是会花费在发布时间和某些情况下的重新加载时间.ASP.NET的ViewState使用隐藏的表单变量来维护信息.使用ViewState之类的页面之间传递数据的优点是可以使用后退按钮更好地工作,但可以轻松创建巨大的页面,从而减慢用户的体验.一般情况下,ASP.NET模型不适用于跨页面发布(虽然它是可能的),而是在帖子上工作回到同一页面并从那里导航到下一页.

  • 会话 - 会话适用于与用户正在进行的流程或一般设置相关的信息.您可以以服务器内存或数据库加载时间为代价将相当多的信息存储到会话中.从概念上讲,Session通过从内存或从状态服务器一次性加载用户的整个数据来工作.这意味着,如果您拥有非常大的数据集,则可能不希望将其置于会话中.会话可以创建一些后退按钮问题,这些问题必须与用户实际尝试完成的内容进行权衡.通常,您会发现后退按钮可能是Web开发人员的祸根.

  • 数据库 - 最后一个解决方案(同样可以与其他解决方案结合使用)是您将信息存储在数据库中的适当模式中,并使用指示项目状态的列.例如,如果您正在处理订单的创建,则可以将订单存储在订单表中,并使用"状态"列确定订单是否为真实订单.您可以将订单标识符存储在查询字符串或会话中.该网站将继续将数据写入表中以更新各个部分和子项,直到最终用户能够声明它们已完成并且订单的状态被标记为真实订单.这会使报告和查询复杂化,因为它们都需要区分"真实"项目和正在处理的项目.

后一个链接中提到的项目之一是Application Cache.我不认为这是用户特定的,因为它是应用程序范围的.(它显然可能是用户特定的,但我也不建议这样做).除了将数据传递给处理程序或模块之外,我从来没有在HttpContext中存储数据,但我怀疑它与上面提到的解决方案有什么不同.

一般来说,没有一种解决方案可以统治它们.最好的方法是在每个页面上假设用户可以从任何地方导航到该页面(而不是假设他们通过使用另一页面上的链接到达那里).如果你这样做,后退按钮问题变得更容易处理(尽管仍然很痛苦).在我的开发中,我广泛使用前四个,偶尔在需要时使用最后的解决方案.


Ste*_*eve 9

好的,所以我想用这个作为序言的前言; 对于刚刚开始新人的人来说,托马斯显然拥有最准确,最全面的答案.这个答案根本不是一脉相承的.我的答案来自"业务开发人员"的立场.众所周知; 有时花钱重新写一些已经存在并且"有效"的东西是不可行的......至少不是一次性完成.有时最好实施一个解决方案,让您随着时间的推移迁移到更好的替代方案.

我唯一想说托马斯遗失的是; 客户端javascript状态.在我工作的地方,我们发现客户越来越期望"Web 2.0"类型的应用程序.我们还发现这些类型的应用程序通常会带来更高的用户满意度.通过一些练习,以及一些非常棒的javascript库(如jQuery(我们甚至开始使用GWT并发现它很棒)的帮助,与WCF中实现的基于JSON的REST服务进行通信可能是微不足道的.这种方法还提供了一种非常好的方式来开始转向基于SOA的体系结构,并清理UI和业务逻辑的分离.

但我离题了.

听起来好像你已经有了一个应用程序,并且你已经扩展了ASP.NET内置会话状态管理的限制.所以......这是我的建议(假设您已经尝试过ASP.NET的进程外会话管理,它比进程内/机上会话管理更好地扩展,听起来就像你提到的那样,因为你提到过它); NCACHE.

NCache为ASP.NET的会话管理选项提供了"插入式"替换.它实现起来非常简单,并且可以"帮助"您的应用程序,而不仅仅是让您完成 - 无需立即重构现有代码库.

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

只是我的想法.


Bri*_*Kay 8

几个月之后,我想我会用最后的技术来更新这个问题,因为它已经很好了.

在玩更多涉及的会话状态处理(导致大量折断按钮等)后,我最终滚动自己的代码来处理加密的QueryStrings.这是一个巨大的胜利 - 我的所有问题场景(后退按钮,同时打开多个选项卡,丢失会话状态等)都得到了解决,并且复杂性很小,因为使用非常熟悉.

对于所有事情来说,这仍然不是一个神奇的子弹,但我认为这对你遇到的大约90%的场景都有好处.

细节

我构建了一个名为CorePage的类,它继承自Page.它有一些名为SecureRequest和SecureRedirect的方法.

所以你可以打电话:

 SecureRedirect(String.Format("Orders.aspx?ClientID={0}&OrderID={1}, ClientID, OrderID)
Run Code Online (Sandbox Code Playgroud)

CorePage解析出QueryString并将其加密为名为CoreSecure的QueryString变量.所以实际的请求看起来像这样:

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

如果可用,则将当前登录的UserID添加到加密密钥中,因此重放攻击不是一个问题.

从那里,您可以致电:

X = SecureRequest("ClientID")
Run Code Online (Sandbox Code Playgroud)

结论

使用熟悉的语法,一切都可以无缝地工作.

在过去几个月中,我还调整了此代码以处理边缘情况,例如触发下载的超链接 - 有时您需要在具有安全QueryString的客户端上生成超链接.这非常有效.

如果你想看到这段代码,请告诉我,我会把它放在某个地方.

最后一个想法:接受我自己对其他人在这里发表的一些非常有思想的帖子的答案很奇怪,但这似乎确实是我问题的最终答案.感谢所有帮助我的人.

  • 就像注释加密本身并没有真正解决在QueryString中传递ID的安全性方面一样,它只是让它更难用它们来调节.在安全的应用程序中,您倾向于在会话中使用某种身份,例如用户名.然后,如果您有一个页面Orders.aspx?OrderId = 1,在较低层(服务/业务)中,您始终可以输入验证逻辑,以确保此ID检索的订单实际上属于登录的用户到申请. (2认同)
  • 请你把它发布在github上吗?你可以解决另一个人的问题...... (2认同)

saj*_*aha 5

在完成上述所有场景和答案之后,这个链接数据pasing方法我的最终建议是:

COOKIES:

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

数据库:

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

我的建议还取决于以下统计数据和此链接详细信息数据方法:

在此输入图像描述