Secure Coding Done Right.

Secure Coding Done Right

Security is one of the most important aspects of software development. Gone are the days when companies focused on the amount of code developers produce. Nowadays, they care about the quality and security of your code.   

 

The increasing number of security breaches over the past years is alarming. Too often, we hear scary stories about how millions of people’s personal information and financial records were exposed following a data breach. With this trend, every developer should focus on building more secure systems.

 

In this article, I will put together a list of practices that, in my view, offer a solid foundation for building more secure applications. Having worked with hundreds of developers in multiple companies for the past few decades, I’ve had the privilege to interact and learn a great deal from various development professionals.

 

So, here are my ground rules for writing more secure code. 

 

Secure By Design

 

Writing clean and secure code begins long before creating the first class or forming the first loop. When designing systems, I see some architects focusing more on the functional requirements but sidelining the security side of things. They tend to assume that access controls and other security measures will be implemented later in the development stage.

 

This is wrong. Instead, development teams should embrace the secure by design concept during application development.

 

During the design stage, prepare a list of technical and regulatory security requirements for your project. Think of every component that will be used in application development, from the class-level language to API endpoint authorization.

 

Having security in mind right from project inception is the best way to eliminate weaknesses inherent in the architecture of a product. Furthermore, it becomes harder to implement security controls or address vulnerabilities as the system develops. 

 

The most effective approach is enforcing security controls right from the design stage.

 

Model Threats to Your Code

 

Threat modeling is a cost-effective approach to implementing security in the application design phase. It involves identifying potential threats to software, analyzing their risks, and developing mitigations strategies to be implemented in the design, coding, and testing stages.

 

By modeling threats to your code, you can anticipate the kind of threats that may affect your application way before coding begins. For instance, if you deal with credit card numbers, personally identifiable information, or intellectual property, it will be easier to identify possible security risks and devise ways of protecting your application.

 

If you can imagine an attack on your code, you can keep the threat in mind when designing and implementing the system.

 

Don’t Trust User Data

 

If you look at the vast majority of software vulnerabilities, you will realize they share a common trait in that they stem from improper input validation. Think of SQL injections, cross-site scripting, LDAP injections, xPath injections, buffer overflow, uncontrolled string format, and other common security gaps.

So, I’ll insist on this – always treat all input as untrusted until proven otherwise. Sometimes being skeptical pays. As long as the data is coming from an external source, there’s every reason to verify it.  This should be done regardless of whether the input comes from environment variables, network interfaces, command line arguments, or user controlled files.

 

When developing a PHP application, for instance, you need to validate several elements. Here is an example class you can call to validate user input from your forms.

 

Implement the Principle of Least Privilege

Some developers give users access to all features and permissions they might need to avoid restructuring their code in the future. This leaves a pathway that attackers can abuse upon getting their hands on your system.

 

A good practice is to limit privileges by giving each account the appropriate (least) amount of privilege. Access within applications should be designed in a way that attackers are denied most functionalities. 

 

Ideally, base your access controls on permission as opposed to exclusion. In doing this, access is denied by default so that the protection scheme will determine the conditions under which access is granted.

 

 

Sanitize Data Sent to Other Systems

Data passed to an output subsystem may contain malicious content, especially if it originates from an untrusted source. If not escaped or sanitized properly, this data can be used to facilitate injection attacks. For this reason, output sanitization as vital as proper input validation to prevent attacks.

 

To prevent attackers from taking advantage of unused functionality in output data, always sanitize the data before invoking another system component.  

 

The only code that can identify malicious characters is the code responsible for output in a given context. This is where you should add a contextual escaping functionality before displaying data to the user.

 

For instance, when building SQL, you can use parameterized query features to ensure proper escaping:

 

 

Below is a simple non-compliant code that uses the Java MVC concept to display data to users without escaping or encoding it. The code below sends data to a web browser, which means it is subject to XSS and HTML injection attacks.

 

 

To fix this, I can create a ValidateOutput class that will normalize the output and sanitize it using a whitelist. Note that you can use a different whitelisting pattern depending on your output fields.

 

 

Adopt Secure Coding Standards

 

Every developer has been in at least one lecture about secure coding practices. It might get boring, but it’s important to safeguard your code. 

 

Some secure coding standards you should follow at every stage of the application development process include:

 

  • Avoid using language functions and other components with known security vulnerabilities.
  • Use proper encyprion techniques to protect user data.
  • Avoid revealing internal implementation through error messages.
  • Do not implement your own authentication and authorization system. Instead, consider adding an extra security layer through 2-factor authentication.
  • Effective monitoring and logging of user activity.
  • Scan and analyze your codebase for dependency vulnerabilities.
  • Stay on top of security releases.
  • Perform quality assurance checks through rigorous testing and source code audits.
  • Integrate the right security tools in your IDE, source repository, bug tracking systems, and other environments used during development.
  • Make necessary security documentation.

 

Wrap Up

 

Code security is the ultimate measure of code quality, and it’s not hard to achieve. I’ve seen most of my colleagues complicate stuff by overthinking secure designs. At the end, they have a strangely complex system that’s even harder to secure.

 

The best approach is keeping your designs as simple as you possible. This way, you can understand and prove the security of your system.

 

Embrace the above practices as you write your code. It’s a sure way of contributing to a safer world today.

 

Leave a Reply

Your email address will not be published. Required fields are marked *