问题描述
问题
在我们在项目之间重复使用的堆栈中,我们在会话中放入了过多的数据以在页面之间传递数据.这在理论上很好,因为它可以防止篡改、重放攻击等,但它带来的问题与解决的问题一样多.
In the stack that we re-use between projects, we are putting a little bit too much data in the session for passing data between pages. This was good in theory because it prevents tampering, replay attacks, and so on, but it creates as many problems as it solves.
会话丢失本身就是一个问题,尽管它主要是通过实现会话状态服务器(或使用 SQL Server)来处理的.更重要的是,让后退按钮正常工作是很棘手的,而且创建一个用户可以在三个选项卡中打开同一个屏幕来处理不同记录的情况也是额外的工作.
Session loss itself is an issue, although it's mostly handled by implementing Session State Server (or by using SQL Server). More importantly, it's tricky to make the back button work correctly, and it's also extra work to create a situation where a user can, say, open the same screen in three tabs to work on different records.
这只是冰山一角.
这些问题中的大多数都有解决方法,但随着我的努力,所有这些摩擦让我觉得使用会话在页面之间传递数据是错误的方向.
There are workarounds for most of these issues, but as I grind away, all this friction gives me the feeling that passing data between pages using session is the wrong direction.
在这里我真正想做的是提出一个最佳实践,我的商店可以一直使用它在页面之间传递数据,然后,对于新应用程序,替换当前依赖 Session 的堆栈的关键部分.
What I really want to do here is come up with a best practice that my shop can use all the time for passing data between pages, and then, for new apps, replace key parts of our stack that currently rely on Session.
如果最终解决方案不会导致大量样板管道代码,那也很好.
It would also be nice if the final solution did not result in mountains of boilerplate plumbing code.
建议的解决方案
会话
如上所述,严重依赖会话 似乎是个好主意,但它会破坏后退按钮并导致一些其他问题.
As mentioned above, leaning heavily on Session seems like a good idea, but it breaks the back button and causes some other problems.
可能有办法解决所有问题,但这似乎需要做很多额外的工作.
There may be ways to get around all the problems, but it seems like a lot of extra work.
使用 session 的一个好处是篡改不是问题.与通过未加密的 QueryString 传递所有内容相比,您最终编写的保护代码要少得多.
One thing that's very nice about using session is the fact that tampering is just not an issue. Compared to passing everything via the unencrypted QueryString, you end up writing much less guard code.
跨页发布
事实上,我几乎没有考虑过这个选项.我有一个问题,它使页面的耦合程度如何——如果我开始执行 PreviousPage.FindControl("SomeTextBox"),如果我想从另一个可能没有的页面访问此页面,这似乎是一个维护问题一个名为 SomeTextBox 的控件.
In truth I've barely considered this option. I have a problem with how tightly coupled it makes the pages -- if I start doing PreviousPage.FindControl("SomeTextBox"), that seems like a maintenance problem if I ever want to get to this page from another page that maybe does not have a control called SomeTextBox.
它似乎在其他方面也受到限制.例如,我可能想通过链接访问该页面.
It seems limited in other ways as well. Maybe I want to get to the page via a link, for instance.
查询字符串
我目前倾向于这种策略,就像过去一样.但我可能希望我的 QueryString 被加密以使其更难以篡改,我也想处理重放攻击的问题.
I'm currently leaning towards this strategy, like in the olden days. But I probably want my QueryString to be encrypted to make it harder to tamper with, and I would like to handle the problem of replay attacks as well.
Rolla 的 4 个人,有一篇关于此的文章.
On 4 guys from Rolla, there's an article about this.
但是,应该可以创建一个 HttpModule 来处理所有这些并从页面中删除所有加密香肠制作.果然,Mads Kristensen 发表了一篇文章.但是,评论使它听起来像是在极其常见的场景中存在问题.
However, it should be possible to create an HttpModule that takes care of all this and removes all the encryption sausage-making from the page. Sure enough, Mads Kristensen has an article where he released one. However, the comments make it sound like it has problems with extremely common scenarios.
其他选项
当然,这不是对选项的详尽介绍,而是我正在考虑的主要选项.此链接包含更完整的列表.我没有提到的那些,例如 Cookies 和 Cache 不适合在页面之间传递数据.
Of course this is not an exaustive look at the options, but rather the main options I'm considering. This link contains a more complete list. The ones I didn't mention such as Cookies and the Cache not appropriate for the purpose of passing data between pages.
结束...
那么,您如何处理页面之间传递数据的问题?您必须解决哪些隐藏的问题,是否有任何预先存在的工具可以完美地解决所有问题?你觉得你有一个完全满意的解决方案吗?
So, how are you handling the problem of passing data between pages? What hidden gotchas did you have to work around, and are there any pre-existing tools around this that solve them all flawlessly? Do you feel like you've got a solution that you're completely happy with?
提前致谢!
更新: 以防万一我不够清楚,通过在页面之间传递数据"我正在谈论,例如,将 CustomerID 键从 CustomerSearch.aspx 页面传递到客户.aspx,客户将在其中打开并可以进行编辑.
Update: Just in case I'm not being clear enough, by 'passing data between pages' I'm talking about, for instance, passing a CustomerID key from a CustomerSearch.aspx page to Customers.aspx, where the Customer will be opened and editing can occur.
推荐答案
几个月后,我想我会用我最终采用的技术更新这个问题,因为它效果很好.
Several months later, I thought I would update this question with the technique I ended up going with, since it has worked out so well.
在玩过更复杂的会话状态处理(导致很多后退按钮损坏等)之后,我最终滚动了自己的代码来处理加密的 QueryStrings.这是一个巨大的胜利——我的所有问题场景(后退按钮、同时打开多个选项卡、丢失会话状态等)都得到了解决,并且由于使用非常熟悉,因此复杂性最小.
After playing with more involved session state handling (which resulted in a lot of broken back buttons and so on) I ended up rolling my own code to handle encrypted QueryStrings. It's been a huge win -- all of my problem scenarios (back button, multiple tabs open at the same time, lost session state, etc) are solved and the complexity is minimal since the usage is very familiar.
这仍然不是万能的灵丹妙药,但我认为它适用于您遇到的大约 90% 的情况.
This is still not a magic bullet for everything but I think it's good for about 90% of the scenarios you run into.
详情
我构建了一个名为 CorePage 的类,它继承自 Page.它有名为 SecureRequest 和 SecureRedirect 的方法.
I built a class called CorePage that inherits from Page. It has methods called SecureRequest and SecureRedirect.
所以你可以调用:
SecureRedirect(String.Format("Orders.aspx?ClientID={0}&OrderID={1}, ClientID, OrderID)
CorePage 解析出 QueryString 并将其加密为名为 CoreSecure 的 QueryString 变量.所以实际的请求是这样的:
CorePage parses out the QueryString and encrypts it into a QueryString variable called CoreSecure. So the actual request looks like this:
Orders.aspx?CoreSecure=1IHXaPzUCYrdmWPkkkuThees%2fIs4l6grKaznFGAeDDI%3d
Orders.aspx?CoreSecure=1IHXaPzUCYrdmWPkkkuThEes%2fIs4l6grKaznFGAeDDI%3d
如果可用,当前登录的用户 ID 将添加到加密密钥中,因此重放攻击不是什么大问题.
If available, the currently logged in UserID is added to the encryption key, so replay attacks are not as much of a problem.
从那里,您可以调用:
X = SecureRequest("ClientID")
结论
一切都使用熟悉的语法无缝运行.
Everything works seamlessly, using familiar syntax.
在过去几个月中,我还修改了此代码以处理边缘情况,例如触发下载的超链接 - 有时您需要在具有安全 QueryString 的客户端上生成超链接.效果非常好.
Over the last several months I've also adapted this code to work with edge cases, such as hyperlinks that trigger a download - sometimes you need to generate a hyperlink on the client that has a secure QueryString. That works really well.
如果你想看这个代码,请告诉我,我会把它放在某个地方.
Let me know if you would like to see this code and I will put it up somewhere.
最后一个想法:接受我自己对其他人在这里发表的一些非常周到的帖子的回答很奇怪,但这似乎确实是我问题的最终答案.感谢所有帮助我到达那里的人.
One last thought: it's weird to accept my own answer over some of the very thoughtful posts other people put on here, but this really does seem to be the ultimate answer to my problem. Thanks to everyone who helped get me there.
这篇关于在页面之间传递数据的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!