设为首页 收藏本站
查看: 1049|回复: 0

[经验分享] ASP.NET Core中的OWASP Top 10 十大风险

[复制链接]

尚未签到

发表于 2017-12-14 18:16:17 | 显示全部楼层 |阅读模式
  不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址
  本博文翻译自:
  
https://dotnetcoretutorials.com/2017/10/11/owasp-top-10-asp-net-core-sql-injection/
  OWASP或者说是开放Web应用程序安全项目,这是一个非营利性的组织,其目的是促进安全的web应用程序的开发和设计。当他们在世界各地举办不同的研讨会和活动时,你可能听说过他们,因为“OWASP Top Ten”项目。每隔几年,OWASP就会发布十大最重要的web安全风险列表。当然,这并不意味着您需要检查这10个项目,您的网站现在是安全的,但它绝对涵盖了您的网站上最常见的攻击媒介的基础。
  当我第一次开始编程并听说OWASP的时候,对我来说最困难的事情就是把它变成实际的东西,例如,当有人开始谈论“CSRF”时,我想知道在.NET中,它是什么样子,它保护自己的基本原则是什么,.NET的系统中有什么(如果有的话)?这篇10部分的文章系列将尝试在ASP.net Core的领域中回答这些问题。您绝对不会突然对所有网络攻击都可以免疫,但是希望可以帮助您从ASP.net Core角度了解OWASP十大安全风险。
  另外要注意的是,我将基于OWASP 2017 候选发布版的前10名。这些尚未被接受为2017年的官方十强,如果他们改变,我一定会添加额外的文章来涵盖一切。
  所以不用多说,我们开始吧!我们列出的第一个项目是SQL注入。

SQL注入如何工作?
  SQL注入可以通过修改一个已知的输入参数来修改SQL语句,而这个SQL语句的执行方式与我们预期的非常不同。这听起来像是一大堆的胡言乱语,我们来举个例子吧。
  如果您想要在您的机器上运行整个工作代码项目,您可以从Github那里获取任何东西。您仍然可以在没有代码的情况下继续进行下去,因为我将在整个过程中发布代码示例和屏幕截图。
  首先让我们创建一个包含两个表的数据库。第一个表名为“NonsensitiveDataTable”,它包含一些我们不敏感可以向用户分享的数据。第二个表名为“SensitiveDataTable”它包含用户信用卡和社会保障号码。下面是SQL Server中的表。

  现在我们假设我们有一个API方法。这个方法的作用就是让我们通过id来向NonSensitiveDataTable表请求数据。
  

[HttpGet]  
[Route("nonsensitive")]
  
public string GetNonSensitiveDataById()
  
