【问题标题】:Authorization in WebAPI (MVC4)WebAPI 中的授权 (MVC4)
【发布时间】:2014-05-21 07:17:49
【问题描述】:

我们的客户要求我完成以下任务:

使经过身份验证的用户无法修改其他用户的信息

目前,手机应用程序通过 HTTPS 向我们的 API 发送用户用户名和密码作为 BASIC auth 标头:base64(username:password)。

在 WebAPI 中,我创建了一个 BasicAuthenticationMessageHandler。在这个处理程序中,我根据客户 LDAP 验证用户凭据。

这一切都很好。

我有一个名为 Customer 的控制器:

[Authorize]
public class CustomerController : BaseApiController<CustomerMapper>
{ ... }

如上所示,我用 Authorize 属性装饰它。

我有一个 PUT 方法:

    public HttpResponseMessage Put(CustomerPutModel data)
    {
        if (ModelState.IsValid)
        {
            var c = customerService.GetByID(data.ID);

            if (c != null)
            {
                c = ModelMapper.Map<CustomerPutModel, Customer>(data, c);

                customerService.Update(c);

                return new HttpResponseMessage(HttpStatusCode.NoContent);
            }
        }
        throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
    }

型号:

public class CustomerPutModel
{
    public int ID{ get; set; }
    [Required]
    public string CustomerAccountID { get; set; }
    [Required]
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }
    [Required]
    public string City { get; set; }
    [Required]
    public string State { get; set; }
    public int Zipcode { get; set; }
}

此控制器方法按预期工作。

我遇到的问题是,如何防止我的 PUT 方法(以及所有其他控制器/方法)中出现以下情况:

  1. 用户 1 具有正确的身份验证凭据
  2. 用户 1 使用代理监听请求
  3. 用户 1 将请求正文的 ID 从他们的 ID 更改为用户 2 的 ID
  4. 用户 1 发送带有正确身份验证标头的 PUT,但在正文中他们传递了另一个用户 ID

如何在方法级别防止这种情况发生?由于应用程序的不同部分会触发某些控制器操作,我认为我无法保护所有这些操作。

授权经过身份验证的用户实际上可以执行他们请求的操作的正确方法是什么?这是否需要为每个方法操作进行自定义编码??

【问题讨论】:

    标签: c# asp.net-web-api authorization basic-authentication restful-authentication


    【解决方案1】:

    您可以将 Action 方法更改为:

    public HttpResponseMessage Put(CustomerPutModel data)
    {
        if (ModelState.IsValid)
        {
            var myID = userService.GetIDByUserName(HttpContext.Current.User.Identity.Name);
            if (myID != data.ID) 
            {
                ... wrong id, e.g. throw an exception or return a View indicating the error.
            }
            var c = customerService.GetByID(data.ID);
    
            if (c != null)
            {
                c = ModelMapper.Map<CustomerPutModel, Customer>(data, c);
    
                customerService.Update(c);
    
                return new HttpResponseMessage(HttpStatusCode.NoContent);
            }
        }
        throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
    }
    

    【讨论】:

    • 这正是我认为我们必须做的事情……当你有 160 多种方法要做时,这并不有趣。更不用说这是客户在最后一刻添加的。还有其他更通用的方法吗?
    • @SteveStokes - 我看不到任何“通用”方法可以做到这一点,尽管可以重构通用代码。就我个人而言,我倾向于在业务层实现授权(例如存储库,具体取决于您如何构建应用程序)。
    • 对,我们总是在每个请求中传递相同的 ID,所以我打算用通用方法提取它。男人,多么痛苦。 =\
    【解决方案2】:

    我建议创建签名以验证请求是否未被篡改,这意味着您可以根据应用发送的信息使用某种单向加密算法。

    当您在 API 上收到请求时,您只需使用相同的算法来接收信息并查看签名是否匹配。如果不是,则有人篡改了请求并修改了一些信息。

    只需对防止篡改请求进行一些研究即可。

    关于确保用户只能执行某些方法,而不能执行其他方法,例如,我建议您研究基于声明的授权。

    【讨论】:

    • 我不推荐使用自制的单向加密算法。要防止 MITM 攻击,请使用 https。要防止授权用户修改 POST 数据,请始终验证服务器端。
    • 加密算法可能不是最好的选择词。相反,我说的是哈希函数,并且有很多算法可以解决这个问题,例如 SHA。我也不建议使用自制的。
    猜你喜欢
    • 2016-05-11
    • 1970-01-01
    • 2014-04-27
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多