The .NET Framework is Microsoft's primary enterprise development platform. It comprises a set of APIs for developing applications for desktops, servers, and the web. Its roots extend back to 2002 as a proprietary framework for Windows. But since then, it's transformed into a free and open-source framework for Windows, Linux, and macOS.
The .Net framework has been around for a very long time and is the enterprise framework for one of the most common operating systems in use. So, it has its share of exploits. But Microsoft and the open source community provide excellent support for the framework. As a result, you can write secure and safe applications by following Microsoft's guidelines and employing the same best practices as any programming framework.
Let's look at .Net's security features, some best practices for .Net developers, and how the framework fares against some of the most common security threats.
.Net Security Features
Principal and Identity Objects
When managed code runs under .Net on Windows, it can access Windows' identity and principal subsystem. So, .Net apps running on Windows have access to Windows security and role-based access control. But, .Net Core doesn't have the same level of access to user and authentication resources on Linux and macOS. Therefore, cross-platform applications need some extra help with authentication.
What .Net Core does have is the IAuthentication service. Applications can it use to access third-party authentication services such as Twitter, Google, and in-house OAuth services. In all cases, authenticating a user with the .Net framework creates a Principal object that's useful for operations like role-based security.
Role-Based Access Control
If you use .Net's authentication services, you get access to role-based access control (RBAC), too. The .Net framework has built-in support for RBAC. Used properly, RBAC will protect applications from many common attacks. Having support doesn't automatically make .Net secure, but having the behavior built-in means you don't have to write it yourself, and the functionality has been tried and tested.
.Net compilers compile code to Microsoft intermediate language (MSIL) for distribution. Then, a just-in-time compiler compiles it to native code at execution time.
Part of compiling MSIL to native code is a verification process that examines the code and its associated metadata. Microsoft confusingly refers to this check as "type safety," even though it's not related to the type safety enforced in programming languages.
MSIL code may only access authorized memory locations. This ensures proper isolation between modules and verifies that the runtime can enforce security restrictions.
System administrators can override this verification step on a specific piece of code or a systemwide basis. But, this is almost never a good idea.
Security Best Practices
Don't Override Code Verification
Our first best practice recommendation is not to override the "type-safety" verification check outlined above. While this check is not perfect, and it's even possible in rare cases for valid code to fail the check, running untrusted code is never a good idea. Supply-chain attacks on systems like Nuget make running untested and unverified code too dangerous.
If you must run untrusted code, take additional security measures such as running the application in containers or virtual environments where the unsafe code is isolated.
Verify User Input
If you don't carefully verify and sanitize user input, it can cause your application to misbehave. While .Net has mechanisms for verifying code that calls your application or library, you're on your own when it comes to user-specified information.
Here's a brief list of checks you should make against user data:
Always verify and sanitize URIs. Be careful of:
Very long paths
Any and all wildcards
Special paths, like file://, socket://, etc.
Token expansion (%token%)
Hexadecimal and Unicode character escapes
Nested escapes (%nn becomes %mmnn, where %mm is the escape for '%').
.Net's Eval() can execute any arbitrary code. Avoid it.
Beware of late binding that may point to user-specified data.
All of the common attacks we'll examine below involve malicious input.
Verifying and cleaning user input is one of the most important security precautions you can take.
Keep Your Packages up to Date
.Net has a mature and robust package ecosystem. This makes it easy to keep your dependencies up-to-date with Nuget. Make checking for updates a part of maintenance. Then, rebuild and test your code with the new libraries as part of your regular release process.
Most Common .NET Security Attacks
Finally, let's wrap up by looking at four of the most common .Net Security threats.
A SQL injection attack is when a malicious actor takes advantage of an application that doesn't properly sanitize its input. It leverages this weakness by coercing it into executing SQL statements. It's a very real threat, and an improperly coded .Net application is vulnerable to it.
You can read about SQL injection and how to protect your .Net application here.
Cross-site Scripting (XSS)
XSS is another type of injection attack. These attacks occur when an attacker tricks a website into running a harmful script by injecting it as—you guessed it—malicious input. XSS attacks usually leverage the <script> tag, hoping the site will accept and run it.
You can learn more about XSS and how to protect your .Net application here.
Cross-Site Request Forgery (CSRF)
Cross-site request forgery is a mouthful, but the name tells you exactly what it is. It happens when a forged request from a rogue website tricks an authenticated user into running harmful code. This attack relies on a user being logged in and having access to privileged information or resources, like credit card numbers or access to a bank account.
When this attack works, it can be devastating. Read more about CSRF and how to protect your .Net code from it here.
XML External Entities (XXE)
An XML External Entities attack leverages vulnerabilities in how an app processes XML. It's another type of injection attack. XML documents contain constructs that make it easy for apps to access external data. But, these mechanisms are dangerous in the wrong hands. So, an attacker can trick an application into downloading malicious code from another site. Or, it can trick a server into supplying sensitive information. Even worse, a properly crafted document can act as a denial-of-service attack by causing a server crash.
We have details on XXE attacks and how to address them in .Net here.
We started with .Net's security features. Then we discussed some development best practices. Finally, we wrapped up the most common .Net security threats and supplied links to articles that will help you address them. As you can see, securing .Net applications doesn't have to be hard.
With the right information and the correct tools, you can keep your code and your users safe.
Are you responsible for delivering fast, safe, and secure .Net solutions? With our Dynamic Application Security Testing (DAST) suite, you can take the next step. Our DAST tool runs security tests against your application while it's running. It'll identify potential security vulnerabilities and help you fix them. So, you'll have real-time, reliable, and detailed reports about the security status of your platform. The DAST suite ensures that you get the best insight and tools to provide reliable decision-making information so that you focus on delivering value,
You can check it out here.