The OWASP Top 10 is a standard awareness document for developers and web application security. It represents a broad consensus about the most critical security risks to web applications. In this article, I want to cover the first part of the TOP 10 vulnerabilities and how to protect against them using .NET. 1. Injection What it is? Almost any source of data can be an injection - vector, environment variables, parameters, external and internal web services, and all types of users. Injection flaws occur when an attacker can send hostile data to an interpreter. Injection vulnerabilities are often found in SQL, LDAP, XPath, or NoSQL queries, OS commands, XML parsers, SMTP headers, expression languages, and ORM queries. Injection can result in data loss, corruption, or disclosure to unauthorized parties, loss of accountability, or denial of access. What to do? SQL Injection Using an object-relational mapper (ORM) or stored procedures is the most effective way of countering the SQL Injection vulnerability. Use parameterized queries where a direct SQL query must be used. Practise Least Privilege - Connect to the database using an account with a minimum set of permissions required to do it's job i.e. not the same account Good example: sql = ; context.Database.ExecuteSqlCommand( sql, SqlParameter( , firstname), SqlParameter( , id)); var @"Update [User] SET FirstName = @FirstName WHERE Id = @Id" new "@FirstName" new "@Id" Bad example: strQry = + txtUser.Text + + txtPassword.Text + ; EXEC strQry string "SELECT * FROM Users WHERE UserName='" "' AND Password='" "'" // SQL Injection vulnerability! OS Injection Use to call underlying OS functions. System.Diagnostics.Process.Start System.Diagnostics.Process process = System.Diagnostics.Process(); System.Diagnostics.ProcessStartInfo startInfo = System.Diagnostics.ProcessStartInfo(); startInfo.FileName = ; startInfo.Arguments = ; process.StartInfo = startInfo; process.Start(); new new "validatedCommand" "validatedArg1 validatedArg2 validatedArg3" Use whitelist validation on all user-supplied input. Input validation prevents improperly formed data from entering an information system. ipAddress = ; (! .IsNullOrEmpty(ipAddress)) { (IPAddress.TryParse(ipAddress, address)) { address.ToString(); } { } } //User input string "127.0.0.1" //check to make sure an ip address was provided if string // Create an instance of IPAddress for the specified address string (in // dotted-quad, or colon-hexadecimal notation). if out var // Display the address in standard notation. return else //ipAddress is not of type IPAddress LDAP injection Almost any characters can be used in Distinguished Names. However, some must be escaped with the backslash \ escape character. The space character must be escaped only if it is the leading or trailing character in a component name, such as a Common Name. Embedded spaces should not be escaped. 2. Broken Authentication What it is? Attackers can detect broken authentication using manual means and exploit them using automated tools with password lists and dictionary attacks. Attackers have to gain access to only a few accounts, or just one admin account to compromise the system. Depending on the domain of the application, this may allow money laundering, social security fraud, and identity theft, or disclose legally protected highly sensitive information. What to do? Use . ASP.net Core Identity framework is well configured by default, where it uses secure password hashes and an individual salt. Identity uses the PBKDF2 hashing function for passwords, and they generate a random salt per user. ASP.net Core Identity Set a secure password policy services.Configure<IdentityOptions>(options => { options.Password.RequireDigit = ; options.Password.RequiredLength = ; options.Password.RequireNonAlphanumeric = ; options.Password.RequireUppercase = ; options.Password.RequireLowercase = ; options.Password.RequiredUniqueChars = ; options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes( ); options.Lockout.MaxFailedAccessAttempts = ; options.SignIn.RequireConfirmedEmail = ; options.User.RequireUniqueEmail = ; }); //startup.cs // Password settings true 8 true true true 6 30 3 true true Set a cookie policy services.ConfigureApplicationCookie(options => { options.Cookie.HttpOnly = ; options.Cookie.Expiration = TimeSpan.FromHours( ) options.SlidingExpiration = ; }); //startup.cs true 1 true 3. Sensitive Data Exposure What it is? Rather than directly attacking crypto, attackers steal keys, execute man-in-the-middle attacks, or steal clear text data off the server, while in transit, or from the user’s client, e.g. browser. The most common flaw is simply not encrypting sensitive data. When crypto is employed, weak key generation and management, and weak algorithm, protocol and cipher usage is common, particularly for weak password hashing storage techniques. Failure frequently compromises all data that should have been protected. Typically, this information includes sensitive personal information (PII) data such as health records, credentials, personal data, and credit cards, which often require protection as defined by laws or regulations such as the EU GDPR or local privacy laws. What to do? Use a strong hash to store password credentials. Enforce passwords with a minimum complexity that will survive a dictionary attack i.e. longer passwords that use the full character set (numbers, symbols and letters) to increase the entropy. Use a strong encryption routine such as AES-512 where personally identifiable data needs to be restored to it's original format. Use TLS 1.2 for your entire site. Have a strong TLS policy, use TLS 1.2 wherever possible. Ensure headers are not disclosing information about your application. Example for headers app.UseHsts(hsts => hsts.MaxAge( ).IncludeSubdomains()); app.UseXContentTypeOptions(); app.UseReferrerPolicy(opts => opts.NoReferrer()); app.UseXXssProtection(options => options.FilterDisabled()); app.UseXfo(options => options.Deny()); app.UseCsp(opts => opts .BlockAllMixedContent() .StyleSources(s => s.Self()) .StyleSources(s => s.UnsafeInline()) .FontSources(s => s.Self()) .FormActions(s => s.Self()) .FrameAncestors(s => s.Self()) .ImageSources(s => s.Self()) .ScriptSources(s => s.Self()) ); 365 4. XML External Entities (XXE) What it is? Attackers can exploit vulnerable XML processors if they can upload XML or include hostile content in an XML document, exploiting vulnerable code, dependencies or integrations. By default, many older XML processors allow specification of an external entity, a URI that is dereferenced and evaluated during XML processing. These flaws can be used to extract data, execute a remote request from the server, scan internal systems, perform a denial-of-service attack, as well as execute other attacks. What to do? Use LINQ to XML. Both the XElement and XDocument objects in the System.Xml.Linq library are safe from XXE injection by default. Use XmlDictionaryReader. System.Xml.XmlDictionaryReader is safe by default, as when it attempts to parse the DTD, the compiler throws an exception saying that "CData elements not valid at top level of an XML document". Using XmlDocument set XmlResolver to null. static void LoadXML() { string xxePayload = " " + " &win; "; string xml = " " + xxePayload; XmlDocument xmlDoc = new XmlDocument(); // Setting this to NULL disables DTDs - Its NOT null by default. xmlDoc.XmlResolver = null; xmlDoc.LoadXml(xml); Console.WriteLine(xmlDoc.InnerText); Console.ReadLine(); } <!DOCTYPE doc [<!ENTITY win SYSTEM 'file:///C:/Users/testdata2.txt'>]> < > doc </ > doc <?xml version='1.0' ?> Use XmlNodeReader. System.Xml.XmlNodeReader objects are safe by default and will ignore DTDs even when constructed with an unsafe parser or wrapped in another unsafe parser. Use XmlReader. System.Xml.XmlReader objects are safe by default. Use XmlTextReader. In .NET Framework versions 4.5.2 and up, XmlTextReader's internal XmlResolver is set to null by default, making the XmlTextReader ignore DTDs by default. Using XPathNavigator give it a safe parser like XmlReader (which is safe by default) in the XPathDocument's constructor. XmlReader reader = XmlReader.Create( ); XPathDocument doc = XPathDocument(reader); XPathNavigator nav = doc.CreateNavigator(); xml = nav.InnerXml.ToString(); "example.xml" new string Use XslCompiledTransform. System.Xml.Xsl.XslCompiledTransform (an XML transformer) is safe by default as long as the parser it's given is safe. 5. Broken Access Control What it is? Exploitation of access control is a core skill of attackers. Access control is detectable using manual means, or possibly through automation for the absence of access controls in certain frameworks. Access control weaknesses are common due to the lack of automated detection, and lack of effective functional testing by application developers. The technical impact is attackers acting as users or administrators, or users using privileged functions, or creating, accessing, updating or deleting every record. What to do? Ensure cookies are sent via httpOnly: CookieHttpOnly = , true Reduce the time period a session can be stolen in by reducing session timeout and removing sliding expiration: ExpireTimeSpan = TimeSpan.FromMinutes( ), SlidingExpiration = 60 false Protect LogOn, Registration and password reset methods against brute force attacks by throttling requests (see code below), consider also using ReCaptcha. [ ] [ ] [ ] [ ] HttpPost AllowAnonymous ValidateAntiForgeryToken AllowXRequestsEveryXSecondsAttribute(Name = , Message = , Requests = 3, Seconds = 60) "LogOn" "You have performed this action more than {x} times in the last {n} seconds." Task<ActionResult> ( ) public async LogOn LogOnViewModel model, returnUrl string Authorize users on all externally facing endpoints. The .NET framework has many ways to authorize a user, use them at method level: [ ] [ ] Authorize(Roles = ) "Admin" HttpGet ActionResult ( ) [Authorize] class UserController public Index page = int 1 // or better yet, at controller level: public When you have a resource (object) which can be accessed by a reference (in the sample below this is the id) then you need to ensure that the user is intended to be there { user = _context.Users.FirstOrDefault(e => e.Id == id); View( , UserViewModel(user); } { user = _context.Users.FirstOrDefault(e => e.Id == id); (user.Id != _userIdentity.GetUserId()) { HandleErrorInfo error = HandleErrorInfo( Exception( )); View( , error); } View( , UserViewModel(user); } // Insecure ActionResult ( ) public Edit id int var return "Details" new // Secure ActionResult ( ) public Edit id int var // Establish user has right to edit the details if new new "INFO: You do not have permission to edit these details" return "Error" return "Edit" new P.S. Thanks for reading! Part two coming soon. Read more about OWASP - https://owasp.org/www-project-top-ten/