{
  using (SqlConnection connection = new SqlConnection(_configuration.GetValue<string>(&quot;ConnectionString&quot;)))
  {
  connection.Open();

  SqlCommand command = new SqlCommand($&quot;SELECT * FROM NonSensitiveDataTable WHERE>  using (var reader = command.ExecuteReader())
  {
  if (reader.Read())
  {
  string returnString = string.Empty;
  returnString += $&quot;Name : {reader[&quot;Name&quot;]}. &quot;;
  returnString += $&quot;Description : {reader[&quot;Description&quot;]}&quot;;
  return returnString;
  }
  else
  {
  return string.Empty;
  }
  }
  }
  
}
  

  这是一个相当极端的例子,编码相当差,但它说明了这一点。我们通过调用这个方法获取数据,似乎没问题。

  但是只要看代码,我们就可以看到有疑问的东西。值得注意的是:
  

SqlCommand command = new SqlCommand($&quot;SELECT * FROM NonSensitiveDataTable WHERE>  

  我们正在将Id参数直接传递到SQL语句中,难道我们可以在那里输入任何东西?那么我们知道当我们要求2的ID时,“Mark Twain”的记录就会被返回。但让我们来试试这个:


  哇…。那么为什么我们添加测试“OR>  

SELECT * FROM NonSensitiveDataTable WHERE>  

  但是当我们通过OR语句时,它实际上会像这样读取:
  

SELECT * FROM NonSensitiveDataTable WHERE>  

  所以在这里我们已经设法通过更改查询参数来修改执行的SQL语句。但没有什么大不了的对吗?用户将收到错误的数据,那就是结束了。那么,因为我们知道我们可以修改SQL语句。让我们尝试一些时髦的东西。让我们试试这个网址:

  呃哦,看起来不好看 运行的查询结果如下所示:
  

SELECT * FROM NonSensitiveDataTable WHERE>  

  我们在NonSensitiveDataTable表中查询ID为999的记录,并且和SensitiveDataTable表的数据关联起来,因为没有999的ID的记录我们会立即跳过,不过我们发现我们的敏感信息已经被泄露。
  如果这是一个电子商务网站,他们将会有一个“客户”表和一个“订单”表等等。那么这个时候我们的信息已经被泄露,SQL注入并不像复制粘贴URL那样简单,但是有了它们我们好像有了打开王国大门的钥匙。
  好的,让我们再试一次。让我们尝试以下查询。它会告诉我们数据库中的表名。
  

SELECT * FROM NonSensitiveDataTable WHERE>  


  您经常会在web上发现SQL注入的“规则”,其中有大量的SQL命令可以尝试。你有它,少一点猜测。我们可以在这里坐上几天,把命令扔到这里。在SQL注入的情况下,对方的数据库里有什么简直一目了然
  我将留给您一个最后的查询,您可以尝试并运行。假设你在试图获取数据时感到沮丧,你只是想毁掉某人的一天。想象一下运行以下命令:
  

SELECT * FROM NonSensitiveDataTable WHERE>  

  这里我们已经放弃了,我们只需要删除一个表。也许我们甚至可以获取所有的数据,如果我们只是想让DBA的生活变得痛苦。这肯定是一种方法!
  现在我们大致知道了SQL注入是什么,让我们继续保护自己!

清理您的输入
  您经常会发现,关于任何描述SQL注入攻击的文章的第一条评论是“始终对您的输入进行清理”(紧接着“在您的查询中使用参数代替更好!” )- 但这些稍后再说。对您的输入进行清理可能意味着几件事情,让我们来看看。

转换为非字符串类型
  在我们的示例代码中,因为我们知道我们的Id应该是一个int。我们可以这样:
  

int>
SqlCommand command = new SqlCommand($&quot;SELECT * FROM NonSensitiveDataTable WHERE>  

  完美!现在如果有人试图在我们的查询字符串中添加进一步的信息,它不会被解析为int,我们就会避免注入!
  在ASP.net Cor中一个有个更简单的例子只要允许我们的路由为我们工作,我们就可以达到上面的目的。
  

[HttpGet]  
[Route(&quot;nonsensitiveroute/{id}&quot;)]

  
public string GetNonSensitiveDataByIdWithRoute(int>  

  现在我们甚至不需要做任何手工解析。ASP.net Core路由将为我们处理它!
  当然,如果您的查询实际上是针对整数列的,那么这能起作用。如果我们真的需要传递字符串,那又会怎样呢?

白名单/黑名单/字符替换
  老实说,我不想深入到这个问题,因为我认为这是一个很容易出错的处理SQL注入的方法。但是,如果必须,您可以在传递到SQL之前,对已知正确值的白名单或黑名单运行字符串。或者您可以替换某些字符的所有实例(引号,分号等)。但是所有这些都依赖于你在攻击之前的一步。你也会把你对SQL语言的复杂性的知识与别人混淆。
  虽然像PHP这样的语言具有“转义”SQL字符串的内置函数,但.NET core不支持。此外,简单地转义引号也不能从根本解决SQL注入问题.。
  始终对输入进行清理需要您“记住”来做到这一点。这并不是一种可以遵循的模式。这很有效。但这不是理想的解决方案。

参数化查询
  在您的SQL查询中使用参数将成为您抵御SQL注入攻击的首选。即使您正在使用某种类型的ORM(在下面讨论了一点),但在幕后,他们可能会使用参数化的查询。
  那么我们如何在我们的示例项目中使用它们呢?我们将会稍微改变一下,而不是在我们的NonSensitiveDataTable表中直接使用“name”字段中进行查询。这样做只是因为它给了我们更多的灵活性。
  

[HttpGet]  
[Route(&quot;nonsensitivewithparam&quot;)]
  
public string GetNonSensitiveDataByNameWithParam()
  
{
  using (SqlConnection connection = new SqlConnection(_configuration.GetValue<string>(&quot;ConnectionString&quot;)))
  {
  connection.Open();
  SqlCommand command = new SqlCommand($&quot;SELECT * FROM NonSensitiveDataTable WHERE Name = @name&quot;, connection);
  command.Parameters.AddWithValue(&quot;@name&quot;, Request.Query[&quot;name&quot;].ToString());
  using (var reader = command.ExecuteReader())
  {
  if (reader.Read())
  {
  string returnString = string.Empty;
  returnString += $&quot;Name : {reader[&quot;Name&quot;]}. &quot;;
  returnString += $&quot;Description : {reader[&quot;Description&quot;]}&quot;;
  return returnString;
  }
  else
  {
  return string.Empty;
  }
  }
  }
  
}
  

  你可以看到我们在我们的查询中添加了哪些参数吗?那么这是如何工作的?那么在SQL Profiler的帮助下,正在发送的实际SQL如下所示:
  

exec sp_executesql N'SELECT * FROM NonSensitiveDataTable WHERE Name = @name'  
,N'@name nvarchar(12)'
  
,@name=N'Bart Simpson'
  

  哇...这是一个很大的不同。那么这里发生了什么?我们正在发送查询,但是说“以后,我将告诉您查询什么数据”。我们传递想要查询的确切值,而不是实际的SELECT语句。通过这种方式,我们的原始查询保持不变,并且不影响用户对查询字符串的类型。
  使用参数的最好的方法是它们成为一个简单的模式。你不必“记住”来逃避某些字符串,或者“记住”使用白名单。

存储过程
  SQL存储过程是避免SQL注入攻击的另一个好方法。尽管现在存储过程似乎对开发人员无所适从,但是它们与参数化查询类似,因为您将通过SELECT语句和查询数据在两个不同的“批次”中传递。我们快速创建一个存储过程来尝试(如果您使用GIT中的示例项目,则您的数据库中已经有该SP,并且不需要运行以下操作)。
  

CREATE PROCEDURE SP_GetNonSensitiveDataByName  @Name nvarchar(MAX)
  
AS
  
BEGIN
  SET NOCOUNT ON;
  SELECT * FROM NonSensitiveDataTable WHERE Name = @Name
  
END
  

  让我们创建一个API方法,运行它。
  

[HttpGet]  
[Route(&quot;nonsensitivewithsp&quot;)]
  
public string GetNonSensitiveDataByNameWithSP()
  
{
  using (SqlConnection connection = new SqlConnection(_configuration.GetValue<string>(&quot;ConnectionString&quot;)))
  {
  connection.Open();
  SqlCommand command = new SqlCommand(&quot;SP_GetNonSensitiveDataByName&quot;, connection);
  command.CommandType = System.Data.CommandType.StoredProcedure;
  command.Parameters.AddWithValue(&quot;@name&quot;, Request.Query[&quot;name&quot;].ToString());
  using (var reader = command.ExecuteReader())
  {
  if (reader.Read())
  {
  string returnString = string.Empty;
  returnString += $&quot;Name : {reader[&quot;Name&quot;]}. &quot;;
  returnString += $&quot;Description : {reader[&quot;Description&quot;]}&quot;;
  return returnString;
  }
  else
  {
  return string.Empty;
  }
  }
  }
  
}
  

  当我们使用SQL Profiler运行这个方法时,我们可以看到以下运行。
  

exec SP_GetNonSensitiveDataByName @name=N'bart simpson'  

  如您所见,它与上面的参数化查询非常相似,我们的查询的实际细节是单独发送的。虽然现在很少看到一个围绕存储过程构建的整个项目,但它们可以保护您免受SQL注入攻击。

使用ORM
  现在下一部分是减轻SQL注入攻击的有趣部分。因为在某种意义上,它成为一个一站式的保护。但是我把它放在最后的原因是因为我认为最好能理解在保护你的ORM的基础上发生了什么。
  如果您使用的实体框架。当您运行Linq查询以获取数据时,任何linq“Where”语句将被打包为参数查询并发送到SQL Server。这意味着你真的需要走出自己的方式来打开自己,直到SQL注入,但这不是不可能的!几乎所有的ORM都可以发送原始的SQL查询,如果你真的想。看看Microsoft的这篇文章通过Entity Framework Core发送原始SQL。至少,使用ORM可以使SQL注入成为“默认”,而不是从外部添加一些东西。

赋予最低的权限
  还记得我们的drop table命令吗?如果你忘了,下面是:
  

SELECT * FROM NonSensitiveDataTable WHERE>  

  我们的网站真的需要删除一个表吗?不太可能然而,在我们的场景中,我们已经把王国大门的钥匙交给了外人让他去做任何它喜欢做的事。授予细粒度权限或最低权限级别是我们“停止”SQL注入攻击的最后一步。我把“停止”放在引号中,因为在现实中我们仍然容易受到敏感数据泄露的攻击,但是我们的攻击者至少不能删除表(但是它们仍然可以运行delete命令!)。
  大多数SQL系统(MYSQL,Postgres,MSSQL)内置SQL角色,只允许简单的读取和写入来完成,但不能修改实际的表模式。应尽可能使用这些角色来限制任何可能的攻击。

总结
  正如我们所看到的,SQL注入对于泄露敏感数据甚至是毁灭它可能是非常残酷的。但是我们也看到ASP.net Core 已经有了我们可以保护自己的方法。在依赖于输入解析/类型转换的过程中,我们可以使用参数化查询,来避免SQL注入。
  欢迎转载,转载请注明翻译原文出处(本文章),原文出处(原博客地址),然后谢谢观看
  如果觉得我的翻译对您有帮助,请点击推荐支持:)

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-424111-1-1.html 上篇帖子: MS SQL批量生成作业脚本方法介绍总结 下篇帖子: 转:MSSQL SERVER行转列 列转行
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表