.NET 开发人员必须遵守的 10 条安全应用程序准则
.NET 应用程序的安全性至关重要,但了解如何保护它并非易事。作为开发人员,我们必须清楚,不安全的应用程序可能带来严重问题:从修改应用程序的操作或窃取源代码,到使公司承担法律责任。
每个开发人员都清楚地应用了他认为对他的应用程序方便的安全性,而且我还想补充一点,实现这一点的可能性和方法是无限的。
但是,在开发 .NET 应用程序时,任何开发人员都应该遵循一套实践。遵循这些最佳实践将能够避免重大的应用程序安全问题。正因如此,我决定编写.NET 应用程序安全十诫。
1. 您退出时应删除cookies
我们使用会话来维护用户在访问期间的登录状态。在某些登录页面上,如果您勾选了某个复选框并选择不退出,则没有会话超时设置。
同时,AspNetCore.Session
cookie 被设置到浏览器中,以跟踪当前登录的用户。
退出时,请记住删除应用程序创建的 Cookies,因为黑客可能会在未经授权的登录中利用它们。
如果我们想覆盖默认的 cookie 会话,我们可以简单地使用SessionOptions,如下所示:
builder.Services.AddSession(options =>
{
options.Cookie.Name = ".AdventureWorks.Session";
options.IdleTimeout = TimeSpan.FromSeconds(10);
Options.Cookie.IsEssential = true;
});
使用的选项用于:
-
Cookie:确定用于创建 Cookie 的设置。
-
IdleTimeout:指示会话在其内容被放弃之前可以空闲多长时间。
-
IOTimeout:指示允许从存储加载会话或将其提交回存储的最长时间。
我不想在这里进一步展开,因为这个话题可以写成好几篇文章。我建议你去查阅那篇31分钟阅读的文章,里面有关于会话和cookie的所有信息,我建议你搭配一杯好咖啡(或者你喝的那种饮料😉)一起阅读。
2. 你永远不应该忘记XSS注入
跨站点脚本(XSS)是一种允许攻击者将客户端脚本注入网页的漏洞。
当您加载受影响的页面时,攻击者的脚本将会执行,从而窃取您的会话令牌和 Cookie,通过DOM 操作更改网页内容,甚至将您重定向到其他目标页面。跨站点脚本漏洞通常发生在应用程序接收用户输入并将其输出到未经验证的页面时。
最容易实施此类攻击的地方通常是:
- HTTP 标头
- 表单输入
- URL 查询字符串
第一个解决方案是使用正确的 HTTP 标头。HTTPX-XSS-Protection
标头将导致浏览器中启用脚本过滤器。此过滤器将阻止站点之间可能发生的某些 XSS 攻击。
一种方法是。这将触发 XSS 过滤器,对页面进行清理并删除不安全的部分:
X-XSS-Protection: 1;
也可以通过这种方式实现。添加mode=block
将启用 XSS 过滤,一旦检测到攻击,将直接阻止页面显示,而不是对其进行清理:
X-XSS-Protection: 1; mode=block;
我们还必须记住,用户插入的数据(在表单的情况下)必须是纯文本而不是 HTML,因为它可以被执行。
让我们看看正确和错误的方法:
不好的方法:
如果你仔细观察,你很快就会注意到发送的数据有可能被执行。
document.getElementById(“id”).innerHTML = “user data”;
好方法:
这样,输入的任何数据都将被解释为纯文本,无论他们如何努力注入代码,都不可能实现。
document.getElementById(“id”).textContent = “user data”;
这些方法在避免 XSS 攻击时非常有用,但如果您想深入了解这个主题,我推荐这篇文章,其中我仅讨论不同类型的跨站点脚本攻击以及如何避免它们。
文章已不再可用
3. 应避免直接连接数据库
显然,很多时候我们需要将应用程序连接到某个数据库。其中一种方法就是为我们的应用程序使用连接器。
问题是当连接器是纯文本时,让我们看这个例子:
string connectionString =
"datasource=dev.bytehide.com;
port=3306;
username=root;
password=secret;
database=test;";
MySqlConnection databaseConnection = new MySqlConnection(connectionString);
这种方式根本不安全。我们可以清楚地看到,任何有权访问我们应用程序的人都可以获取敏感数据,例如服务器、用户名、端口或密码。
如果您正在寻找一些快速解决方案,这里有一些可能有用的建议。
-
不要使用通用数据链接(UDL) 文件
-
使用Azure Key Vault 机密
-
加密配置文件
-
使用Windows 身份验证
当然,如果您希望数据获得最佳安全性,我建议您外包连接。
4. 不得在数据库中存储敏感信息
几乎每个 Web 应用程序都必须有一个数据库来存储用户数据。然而,黑客总是试图从数据库中窃取用户数据——有时甚至会攻击服务器本身,并获得未经授权的访问权限。如果有人未经授权访问您的数据库,他们就可以窃取其中的所有敏感信息,包括密码和信用卡信息。
这看起来像是一个笑话,但直到今天我仍然看到数据库以纯文本形式存储密码,所以这是一条戒律。
为此,您必须加密敏感信息,使其在数据库中不以纯文本形式存在。无论如何,常见的加密方法都无法达到密码保护的程度。对于敏感数据,最好先对信息进行哈希处理,然后进行验证,无需解密密钥,这样原始信息就无法被逆转。
如果你想深入了解密码哈希或任何类型的信息,我推荐这篇文章(非常完整):如何哈希密码
5. 你必须始终处理错误
开发应用程序时,谁也不想出错,但错误却总是会发生。错误几乎无法避免,但一旦发生,就必须知道如何正确处理。如果不这样做,错误可能会泄露内部信息,这可不是什么好事。
一个可能的解决方案是始终跟踪异常堆栈。最好使用throw;
而不是 ,throw e;
因为如果使用后者,那么在生产环境中它将返回空字符串。
try
{
FunctionThatMightThrow();
}
catch (Exception error)
{
logger.LogInfo(error);
throw new CustomException(error);
}
另一种可能且好的方法是始终分析检测到的错误。
如果您发现错误,请不要忽略它或置之不理而不予修复。这样做毫无意义,因为那样您将永远无法解决问题。如果您知道可能存在错误,并且希望在错误发生之前修复它们,请在可能发生错误的代码中使用try/catch块。
try
{
FunctionThatMightThrow();
}
catch (Exception error)
{
NotifyUserOfError(error); // Another option
ReportErrorToService(error);
}
由此可见,捕获异常可能是一个好主意,因为它会在控制台中与其他所有打印输出区分开来。如果我们将其封装在 try/catch 语句中,那么之后(如果发生错误),我们就可以制定计划来处理它,或者为此类事件设置代码路径。
如果你想更深入地了解在 C# 应用程序中处理错误的方法,我建议你阅读这篇文章:
文章已不再可用
6. 应避免 CSRF 攻击
跨站请求伪造(CSRF) 攻击是一种相当常见且危险的攻击类型。这类攻击基于一个漏洞,攻击者可以利用该漏洞接管用户会话,执行任何对其有利的操作(例如购物、转账等等)。
为了快速解释这一点,我们举个例子,假设一个用户拥有已登录的会话(cookies),并点击了恶意页面上的按钮。恶意网站上的按钮会向真实用户发出未经授权的请求。由于用户已登录,因此任何请求都是有效的。
使用AntiforgeryOptions,您可以通过添加以下方法轻松避免这种情况:
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
如果您想了解 AntiforgeryOptions 的所有可能性和选项,那么微软的这篇文章适合您:防止跨站点请求伪造攻击
7.不要忘记更新依赖项和库
这或许是防止安全漏洞的显而易见的方法,但遗憾的是,许多开发人员仍然没有这样做。在 .NET 中,我们依赖大量的库,包括微软的、用户自定义的以及NuGet 包中的库。
检查我们的应用程序使用的库可以提前告知我们任何漏洞或潜在风险,从而阻止安全漏洞的发生。
📚请记住:保持这些库保持最新是避免任何 .NET 应用程序中的漏洞的一种非常简单有效的方法。
留意所用框架的过时版本也至关重要,因为可能存在一些我们不知道的严重漏洞,需要立即关注,以免造成任何风险 - 这将使应用程序更安全,更易于维护。
为了实现这一点,根据NuGet 文档,您可以使用:
Update-Package
正如 NuGet 提到的:
将当前解决方案的所有项目中的所有包更新到最新版本。
这将确保你的解决方案使用的所有软件包都得到更新。
如果你想了解某个软件包的漏洞,我建议你使用Snyk 漏洞数据库。
8. 您应该避免点击劫持攻击
对于那些不知道点击劫持是什么的人来说,这是一种基于(大多数情况下)用户的无知来欺骗用户并迫使用户点击网页的另一个元素的攻击。
这会导致用户在不知情的情况下访问不受欢迎的网站、下载恶意文件、提供机密信息甚至转账。
避免这种情况至关重要,因为它会给访问我们网站的用户带来严重问题。我们绝不能允许任何域名与我们不同的网站在iframe中打开。在 ASP.NET 中,只需添加一个响应头并将其设置为拒绝,即可轻松实现这一点x-frame-options
。我来举个例子:
void application_beginrequest(object sender, eventargs e)
httpcontext.current.response.addheader("x-frame-options ", "deny");
这样,标头将始终添加到应用程序响应中,以避免任何可能的点击劫持攻击。
9. 应防止 SQL 注入
SQL 注入攻击利用一种漏洞,将恶意命令插入 SQL(结构化查询语言)查询中,利用 SQL 的动态特性突破数据的安全壁垒,使攻击者能够访问他们本不应查看或修改的信息。大多数公司对此类网络攻击缺乏足够的防御措施,因此了解 SQL 注入攻击的本质及其危险性至关重要,这样才能有效地防御此类攻击。
通过 SQL 注入注入命令,黑客可以改变数据库上发生的情况。让我们为那些不知道 SQL 注入如何工作的人看一个简单的例子:
假设我们有一个登录表单,其中要求输入用户名和密码,以便用户可以登录:
提交信息后,数据库中将执行类似如下的查询:
select id
from users
where username='$username' and password='$password';
假设查询是串联的,例如,如果user
我们在字段中输入root
(知道该用户存在)并且在password
字段中输入,'or '1'=1
会发生什么?我的意思是这样的:
会发生的情况是,密码字段中的参数会将 SQL 查询修改为如下内容:
Select id
from users
where username='root' and password=''or '1'='1';
结果呢?和往常一样true
,我们能够以用户身份登录root
。
解决这个问题的一个非常简单的方法是将值作为参数传递:
select id
from users
where username=@username and password=@password;
但除此之外,我始终建议:
-
验证输入:验证客户端和服务器端的输入,同时记得使用数据注释和正则表达式。
-
使用最低权限的数据库访问:为了确保数据库的安全,请移除权限,以确保任何人都无法更改敏感数据或执行某些操作。首先,限制与付款详情或交易相关的表的插入、更新和删除权限。接下来,确保任何人都无法访问包含敏感用户信息(例如密码或用户名)的表,因为这些条目可能导致账户被盗用。
-
使用 ORM(例如 Entity Framework):对象关系映射 ( ORM ) 使您能够与对象进行交互,就像它们直接连接到数据库一样,而无需了解任何有关后端的信息。Entity Framework是一个不错的选择。
10. 你永远不应该编写自己的密码学
一个不容忽视的安全事实是,没有一个开发人员知道如何设计出牢不可破的加密算法。即使你的团队尝试了多年却仍未找到完美的组合,也没关系——重要的是,你不会冒险。
这种“自制”的加密技术通常更容易出错,漏洞也更多,而不是真正保护应用程序的源代码。正如安全专家研究员Runa Sandvik在 Twitter 上所说:
“问为什么你不应该自己开发加密技术,就像问为什么你不应该设计自己的飞机引擎一样”——Runa Sandvik
就 .NET Framework 而言,有一个好消息。目前已经有不少混淆和加密算法的实现,但你必须小心使用其中一些,因为它们多年来一直没有更新,而且这些算法已经过时了——它们的混淆和加密可以通过互联网上的免费工具轻松删除。
这是一个非常严重的安全问题,因此我推荐使用云混淆器 (Cloud Obfuscator )。由于它可以通过 Web 面板进行保护,您甚至无需在计算机上下载或安装它(更无需更新)。我推荐的是Shield .NET 混淆器,这是一款非常优秀的云混淆器,具有军用级防护。此外,它还提供了一个Visual Studio 扩展,您可以免费试用,以便在编译时直接进行保护。此外,它还与 MSBuild 集成,可以部署已受保护的应用程序。
这是我汇编的 .NET 开发人员应遵循的安全实践,以在其开发中保持最低限度的安全性。
鏂囩珷鏉ユ簮锛�https://dev.to/bytehide/the-10-commandments-net-developers-must-apply-for-secure-applications-3gl3