Ensure your safety net for software applications

Software can be seen as a virtual world, where real life assets, like houses or roads, can be visualized in the software applications. An application can be understood like a house and the integration connections between different applications can be imagined as roads. Application security can be thought of in similar ways to the protection ensured by people for their houses, like doors with locks, or the protection offered for the money and legal documents being transported in wallets or briefcases while people are walking on the roads.

Author: Nicoleta Scrimint, Technical Lead

In order to be safe with the people's physical goods or with the digital data of the software applications, prevention is key, since like in all domains, to prevent is less expensive than to repair. For software developers, it is important to learn what are the possible security threats and what security prevention means, which is a continuous learning process, since the creativity of security attacks is growing. As part of the learning curve, reading the book "Alice & Bob learn Application security" by Tanya Janca, can be a valuable step.

Nicoleta Scrimint

Technical Lead

The book states that “the CIA Triad (confidentiality, integrity and availability) is the reason IT Security teams exist. Confidentiality is about keepings things safe, Integrity means accuracy and Availability refers to being able to access the systems in the accepted amount of time”.

The following article contains a brief summary of some useful ideas from the book, alongside security practices from my experience, which emphasize the benefits of the book recommendations.

Book recommendations: benefits and insights from experience

Assume Breach and Zero Trust: Prepare to detect and respond quickly to possible security threats

Practical Insights

  • Log all errors, log with Info or Debug level for complex routines in order to diagnose advanced use case scenarios.
  • Analyze beforehand the security impact of user actions, like providing big loads of data or big-size files that need to be stored somewhere and could bring the system down.
Defense in depth for having multiple levels of security: Protect the applications in different edge scenarios: user mistakes, man-in-the-middle attacks, bugs on different application layers

Practical Insights

  • Use secure communication through HTTPS connections
  • Authentication and authorization on both Web app and Web APIs levels
  • Input validation on the levels: Web app, Web APIs, database
  • Test the multiple levels of security by having automated tests that run automatically in the automatic deployment pipelines after a commit was made on the source code branches, e.g., GIT. Tests can be of multiple types: unit and integration tests made by developers; functional end-to-end, security, load, and performance tests made by functional testers and penetration testers.
  • Ensure backups of the databases.
Least privilege: Prevent SQL injection attacks or control of file system

Practical Insights

  • Create Oracle database user schemas or SQL Server users with minimal permissions.
  • Save incoming files in locations different than the application installation folders.
  • Use service accounts with minimal permissions to run background processes or web hosting processes.
Supply chain security: Minimize the cost of maintenance for the software

Practical Insights

  • Use the functionality from the base framework, e.g., HttpClient and IHttpClientFactory from .Net, instead of a NuGet package to communicate with REST services through HTTP protocol if the built-in library offers good enough functionality for the purpose. Using a third-party solution, e.g., a NuGet package, means a bigger attack surface and additional time for code maintenance when updating the package, which is mandatory to prevent security vulnerabilities and to be in sync with the latest technology updates and performance improvements.
  • Ensure usage of programming frameworks with long-term support and security focus.
  • Maintain up-to-date dependencies, e.g., NPM and NuGet packages, by using an automated tool like RenovateBot.
Attack surface reduction: The smaller the application, the smaller the attack surface

Practical Insights

  • Write a good enough size of code to implement the business or non-functional requirement. Writing less code is better. Less code is easier to understand.
  • Make an inventory of the maintained applications and remove the unused applications or functionality which the users do not use
  • Do not deliver experimental code if it is not tested properly
  • Practice continuous refactoring in order to reduce technical debt and to use the latest .Net updates, which helps in writing less verbose code
  • Remove unused dependencies
  • Do not send related information for technical frameworks/libraries in the Web API service response errors in order to limit the attack surface in case the framework version has open vulnerabilities.
  • Make an inventory of the used open-source libraries and versions in order to know if a related vulnerability impacts the maintained applications.
  • Take into account race conditions when implementing use case scenarios that compete for resources in parallel in order to prevent unexpected business behavior, e.g. 2 bus messages with the same content are processed at the same time.
  • Include in the automated continuous integration pipelines DevOps tasks with security concerns, e.g. tasks that verify the health of the used open source libraries or tasks for checking/including web security headers.
Avoid hard coding: Keep the secrets confidential from attackers

Practical Insights

  • Configure the database connection strings in encrypted settings in configuration files or secret management tools.
  • Configurable settings make it easier to use a different database or service bus since a new code compilation is not needed. Settings can have a lifetime scope per request so that new settings are read from the configuration files or from a third-party service, when a new web request is initiated.
Never trust, Always verify: Ensure the integrity of the data incoming from systems with which our application integrates with

Practical Insights

  • Integrate with third-party systems through authentication mechanisms before exchanging data, e.g. authentication tokens or certificates
  • Perform data validation for being the expected type, size, content. For complex validations, e.g. email, existing implementations/recommendations can be used, like the Angular email validator.
  • Prevent saving data with XSS injection.
  • Make use of the accepted list of possible input values.
  • Use ORM (Object relational mapping) libraries which use parameterized SQL queries and commands and, thus, prevent SQL injection attacks
  • Prevent sensitive data in URL parameters since they can be logged and they are visible to possible attackers
  • Verify imported data through hashed check values
  • Perform proper business validations for incoming data in relation to the existing data, e.g. a student can enroll in a course when he passed a specific exam.
  • Implement security web headers to protect web applications that are accessed from a browser.

The security recommendations from the book follow the shift left security direction towards building proactively secure software, which is a challenge, since the developers need to learn secure coding practices while building functional requirements with a release deadline. This challenge can be addressed by proactively learning secure coding skills through reading books, following courses, joining workshops or conferences, having a mentor, writing an article, sharing a technical topic at a meetup event in the community or on the job. Security penetration test results, output of static code analysis tools, open source health tooling, regression functional testing can help in finding and fixing security issues before the application is released.

Regarding big impact or high risk features, developers can have open discussions, also known as threat modeling, with security and DevOps colleagues, delivery consultants in order to take into consideration from the design moment any security or delivery aspects which might impact the development decisions and implementation time. By including security requirements in the design phase of the software lifecycle, the application is built iteratively with security in mind.

References: