CS.XSS.PERSIST
跨站脚本持久型漏洞
CS.XSS.PERSIST 检查器会标记代码的实例,其中输入直接由来自 HTTP 请求的数据提供,而该数据则存储在数据库、消息论坛、访客日志或其他受信任的数据存储中,并且可以在稍后读回。
漏洞与风险
遭到跨站脚本 (XSS) 攻击后,对于用户可控制的输入,软件不会或会错误地对其进行中性化处理,随后便将其放入用于服务其他用户的网页的输出中。
发生 XSS 漏洞时:
- 不受信任的数据会进入 Web 应用程序,通常是通过 Web 请求。
- 该 Web 应用程序会动态生成一个包含此不受信任数据的网页。
- 在页面生成期间,应用程序不会阻止数据包含可由 Web 浏览器执行的内容,如 JavaScript、HTML 标签、HTML 属性、鼠标事件、Flash、ActiveX 等。
- 通过使用 Web 浏览器,受害者会访问生成的网页,而网页中则包含使用不受信任数据注入的恶意脚本。
- 因为脚本来自由 Web 服务器发送的网页,所以受害者的 Web 浏览器会在 Web 服务器域的上下文中执行恶意脚本。
- 这可以有效避开 Web 浏览器的同源策略,该策略规定,一个域中的脚本不可访问其他域中的资源或在其中运行代码。
XSS 有三个主要类型:
- 类型 1:反射型 XSS(或非持久型)
- 类型 2:存储型 XSS(或持久型)
- 类型 0:DOM 型 XSS
应用程序将危险数据存储在数据库、消息论坛、访客日志或其他受信任的数据存储中。随后,危险数据会被读回应用程序并包含在动态内容中。从攻击者的角度来看,注入恶意内容的最佳位置是许多用户或特别感兴趣的用户会访问的区域。感兴趣的用户通常在应用程序中拥有提升的权限,或者会与攻击者看重的敏感数据进行交互。如果这些用户中的其中一位执行恶意内容,攻击者便可代表该用户执行特权操作或访问属于该用户的敏感数据。例如,攻击者可能将 XSS 注入日志消息,当管理员查看日志时可能无法正确处理该消息。
缓解与预防
为防止 XSS 攻击,请先对所有用户可控制的输入进行中性化处理,然后再将这些数据放入用作网页的输出中。
漏洞代码示例
复制
protected void Submit_Click(object sender, EventArgs e)
{
try
{
var txt = MyTextbox.Text;
saveValueInDataBase( txt ); // CS.XSS.PERSIST
}
catch (Exception) { }
}
void saveValueInDataBase(string val)
{
SqlConnection con = new SqlConnection();
SqlCommand cmd = new SqlCommand("sp_insert1", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter outpara = new SqlParameter("@id", SqlDbType.Int);
outpara.ParameterName = "@id";
outpara.SqlDbType = SqlDbType.Int;
outpara.Direction = ParameterDirection.Output;
cmd.Parameters.Add(outpara);
cmd.Parameters.AddWithValue("@value", val);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
在此示例中,Klocwork 在第 6 行报告了缺陷,这表示“在第 5 行从 get_Text() 接收到未经验证的 XSS 字符串 txt。该内容会通过调用第 6 行的 saveValueInDataBase() 进行保存。这可能造成跨站脚本漏洞。”
修正代码示例
复制
protected void Submit_Click(object sender, EventArgs e)
{
try
{
var txt = MyTextbox.Text;
saveValueInDataBase(Server.HtmlEncode( txt )); // no defect
}
catch (Exception) { }
}
void saveValueInDataBase(string val)
{
SqlConnection con = new SqlConnection();
SqlCommand cmd = new SqlCommand("sp_insert1", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter outpara = new SqlParameter("@id", SqlDbType.Int);
outpara.ParameterName = "@id";
outpara.SqlDbType = SqlDbType.Int;
outpara.Direction = ParameterDirection.Output;
cmd.Parameters.Add(outpara);
cmd.Parameters.AddWithValue("@value", val);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
在此修正代码示例中,Klocwork 不报告缺陷。