【问题标题】:Generate Reset Password link in WebApi在 WebApi 中生成重置密码链接
【发布时间】:2023-03-25 04:25:02
【问题描述】:

我想生成一个重置密码链接以发送到用户的电子邮件,该电子邮件将打开 ResetPassword 页面。在这个页面上,我将填写新密码的详细信息,然后确认密码。

为此我关注了Link

但是有一个 Url.Action 方法我无法在我的 web api 项目中找到。

var callbackUrl = Url.Action(
               "ConfirmEmail", "Account", 
               new { userId = user.Id, code = code }, 
               protocol: Request.Url.Scheme);

有人在 web api 中完成了重置密码部分吗?我需要帮助。

【问题讨论】:

  • 为什么这被否决了?似乎是一个合理的问题。
  • 特雷弗,这是一个很好的问题。谢谢提问!!!!

标签: asp.net asp.net-web-api asp.net-web-api2


【解决方案1】:

在我看来,你不应该在没有自己设置主机的情况下使用Url.Link()Url.Action() 向用户发送内容。您将他们暴露给可能的Host Header Attack -> Password Reset Poisoning

如果 IIS 具有接受 80/443 上的连接的绑定,则可以更改主机标头,进而影响 Url.Link()Url.Action() 方法。如果您查看我在下面提出的请求,我将连接到 http://hostheaderattack,但正在操作 host 标头。

概念证明 (PoC):

网址链接:

public class TestController : ApiController
{
    public IHttpActionResult Get()
    {
        var callbackUrl = Url.Link("Default", new
        {
            Controller = "Home",
            Action = "Index",
        });

        return Ok(callbackUrl);
    }
}

网址.操作:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Title = $"Url Created: {Url.Action("Index", "Home", "", Request.Url.Scheme)}";

        return View();
    }
}

我也在这里演示过:

https://security.stackexchange.com/questions/170755/host-header-attack-password-reset-poisoning-asp-net-web-api-2-hosted-as-az/170759#170759

更多关于主机头攻击的阅读:

https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/

你应该做的是永远不要相信用户请求并手动构造与主机的 url。

手动主机名示例:

Url.Action:Url.Action("Index", "Home", null, Request.Url.Scheme, "example.com")

对于 Url.Link 它有点棘手,但可以这样做:

public class TestController : ApiController
{
    // GET api/<controller>
    public IHttpActionResult Get()
    {
        var callbackUrl = Url.Link("Default", new
        {
            Controller = "Home",
            Action = "Index",
        });

        callbackUrl = ReplaceHost(callbackUrl, "example.com");

        return Ok(callbackUrl);
    }

    private string ReplaceHost(string original, string newHostName)
    {
        var builder = new UriBuilder(original);
        builder.Host = newHostName;
        return builder.Uri.ToString();
    }
}

ReplaceHost 方法的来源:

https://stackoverflow.com/a/479812/3850405

【讨论】:

    【解决方案2】:

    您可以在 Web API 2.0 中使用Url.Link

    var callbackUrl = Url.Link("Default", new { Controller = "Account", 
                      Action = "ConfirmEmail", userId = user.Id, code = code });
    

    【讨论】:

      【解决方案3】:

      我创建了一个简单的“更改密码”表单,我根据我的 webAPI 应用程序中的菜单点击来管理它。在此表单的更新处理程序上,我创建了以下事件处理程序。这只是调用了 VS2013 WebAPI 模板附带的 AccountController Web 服务。此示例启用了身份验证,并记下用于在 AccountController 方法中包含已定义路由的特定 Url。

      在 WebAPI 模板中生成的 AccountController 类中查找 ChangePassword() 方法,以查看调用了什么。我认为这应该回答您的基本问题。

      function updateHandler(callback) {
      var response;
      var targetUrl;
      
      // disabled the login button to avoid multiple events
      $("#btnLogin").prop('disabled', true);
      
      var loginData = {
          grant_type: 'password',
          NewPassword: $("#txtNewPassword").val(),
          OldPassword: $("#txtOldPassword").val(),
          ConfirmPassword: $("#txtConfirmPassword").val()
      };
      
      var token = sessionStorage.getItem(tokenKey);
      var headers = {};
      if (token) {
          headers.Authorization = 'Bearer ' + token;
      }
      
      
      targetUrl = "/api/account/ChangePassword";
      
      $.ajax({
          type: 'POST',
          url: targetUrl,
          data: loginData,
          headers: headers,
      }).done(function (data) {
              closeChangePassword();
      }).fail(function (xhr, textStatus, errorThrown) {
          passwordErrorHandler(xhr,0);
          // re-enable the login button 
          $("#btnLogin").prop('disabled', false);
      });
      

      }

      【讨论】:

        【解决方案4】:

        尝试以下:

        var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
                var callbackUrl = Url.Action("ResetPassword", "Account", 
                new { UserId = user.Id, code = code }, protocol: Request.Url.Scheme);
                await UserManager.SendEmailAsync(user.Id, "Reset Password", 
                "Please reset your password by clicking here: <a href=\"" + callbackUrl + "\">link</a>");        
                return View("ForgotPasswordConfirmation");
        

        更多信息请关注link

        【讨论】:

        • 感谢@chandrika 我已经浏览了链接。但是在我的 wep-api 项目 Action og Url 中显示错误,它不可用。我已经附上了相同的链接。
        • 这在 API 控制器中不起作用,因为如循环所述,Url 不可用。你可以通过使用new UrlHelper(System.Web.HttpContext.Current.Request.RequestContext); 构造一个 UrlHelper 来解决这个问题,但是 protocol: Request.Url.Scheme 不起作用,你最终会得到一个相对的 Url 而不是绝对的。
        【解决方案5】:

        Url.Action 不存在,因为 WebApi 中的 Url 助手没有 Action 方法。您可以改用 Url.Route 来生成相同的内容,但您需要创建一个命名路由才能使用该方法。如果您正在使用属性路由它,您可以像这样为路由属性添加一个名称:

        [Route(Name="ConfirmEmail")]
        

        帮助者是

        var callbackUrl = Url.Route("ConfirmEmail", new { userId = user.Id, code = code });
        

        【讨论】:

          猜你喜欢
          • 2019-05-29
          • 2021-11-04
          • 2011-04-03
          • 2017-03-03
          • 2013-03-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-19
          相关资源
          最近更新 更多