模型绑定是一个相当不错的功能,如果使用得当,它可能会增加整体安全性。
以下是它的工作原理(代码和功能适用于 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 都受影响),但这并不是漏洞本身,它只是糟糕的编程。只要程序员正确处理此功能,一切都应该没问题。
我不认为自动化工具可以检测到这类问题,但是彻底的代码审查应该可以解决它。