过滤输入
过滤用户数据是我们提高Web应用程序安全性的一种方法,使用它来验证传入数据的合法性。
过滤所有输入数据以避免恶意代码或数据被错误地执行或存储。
大多数Web应用程序漏洞都会忽略过滤输入数据并天真地信任它。
我们对过滤数据的介绍分为三个步骤:
1. 识别数据;我们需要过滤数据以确定其来源
2. 过滤数据本身;我们需要弄清楚我们收到的数据类型
3. 区分过滤(消毒)和污染数据;数据过滤后,我们可以确信它是安全的
识别数据
“识别数据”是我们的第一步,因为大多数时候,如上所述,我们不知道它的来源。
没有这些知识,我们将无法正确过滤它。
此处的数据全部来自非代码数据。
例如:所有数据都来自客户端,但用户的客户端不是唯一的外部数据源。
提供第三方数据的数据库接口也可以是外部数据源。
在Go中很容易识别用户输入的数据。
我们在用户POST表单后使用r.ParseForm来获取r.Form中的所有数据。
其他类型的输入更难以识别。
例如,在r.Headers中,许多元素通常由客户端操纵。
通常很难确定客户操纵了哪些元素,因此最好将它们全部视为已被污染。
例如,r.Header.Get("Accept-Charset")头字段也被视为用户输入,尽管这些通常仅由浏览器操纵。
过滤数据
如果我们知道数据的来源,我们可以过滤它。
过滤是该术语的一种正式用法。
许多其他术语(例如输入清洁,验证和消毒)都知道该过程。
尽管这些术语的含义有所不同,但它们都指的是同一件事:防止非法数据进入您的应用程序的过程。
有许多方法可以过滤数据,其中一些方法不如其他方法安全。
最好的方法是检查数据本身是否符合您的应用程序规定的法律要求。
在尝试这样做时,不要试图纠正非法数据是非常重要的;
这可能允许恶意用户根据自己的需要操纵验证规则,从根本上破坏了过滤数据的目的。
历史证明,尝试更正无效数据通常会导致安全漏洞。
让我们来看一个过于简单的例子,用于说明目的。
假设银行系统要求用户提供安全的6位数密码。
系统验证所有密码的长度。
有人可能天真地编写一个验证规则来纠正非法长度的密码:"如果密码短于法定长度,请用0表示填写剩余数字"。
这个简单的规则允许攻击者只猜测密码的前几位数,以成功获得用户帐户的访问权限!
我们可以使用几个库来帮助我们过滤数据:
1. strconv包可以帮助我们将用户输入的字符串转换为特定类型,因为r.Forms是字符串值的映射。strconv提供的一些常见字符串转换是Atoi,ParseBool,ParseFloat和ParseInt。
2. Go的strings包包含一些过滤函数,如Trim,ToLower和ToTitle,它们可以帮助我们根据需要获取特定格式的数据。
3. Go的regexp包可用于处理本质上更复杂的案例,例如确定输入是电子邮件地址,生日等。
区分已过滤和受污染的数据
如果您已完成上述步骤,则基本上已完成过滤数据的工作。
但是,在编写Web应用程序时,我们还需要区分已过滤和受污染的数据,因为这样做可以保证数据过滤过程的完整性,而不会影响输入数据。
让我们将所有过滤后的数据放入名为CleanMap的全局映射变量中。
然后,需要两个重要步骤来防止数据注入污染:
1. 每个请求必须将CleanMap初始化为空映射。
2. 防止将名为CleanMap的外部数据源中的变量引入应用程序。
接下来,让我们使用示例表单来强化这些概念:
<form action="/whoami" method="POST">
Who am I:
<select name="name">
<option value="durban">durban</option>
<option value="durban1">durban1</option>
<option value="durban2">durban2</option>
</select>
<input type="submit" />
</form>
在处理这种类型的表单时,很容易犯错误,认为用户只能提交三个选择选项中的一个。
实际上,攻击者可以轻松模拟POST操作。
例如,通过使用name = attack提交相同的表单,恶意用户可能会将非法数据引入我们的系统。
我们可以使用简单的白名单来对抗这些类型的攻击:
r.ParseForm()
name := r.Form.Get("name")
CleanMap := make(map[string]interface{}, 0)
if name == "durban" || name == "durban1" || name == "durban2" {
CleanMap["name"] = name
}
上面的代码初始化了一个CleanMap变量,只有在对合法值的内部白名单(在这种情况下为durban,durban1和durban2)进行检查后才会分配名称。
我们将数据存储在CleanMap实例中,因此您可以确保CleanMap["name"]包含经过验证的值。
任何希望访问此值的代码都可以自由地执行此操作。
如果白名单用于处理非法数据,我们还可以在上面添加其他语句,可能是表单显示错误。
不要试图过于宽容,否则您可能会意外污染您的CleanMap。
用于根据一组已知的合法值过滤数据的上述方法是非常有效的。
还有另一种方法可以检查传入数据是否由使用正则表达式的合法字符组成,但是在上述情况下,我们要求该名称是select中的一个选项,这将无效。
例如,您可能要求用户名仅包含字母和数字:
r.ParseForm()
username := r.Form.Get("username")
CleanMap := make(map[string]interface{}, 0)
if ok, _ := regexp.MatchString("^[a-zA-Z0-9].$", username); ok {
CleanMap["username"] = username
}
小结
数据过滤在现代Web应用程序的安全性中起着至关重要的作用。
大多数安全漏洞是由于不正确地过滤数据或忽略正确验证数据而导致的。
由于前一部分涉及CSRF攻击,接下来的两部分将引入XSS攻击和SQL注入,因此在处理与数据清理同等重要的主题时没有自然的区别,因此在本节中,我们特别关注它。
版权声明
由 durban创作并维护的 小绒毛的足迹博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证。
本文首发于 博客( https://www.xiaorongmao.com ),版权所有,侵权必究。