Within the security industry, we often run into situations where providing immediate security guidance isn’t straightforward. For instance, a team may be using a new, cutting edge language that doesn’t have many existing security tools or guidelines available. If you are a small startup, then you may not have the budget for the enterprise security solutions. In large organizations, the process of migrating a newly acquired team into your existing tools and trainings may take several weeks. What advice can we give to those teams to get them down the road to security today?
In these situations, I remind them to go back to their original developer training. Many developers are familiar with the term “technical debt“ which refers to the “eventual consequences of poor system design, software architecture or software development within a codebase.” Technical security debt is one component of an application’s overall technical debt. The higher the technical debt is for an application, the greater the chance for security issues. Moreover, it’s much easier to integrate security tools and techniques into code that has been developed with solid processes.
To a certain extent, the industry has known this for awhile. Developers like prepared statements because pre-compiled code runs faster, and security people like it because pre-compiled code is less injectable. Developers want exception handling because it makes the web application more stable and they can cleanly direct users to a support page which is a better user experience. Security people want exception handling so that there is a plan for malicious input and because showing the stack trace is an information leak. However, let’s take this a step further.
If you search the web for “Top 10” lists for developer best practices and/or common coding mistakes, then you will see there’s a clear overlap in traditional coding principles and security principles across all languages. For example, the Modern IE “Cross Browser Development Standards & Interoperability Best Practices“ is written for developers and justifies these points using concepts that are important to clean development. However, I can go through the same list and justify many of their points using security concepts. Here are just a few of their recommendations and how they relate to security:
- Use a build process with tools to check for errors and minify files. On the security side, establishing this will enable you to more easily integrate security tools into the build process.
- Always use a standards-based doctype to avoid Quirks Mode. Quirks Mode makes it easier to inject XSS vulnerabilities into your site.
Switching to Ruby on Rails, here’s a list of the 10 Most Common Rails Mistakes and how to avoid them so developers can create better applications. When you look at those errors from a security perspective, you will also see overlaps:
- Common Mistake #1-3: Putting too much logic in the controller/view/model. These three points all deal with keeping your code cleanly designed for better maintainability. Security is a common reason for performing code maintenance. Often times, your response to active attacks against your system will be slowed down because the code cannot be easily changed or is too complex to identify a single validation point.
This section also reminds us that the controller is the recommended place for first-level session and request parameter management. This allows for high-level sanity checking before the data makes it into your model.
- Common Mistake #5: Using too many gems. Controlling your third-party libraries also helps to limit your attack surface and reduce the maintenance costs of keeping them up-to-date for security vulnerabilities.
- Common Mistake #7: Lack of automated tests. As mentioned in the HTML lists, using an automated test framework enables you to also include security tests. This blog refers to use techniques such as BDD for which there are also Ruby-based BDD security frameworks like Gauntlt.
- Common Mistake #10: Checking sensitive information into source code repositories. This is clearly a security rule. In this example, they are referring to a specific issue with Rails secret tokens. However, this is a common mistake for development in general. Separating credentials from code is simply good coding hygiene – it can prevent an unintended leak of the credential and permit a credential rotation without having to rebuild the application.
Even if you go back to a 2007 article in the IBM WebSphere Developer Technical Journal on The Top Java EE Best Practices, which is described as a “best-of-the-best list of what we feel are the most important and significant best practices for Java EE,” then you will see the same themes being echoed within the first five principles of the list:
- Always use MVC.This was also mentioned in the Rails Top 10. Centralized development allows for centralized validation.
- Don’t reinvent the wheel. This is true for security, as well. For instance, don’t invent your own cryptography library wheel!
- Apply automated unit tests and test harnesses at every layer. Again, this will make it easier to include security tests.
- Develop to the specifications, not the application server.This point highlights the importance of not locking your code into a specific version of the server. One of the most frequent issues large enterprises struggle with is migrating from older, vulnerable platforms, because the code is too dependent on the old environment.This concept is also related to #16 in their list, “Plan for version updates”.
- Plan for using Java EE security from Day One. The idea here is similar to “Don’t reinvent the wheel.” Most development platforms provide security frameworks that are already tested and ready to use.
As you can see, regardless of your coding language, security best practices tend to overlap with your developer best practices. Following them will either directly make your code more secure or make it easier to integrate security controls later. In meetings with management, developers and security people can be aligned in requesting adequate time to code properly.
It’s true that security-specific training will always be necessary for topics such as authentication, authorization, cryptography, etc. And security training certainly shows you how to think about your code defensively which will help with application logic errors. However, a lot of the low-hanging bugs and security issues can be caught by following basic good, old-fashioned coding best practices. The more you can control your overall technical debt, the more you will control your security debt.
Lead Security Strategist