MVC 模型绑定给网站带来了哪些独特的风险?需要什么额外的警惕?

信息安全 Web应用程序 应用安全 威胁缓解 asp.net-mvc 红宝石
2021-08-25 23:46:42

据我了解,“模型绑定”是基于 ASP.NET MVC 或 Ruby on Rails(还有其他......)的网站在 HTTP 的 GET 语句中获取参数并将它们作为变量传递给站点内的代码。

由于 GitHub(一个流行的程序员 FOSS 站点)通过模型绑定漏洞被黑客入侵,我想知道需要哪些一般做法来弥补这个漏洞。具体来说

  • 什么是模型绑定漏洞?

  • 所有 MVC 框架都受到影响吗?

  • 这是开发人员必须解决的问题......还是网络代理/过滤器可以纠正这个问题?

  • 是否有任何安全工具可帮助识别或诊断给定站点中的此问题?

2个回答

模型绑定是一个相当不错的功能,如果使用得当,它可能会增加整体安全性。

以下是它的工作原理(代码和功能适用于 ASP.NET MVC,但在 Ruby 中可能相同):假设您在网页中有一个表单:

<form action="/SendData">

  Email: <input type="text" name="email" id="email"><br>
  Address:<input type="text" name="address" id="address"><br>

  <input type="submit" value="Submit">

</form>

你写一个这样的类:

class Contact{
   String Email{get;set;} 
   String Address{get;set;} 
}

通过模型绑定,处理用户请求的函数可以是:

public ActionResult SendData(Contact contact){
        //do something with contact.Email and contact.Address
}

如您所见,模型绑定自动将它在 HTML 请求中接收到的数据放入 Contact 类型的对象中。

此外,您可以使用 DataAnnotations 定义验证函数。

class Contact{
   [Required(ErrorMessage="Input email please!")]
   [RegularExpression("^some_regex"),ErrorMessage ="Error"]
   String Email{get;set;} 
   [Required(ErrorMEssage="Input address please!")]
   String Address{get;set;} 
}

并像这样检查它:

public ActionResult SendData(Contact contact){
    if(ModelState.IsValid)
    {
        //do something with contact.Email and contact.Address
    }
}

如您所见,添加验证和一些常见错误很容易(例如可以避免编写糟糕的 SQL 查询)。

现在解释导致 GitHub hack(批量绑定)的问题:

如果您的类中有没有出现在表单中的属性会发生什么:

<form action="/SendData">

  Email: <input type="text" name="email" id="email"><br>
  <input type="submit" value="Submit">

</form>

如果攻击者还发送了一个名为address的变量,框架会自动绑定它,而不知道在原始表单中没有这样的输入。

GitHub案例中,开发人员可能使用了一个对象,该对象具有区分管理员和普通用户的属性(例如isAdmin)。通过在登录表单(或其他页面)中发送此参数以及用户和密码,攻击者可以获得对管理功能的访问权限。

有几种方法可以解决这个问题(黑名单绑定、白名单绑定),但我建议使用仅包含表单属性(或将其他属性标记为只读)的接口和类。

白名单绑定示例:

public ActionResult SendData(
[Bind(Include="Email")]Contact contact)
{
    //...
}

关于受影响的框架,可能大多数都受到影响(Ruby 和 ASP 都受影响),但这并不是漏洞本身,它只是糟糕的编程。只要程序员正确处理此功能,一切都应该没问题。

我不认为自动化工具可以检测到这类问题,但是彻底的代码审查应该可以解决它。

作为对 Dinu 评论的更新,许多PHP框架中的模型都遭受了同样的问题。很少有提供无法从负载设置的“受限属性”。他们中的大多数人只是假设您在将值“加载()”到它们中并相应地分配属性时知道自己在做什么 - 再次,草率的编码实践。

Laravel 4 是我见过的,它提供了一些限制来帮助防止批量分配问题。