要让别人认识到代码中存在安全问题,就必须自己对开发语言具有一定了解,以前从未接触过C#,现在通过源代码静态分析平台总结一下C#语言中的安全知识点:
SQL注入
string sql = String.Format("UPDATE TBND_IE SET B_E={0} WHERE BEG_DATE='{1}' AND I_E='{2}' AND A_E='{3}' AND M_E='{4}'", Volume, Date, Id.I_E, Id.A_E, Id.M_E);
...
...
using (DbCommand dbCommand = DBFactory.MD.GetSqlStringCommand(sql)) //sink点
String.Format是将指定的 String类型的数据中的每个格式项替换为相应对象的值的文本等效项,如果上面的Date等对象的值来源于不可信数据源,sql字符串中就有可能引入污染数据源,后面执行数据库操作时,就有可能导致sql注入。
GetStoredProcCommand方法用于存储过程命令;
GetSqlStringCommand方法用于 SQL 文本命令,两个方法都会返回一个 DbCommand 对象
用于 SQL 语句的 DbCommand对象
使用 GetSqlStringCommand 方法创建用于内联 SQL 语句的 DbCommand 对象。特定的 SQL 命令在方法调用时做为一个参数进行传递。下列代码展示了如何使用 GetSqlStringCommand:
Database db = DatabaseFactory.CreateDatabase();
string sqlCommand = "Select ID, LastName, FirstName From Cs";
DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);
用于存储过程的 DbCommand 对象
要执行存储过程,必须使用 GetStoredProcCommand 方法来创建 DbCommand 对象。要执行存储过程的名称在方法调用时做为一个参数传递。下列代码展示了如何使用 GetStoredProcCommand:
Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand("GetProductsByCategory");**
XML外部实体注入
var path = HttpContext.Current.Server.MapPath("~/Configuration/Ak.xml");
...
System.Xml.XmlDocument document = new System.Xml.XmlDocument();
document.Load(path); //sink
预防 XXE 攻击的最佳方式就是禁用 XML 实体解析,因此最好将document的XmlResolver 属性设置为 null 来禁用 XML Entity 解析。如:
document.XmlResolver = null;
如果必须应用程序中处理外部实体,应使用以下功能创建一个自定义 XmlResolver:
- 设置请求超时,预防无限延迟攻击
- 限制将检索的数据量
- 限制 XmlResolver 检索本地主机上的资源
另:[ 任何继承、重载、扩展XmlDocument的类都被视为sink点]
存储型XXS
public partial class IBCashTransferSearch : xQuant.Web.UI.Base.PageBaseEx
{
protected void gvTrade_RowDataBound(object sender, GridViewRowEventArgs e){
HyperLink btnView = e.Row.FindControl("btnView") as HyperLink;
string sD = DataBinder.Eval(e.Row.DataItem, "SD").ToString(); //source点
string strMsg = string.Empty;
OTCManager mgr = new OTCManager();
XPOTCTrade trade = mgr.GetId(int.Parse(sD));
switch (strType)
{
case TradeType.CashTransferSealIn:
btnView.NavigateUrl = string.Format("../Trade/Special/frmClear CashTransferDown.aspx?FromUrl=AccountSearch&TradeID={0}", sD); //sink点
...
}
}
}
DataBinder.Eval(Object, String)方法是 在运行时计算数据绑定表达式 (返回对象的值)
GridViewCommandEventArgs 来自webcontrol,因此e.Row.DataItem视为不可信数据
btnView.NavigateUrl 视为sink点的原因是通过“HyperLink”控件可以在网页上创建链接,使用户可以在应用程序中的各个网页之间移动。“HyperLink”控件可以显示可单击的文本或图像。与大多数 ASP.NET 控件不同,用户单击“HyperLink”控件并不会在服务器代码中引发事件,此控件只起到导航的作用。
反射型XSS
string strInst = Request["iD"].ToString();//source点
ClientScript.RegisterStartupScript(this.GetType(), "para", "<script>iD=" + strInst.Trim() + "</script>"); //sink点
ClientScript.RegisterStartupScript(this.GetType(),*),运行前端页面JS脚本,this.GetType()即指代当前页面Page。
134 namespace xQuant.Web.WebSite.UI.Limit.Report
145 {
156 public partial class VaRDetailRpt : System.Web.UI.Page
167 {
168 public string P_ID
179 {
280 get
251 {
252 return this.hdP_ID.Value;
243 }
254 set
265 {
276 this.hdP_ID.Value = value; //sink点
287 }
278 }
System.Web.UI.Page ,Page类,表示从 ASP.NET Web 应用程序的宿主服务器请求的 .aspx 文件(又称为 Web 窗体页)。
this.hdP_ID.Value = value; 类似于将给页面控件赋值。
public partial class AcctSubjectBalanceView : xQuant.Web.UI.Base.LogonPageBase
{
protected void ge_Rd(object sender, GridViewRowEventArgs e){
e.Row.Cells[0].Text = "<a href=\"#\" onclick=\"openwindow('" + string.Format(url, DataBinder.Eval(e.Row.DataItem, "fefe"), txtDate.Text.Trim(), InstID, "1") + "','grg',800,580)\" style=\"color:blue;\">what </a> " +
...
e.Row.Cells[0].Text:某个控件要显示的内容,这里如果传入不可信数据,就有可能发生反射型XSS.
236 string currentClearingDate = TTRD_DAYEND_FLOW.GetCurrentDate();
....
335 ReStart(txtDate.Text); //source点
txtDate.Text,获取某个控件中的值,这个值可能来源于不可信数据。
跨站脚本:弱验证
this.gvTaskParamList.Rows[StringHelper.GetInt(this.txtT_XML.ToolTip)].Cells[3].Text =Server.HtmlEncode(this.txtT_XML.Text);
给StringHelper.GetInt(this.txtT_XML.ToolTip)].Cells[3].Text控件赋值的数据来自不可信数据源,有可能造成跨站脚本漏洞。
Xpath注入
33 public class LimitClient : xQuant.Web.UI.Base.ServiceBase
...
1037 private string GetNodeValue(XmlDocument xmlDoc, string strAttribute, string strKey) //sink点
1038 {
1039 if (string.IsNullOrEmpty(strAttribute.Trim()) || string.IsNullOrEmpty (strKey.Trim())) return string.Empty;
1041 XmlNodeList nodeList = null;
1042 string[] strKeys = strKey.Split('&');
1043 if (strKeys.Count() == 2)
1044 nodeList = xmlDoc.SelectNodes("//ATYPE[@KEY='" + strKeys[1] + "']/PTYPE[@KEY='" + strKeys[0] + "']"); //sink点
}
如果strkey带有污点数据,就会在1044行造成xpath注入。
xmlDoc.SelectNodes(xpath,namespace) //假设xmlDoc为根节点,整个文档下的查询
还是xmlDoc.ChildNodes[i].SelectNodes(xpath,namespace) //节点下的查询
缺少XML验证
8 namespace xQuant.Model.IrCurve
9 {
10 [Serializable]
11 public class GroupItem
12 {
...
21 public static List<GroupItem> LoadFromXml(string xmlString)
22 {
23 List<GroupItem> r = new List<GroupItem>();
25 if (string.IsNullOrEmpty(xmlString))
26 return r;
[1]XmlTextReader.Create(new StringReader(xmlString)):semantic_25
27 XmlReader xml = XmlTextReader.Create(new StringReader(xmlString));//sink
程序直接解析来自不可信赖的XML文档,会给攻击者提供恶意注入等非法攻击的机会;程序解析来自不可信赖资源的XML时,应该使用DTD,XDR 或 XSD 验证 XML 文档。详细验证方法参考。
详细请参考如何使用 C# 通过.NET 中的 DTD,XDR 或 XSD 验证 XML 文档
路径遍历
33 string fileName = Path.Combine(HttpRuntime.BinDirectory, logConfigFile);
34 if (!File.Exists(fileName))
...
HttpRuntime.BinDirectory:获取当前应用程序的 /bin 目录的物理路径,将这个路径直接用于文件操作不是一个安全的做法。
路径遍历是应用程序对用户可控制的输入未经合理验证,就传给一个文件API;攻击者可能会使用一些特殊的字符(如“..”和“/”)摆脱受保护的限制,访问一些受保护的文件或目录,从而可以越权访问或者覆盖敏感数据。
路径遍历的防御主要是需对用户提交的内容进行严格的过滤,这里主要指过滤目录跳转符”..”、”/”,字符截断符”%00”,dir命令等。也可采用黑白名单策略。如或者创建一份资源白名单,允许其中的字符出现在资源名称中、只运行合法后缀的文件出现在资源名称中。
非托管资源未释放
{
...
XPBond xp = new XPBond(true); //source点
xp.SaveType = SaveType.Insert;
QueryBond(xp, reader, true);
return xp; //sink点
}
程序在发生异常或处理不当的时候可能无法释放非托管的资源。最常见的一类非托管资源是包装操作系统资源的对象,例如文件,窗口,网络连接,数据库连接,画刷,图标等。
任何包含非托管资源的类,都应该继承IDisposable接口;实现Dispose()方法,在其中释放托管资源和非托管资源,并将对象本身从垃圾回收器中移除(垃圾回收器不在回收此资源); 实现类析构函数,在其中释放非托管资源。
MSDN建议按照下面的模式实现IDisposable接口:
public class Foo: IDisposable
{
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!m_disposed)
{
if (disposing)
{
// Release managed resources
}
// Release unmanaged resources
m_disposed = true;
}
}
~Foo()
{
Dispose(false);
}
private bool m_disposed;
}
HTTP消息头注入
cookie.Value = Request.QueryString["token"];
程序将未经验证的数据直接插入HTTP头文件,可能会造成HTTP响应截断等攻击,引发跨站脚本,cookie操纵等漏洞。
HTTP消息头注入的防御方法:在恰当位置进行输入验证和过滤,最保险的方法是创建安全字符白名单,只允许白名单里的字符出现在Http消息头文件中。
NUll引用
试图将secuInstructionOut转为SecuInstruction类型,如失败,则返回null
SecuInstruction secuInstructionIn = secuInstructionOut.Clone() as SecuInstruction; //source
secuInstructionIn.BizType = xQuant.Model.XPO.Set.XPSetInstructionSecu.BIZTYPE_TRANSFERIN;//sink
as 运算符类似于强制转换操作。当用as操作符进行类型转换的时候,首先判断当前对象的类型, 当类型满足要求后才进行转换。但是,如果转换不可行,as 会返回 null 而不是引发异常.