通常,当某个站点要求您在访问某个页面之前已登录时,您将进入登录屏幕,并在成功验证自己后,您将被重定向回最初请求的页面.这对于可用性非常有用 - 但是如果不仔细审查,此功能很容易成为一个开放的重定向漏洞.
遗憾的是,对于此漏洞的一个示例,只看ASP.NET MVC 2提供的默认LogOn操作:
[HttpPost] public ActionResult LogOn(LogOnModel model, string returnUrl) { if (ModelState.IsValid) { if (MembershipService.ValidateUser(model.UserName, model.Password)) { FormsService.SignIn(model.UserName, model.RememberMe); if (!String.IsNullOrEmpty(returnUrl)) { return Redirect(returnUrl); // open redirect vulnerability HERE } else { return RedirectToAction("Index", "Home"); } } else { ModelState.AddModelError("", "User name or password incorrect..."); } } return View(model); }
如果用户成功通过身份验证,则会将其重定向到"returnUrl"(如果通过登录表单提交提供).
以下是利用此漏洞的简单示例攻击(实际上是众多攻击之一):
假装成受害者银行的攻击者向受害者发送包含链接的电子邮件,如下所示: http://www.mybank.com/logon?returnUrl=http://www.badsite.com
在被教导验证整个域名(例如,google.com = GOOD,google.com.as31x.example.com = BAD)后,受害者知道链接是正常的 - 没有任何棘手的子域网络钓鱼行为上.
受害者点击链接,看到他们实际熟悉的银行网站并被要求登录
受害者登录并随后被重定向到http://www.badsite.com
看起来与受害者银行的网站完全相同,因此受害者不知道他现在在不同的网站上.
http://www.badsite.com
说"我们需要更新我们的记录 - 请在下面输入一些非常个人的信息:[ssn],[地址],[电话号码]等."
受害者,仍然认为他在他的银行网站,堕落的策略,并为攻击者提供信息
有关如何维护此重定向成功登录功能的任何想法,但避免了开放重定向漏洞?
我倾向于将"returnUrl"参数拆分为控制器/动作部分并使用"RedirectToRouteResult"而不是简单地"重定向".这种方法是否会打开任何新的漏洞?
更新
通过将自己限制为控制器/动作路线,我无法重定向到自定义路线(例如/backend/calendar/2010/05/21
).我知道通过将更多参数传递给LogOn操作,我可以让它工作,但我觉得我将永远重新审视这种方法 - 使我们的路由方案保持最新.因此,不是将returnUrl拆分为其控制器/动作部分,而是保持returnUrl as-is并解析它以确保它仅包含相对路径(例如/users/1
)而不是绝对路径(例如http://www.badsite.com/users/1
).这是我正在使用的代码:
private static bool CheckRedirect(string url) { try { new Uri(url, UriKind.Relative); } catch (UriFormatException e) { return false; } return true; }
旁注:我知道这种开放式重定向与XSS和CSRF相比似乎不是什么大问题,但我们的开发人员是保护我们的客户免受坏人的唯一事情 - 我们可以做任何事情来制造坏人'努力工作是我书中的一个胜利.
谢谢,布拉德
Jon Galloway撰写了一篇关于MVC 2(和1)解决方案的文章.
以下是应该帮助您处理问题的代码段:
SECURED(原始文章更新2014)
private bool IsLocalUrl(string url) { return System.Web.WebPages.RequestExtensions.IsUrlLocalToHost( RequestContext.HttpContext.Request, url); }