ASP.NET Core中的OWASP Top 10 十大风险-失效的访问控制与Session管理
不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址
在我们之前关于OWASP Top 10的文章中,我们讨论了SQL注入。SQL注入有一个非常明确的解释和例子,但这次我们讲的个关于“失效的访问控制和Session管理”有一个更开放的结尾。它涵盖了从糟糕的密码存储系统(纯文本,弱哈希)到通过Session暴露用户的所有内容(例如,URL中的Session字符串),我们演示的所有方法都是相对简单的,例如超时验证session。
和往常一样,虽然我们在这里讨论的话题是如何保护ASP.net Core应用程序让它有个好的开始,但这绝不是我们保护道路的尽头。特别是当涉及到密码的哈希时。这是一款总是与最新的威胁保持同步的游戏,我们需要时刻更新我们的的应用程序。
让我们开始吧!
密码哈希化
不言而喻,存储在数据库中的所有密码应该被哈希化并且具有单独的salt(稍后更多关于单独的salt的信息)。在任何情况下,密码都不能以纯文本形式存储。当您存储纯文本密码时,您不仅会冒着被黑客攻击的风险,而且网站上的用户帐户可能会被盗用,但由于人们倾向于在多个网站上使用相同的密码,所以在他们使用的每个网站上,你都有可能成为用户痛苦的来源。
使用 ASP.net Core Identity
如果您使用ASP.net Core Identity框架,你将会有安全的密码哈希和使用的单独的salt。Identity使用PBKDF2哈希函数来输入密码,并且它们会为每个用户生成一个随机salt。理想情况下,如果你不确定你在做什么,那就现在开始使用吧! 微软在启动和运行框架方面确实有很好的文档.。
让我们开始动手吧
虽然现在开始使用ASP.net Core Identity框架是绝对可取的,但有时你需要自己动手。但你自己动手的版本只能扩展C#代码用来验证,在任何情况下你都不应该“发明”自己的哈希算法来存储密码。
OWASP建议使用4种不同的单向哈希函数来存储密码。他们分别是Argon2,PBKDF2,scrypt和bcrypt。如果你打算编写你自己的认证层,你必须使用其中的一个。
什么是Salt?
Salt是在哈希之前向您的密码添加随机字符串的行为。这样,即使相同的密码被哈希化,所得到的哈希值将会不同...是不是有些疑惑?我们用一个例子。本例中我将使用PBKDF2哈希函数。
比方说,我正在使用密码 apples4tea 。当我哈希化密码时我得到的结果: 09ADB1C51A54C33C11CD3AE113D820305EFA53A173C2FF4A3150B5EC934E76FF
。现在,如果第二个用户注册到我的网站并使用相同的密码,他们将得到完全相同的哈希值。您可以在这里使用PBKDF2在线计算器来自己测试。为什么这不好?因为这意味着任何黑客基本上都可以“预先计算”密码哈希值(例如,现在就拿一个最流行的密码列表),然后在数据库中简单地进行字符串比较。
在此基础上,这意味着共享相同密码的所有用户具有相同的哈希值。当一个用户的密码被“破解”或者甚至被猜出时,任何使用相同密码的人现在也都泄露了他们的密码。
现在我为用户添加一个随机Salt值,我将它连接到密码的开始处。第一次我的Salt值是 H786Bnh54A
。哈希化后H786Bnh54Aapples4tea
的完整字符串 给了我 DfsjpycJwtWkOu8UcP8YXC / G09HES8LU + kku0iSllO4 =
的哈希值 。另一个用户注册到该站点,并随机生成一个Salt值给他们 76HNhg67Ac
。现在我们使用相同的密码对salt进行哈希化,最后得到一个哈希值 RP62 + SmFCJLeQzROTtk5HpMId0zuFtsPeBFuBLpH / Sc =
。现在我们有相同的密码,但有不同的哈希值。
众所周知,Adobe在2013年有一个巨大的数据泄露,泄露了用户的密码。密码并不是每个用户都加了Salt值,最糟糕的是,所有密码提示都存储在密码的旁边。也就是说,如果一个提示帮助您猜测一个用户密码,那么使用相同密码的任何用户在数据库中都会有相同的哈希值! Sophos在这里做了一个很好的报告.
如果你使用的是ASP.net Identity,那么salt会和密码一起存储在数据库中的同一列(因为salt每次都是相同的长度,所以我们只把这些字符当作salt来计算,其余部分就是哈希值)。在先前的ASP迭代中(在.NET完整框架中),salt存储在一个单独的列中。然而只要每个用户都有salt,而不是整个应用程序范围内拥有,就都可以。
暴露Session标识符
在以前的ASP.net版本中,你可以有一个“无cookie”的session。然后,您会看到与以下网址相似的网址:http://www.example.com/(S(lit3py55t21z5v55vlm25s55))/orderform.aspx
。会话数据实际上包含在URL中而不是cookie中。由于多种原因,这造成了严重的后果。想象一下把这个URL发给一个朋友,现在他们可以访问你的会话数据!更糟糕的是,如果您点击此页面上的任何出站链接,引用链接头将被设置为包含您的session。
在ASP.net Core中无cookie的sessions实际上从来没有实现,所以你不会看到这样的URL。但这并不意味着人们不会用自己的方式实现类似的东西。简而言之,通过任何方式给予另一个用户的URL都不能突然冒充用户。
通过未加密的连接发送数据
实际上有一个关于加密连接的完整的OWASP Top 10文章,但是这里值得特别提一下。即使你的密码全部被用户salt哈希化,而且你也不会在URL中暴露Session标识符,但是如果你容易受到“中间人”攻击的话,这意味着根本没有安全。一个用户连接到一些不可靠的开放wifi,可能意味着他们在登录时无意中泄露了我们的明文密码。
SSL意味着您从用户计算机到服务器进行加密,无论它需要什么路由 - 包括狡猾的wifi。鉴于免费的SSL提供商如Let's Encrypt的出现,甚至像Cloudflare这样的网站提供免费的SSL。没有理由不利用SSL来保护您的用户。
锁定,超时,等等
最后,我们在本文中已经讨论了ASP.net Core Identity。但我想再次指出的是,良好的习惯对这有多大的影响。我们来看看通常放置在您的Configure Services方法中的Identity的设置。
services.Configure<IdentityOptions>(options =>
{
// Password settings
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = true;
options.Password.RequireLowercase = false;
options.Password.RequiredUniqueChars = 6;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
options.SignIn.RequireConfirmedEmail = true;
options.User.RequireUniqueEmail = true;
});
看看你在这里的选项。有很好的密码执行选项(尽管你可以提出一些论点:但不要过分要求像字母数字这样的东西,因为人们倾向于把它们写在纸上...),如果他们锁定用户帐户不断输入错误的密码,甚至需要电子邮件确认(这也是身份框架的一部分)。
而在cookies如何存储在用户机器上,我们有这些选项:
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.Expiration = TimeSpan.FromHours(1)
options.SlidingExpiration = true;
});
又一次很棒的实践。用户cookie在默认情况下应该总是有一个过期值。一个来自OWASP的例子甚至明确指出了在攻击的例子中公共计算机session超时的问题:
在此基础上,我们应该尽可能使用HttpOnly cookie。当一个cookie被设置为HttpOnly时,这意味着它不能通过Javascript访问(因此,可能存在XSS漏洞),并且只能在作为请求的一部分发送时才能被访问。
我之所以使用这些例子,是因为它们是在进行身份验证和session管理时最佳实践指南。即使您决定自己动手,您也应该调查Identity给您的是什么,这样您就可以复制一些或所有的功能,并且始终保持对框架最新的的改进。
总结
身份验证和session管理是一个广泛的话题,我认为它被一些呆滞的遗留应用程序所困扰。通常,当我向新的开发人员展示诸如session标识符之类的东西时,他们无法想象为什么有人会这样做。“人们真的认为那是安全的吗?”这是我与之合作的一名初级开发人员的和我说过的话。我认为这是这个话题的本质,我们需要站在新安全的前沿,在认证和使用session的时候,我们要保持领先
欢迎转载,转载请注明翻译原文出处(本文章),原文出处(原博客地址),然后谢谢观看
如果觉得我的翻译对您有帮助,请点击推荐支持:)