Page.IsPostBack的安全实现?

5

根据我的先前的问题,关于ASP.net默认的Page.IsPostBack实现是否安全(不安全;它可以被伪造...甚至HTTP谓词不一定是POST!),我在想;肯定有更好的方法来实现它吧?我们能否想出一个Page.IsPostBack实现方式,使其为真时几乎保证指示页是一个实际的ASP.net回发?这对于只想做一次安全检查(例如基于用户角色确定某些内容是否会出现),并且只想在我们处理非ASP.net回发时才这样做非常重要。

我首先想到的如何实现这个功能的想法是在属性中实现检查代码,这样我就可以在Page_Load中写类似于这样的东西:

if (!_isPostBack)
{
    // Do security check
    if (userIsNotAuthorized)
    {
        btnViewReports.Visible = false;
        btnEditDetails.Visible = false;
        // etc.
    }
}

有没有一种安全的方式来实现_isPostBack?也许在ViewState中存储某些东西,这将很难或不可能被篡改以模拟PostBack?一个随机字符串?


3
你在谈论安全的“几乎可以保证”,这是没有意义的。一个东西要么是安全的,要么不是。 "几乎" 就等同于不安全。 - jalf
1
我的意思是在RSA加密“几乎安全”的背景下,“几乎保证”;理论上它可以被暴力破解,或者你可以“幸运地”猜到某人的密钥,但这是极不可能或困难的。 - Jez
你绝对不能相信客户端传来的任何东西。重新调整你的逻辑,使用Session对象即可。 - H H
1
@Henk 当然你不能相信来自客户端的东西;这就是这个问题的重点。我们能否想出一种机制,使我们知道这是一个先前加载页面的客户端的POST请求,因此必须将其发送回来?当然,显而易见的方法是在客户端首次加载页面时提供一些信息,它必须在后续的postback中提供给我们。 - Jez
+1,@Henk。是的,你必须非常明确地阐明你的安全目标。 - Jason Kleban
3个回答

2

几年前,我参与了一个项目,在该项目中我们对代码进行了一些渗透测试。测试人员指出默认情况下IsPostback没有检查http动词。为了解决这个问题,我创建了一个抽象的页面类,并实现了自己的IsPostback方法来替换默认实现:

Public Class ProjectPage : System.Web.UI.Page

    public new bool IsPostBack()
    {
        return (Page.IsPostBack && Request.HttpMethod.ToUpper() == "POST");
    }

End Class

这样可以让你在http动词上进行测试,但你也可以轻松扩展该方法以进行其他检查。

1

好的,这是我认为的解决方案:只要启用了事件验证,Page.IsPostBack已经足够安全。如果我有任何错误,请在下面解释一下,我很乐意听取任何人的评论。

为了将虚假的回发投稿到ASP.net并触发控件的OnClick事件,需要启用事件验证,并且客户端必须发送__EVENTVALIDATION表单字段。该字段包含一个唯一生成的字符串,基本上告诉ASP.net哪些控件可能产生了该页面的回发事件。如果您尝试欺骗按钮的回发,而该按钮已经设置了.Visibility = false,则会出现事件验证错误消息。因此,看起来您无法直接欺骗隐藏控件的单击。

关于欺骗页面上现有按钮的postback(即您已被呈现的按钮,即您有权限查看/单击的按钮),怎么样? 好吧,您可以将postback发送到页面,但是您需要提交有效的__VIEWSTATE,否则您只会收到“状态信息无效”的错误。为了拥有有效的__VIEWSTATE,您已经需要将页面作为非postback加载,对吧?这意味着安全检查代码至少会执行一次,隐藏适当的控件并记录在__VIEWSTATE中。因此,当您发布欺骗性的postback时,是的,它将导致Page.IsPostBack为true,但无所谓,因为已经生成了已提交的__VIEWSTATE 在前面的非postback页面加载中,以隐藏您无权访问的内容...因此,您可以欺骗postback,但仅通过传递先前由非postback页面加载生成的__VIEWSTATE

所以,基于这些事实,只在Page.IsPostBack == false块中放置安全检查代码应该是安全的。在有效的回发提交到ASP.net服务器之前,这必须始终运行一次。或者我有什么遗漏吗?

0

对于您的需求,Cookie 是一种更好的机制。Cookie 是一个令牌,只能由服务器生成,并为令牌持有者提供某些声明,例如最近签入和具有某些权限和/或首选项。其中一些功能已内置于 FormsAuthentication 中。您可以实现自己的 Cookie 机制,但是应研究安全的 Cookie 协议,因为存在几个不明显的安全考虑。

好处是您无需在每个请求中访问数据库,只需信任它即可。这也可能是抵御某些 DoS 攻击的良好策略,因为您可以将应用程序分层,使位于应用程序服务器前面的专用设备也验证令牌并丢弃无效请求。

如果不允许使用 Cookie,则可以将令牌作为 URL 的一部分发送,如 formsauth 所允许的那样,或者作为 postback 中的表单字段。但是,在生成适当的令牌后,管理这些内容比 Cookie 更加麻烦,以我个人的看法。


在ASP.net中,最好的做法是使用Session吗?这就是ASP.net对cookie的表示方式。 - Jez
Kovacs等人在《安全Cookie协议》中介绍了一种似乎很可靠的通用方法来解决你的问题。我不知道ASP.Net FormsAuth是否具有这些优点,但是几年前我成功地使用C#实现了他们精确的协议(使用了.Net加密库),并且没有遇到太多麻烦。对我来说,这是一个有趣和易于上手的项目,完成后让人感到满意。我不知道是否有任何相关的批评或改进工作。 - Jason Kleban

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接