The goal of application security is to consistently write bug-free software (or at least reasonably bug-free software). The security industry generally knows how to write bug-free software. Modern Software Development Lifecycle (SDLC) policies can mitigate the vast majority of common vulnerabilities if followed properly. NASA has published their set of standards, which allows them to have a high degree of confidence in their software in contexts where mistakes could be costly (in dollars and lives).
Thus, the question arises: if we know how to write secure and reliable software, why don't we? My answer is that these practices, while effective, are inefficient and not feasible in a competitive marketplace. These can be more effectively rolled out while maintaining developer productivity, yet opportunities for human mistakes remain.
The solution is not in writing more code. In fact, I believe that there is too much code in the world. In addition to scaling bug-free development practices, I see writing less code as a meaningful solution to security and productivity.
Do It Once, Do It Right
I frequently use the phrase "do it once, do it right." It was the core of my robotics team's transformation to a culture of quality. Any time someone needed some code:
- It should only be written in one place
- It should be written properly (following standards and policies) the first time, rather than getting it working and then trying to fix it later
This approach is commonly used throughout industry. At the simplest layer, someone might refactor a common set of instructions to a function if it ends up being used several times in a project. When you take it one step further, you might have inner source, where common functionality is shared between different teams. However, for most organizations, the code they write remains internal.
There is no reason why do it once, do it right can only apply within an organization. The rise of Open Source libraries, and especially package management, has helped turn this philosophy from internal to external. By some estimates, between 70% and 90% of the code in web and cloud applications are Open Source libraries. This has enabled unprecedented productivity among developers. Some companies, such as Amazon's AWS, have also been able to commercialize this philosophy, which has enabled AWS to be Amazon's single most important business unit.
How To Write Bug-Free Software
The key to writing bug-free software is to slow down and be careful. Standardized workflows and extensive preparation work can significantly increase the quality and security of a codebase. Software Development Lifecycles (SDLC) can, in a vacuum, be highly effective. The problem I have with SDLCs is that externalities severely blunt their effectiveness.
Software is a highly competitive and fast-moving market. The amount of time to train an entire team of developers to be experts in secure code development would put production behind schedule, and likely allow competitors to surpass. The amount of additional overhead needed to follow SDLC for every line of code written would make development much slower than competitors, and thus could be an existential threat to the business.
Except in very specific scenarios (where reliability is critical, and the market is uncompetitive), the goal of bug-free software will be nearly impossible to realize in practice. The return on investment is terrible, and the external facts make it nearly impossible to scale. Thus, the question arises: what should you do to have bug-free software at scale?
Write Less Software
Open Source has been at the center of the rapid innovation, and I see it as the key to scaling application security. While the return on investment for bug-free software may not make sense for an individual product, when you scale it to millions of products, the return on investment becomes more tolerable.
While there are certainly supply chain risks, I believe that Open Source has been a massive net positive for application security, as it has allowed experts to write many libraries for high-risk procedures. Though the risks in the libraries remain, the greater risks now are with how the libraries are called.
Looking to the future, the key to resolving this issue is continuing to build libraries and higher level abstractions. Higher level abstractions generally offer fewer opportunities to incorrectly use a library, while also making developers even more efficient. I am a strong believer in the power of natural incentives: that if you want someone to perform a task a certain way, you should position that path as in their individual self-interest. High-level libraries performing critical tasks securely will achieve that goal, and have security and developers aligned rather than opposed.
Inverting The Relationship with Libraries
If libraries are already such a large part of codebases, where do we go from here? Libraries are still typically called from code. This brings a lot of boilerplate code along, which opens opportunities for mistakes. I think that this relationship will invert, with libraries having long configurations, and then having callback to developer-provided methods when needed.
Most software problems have already been done before. With few exceptions, most web applications are very similar to each other. I write many CRUD (create, read, update, delete) APIs. While libraries can help me with handling web requests, JWT authentication, and even database queries, there are still thousands of lines of repetitive code every time I want to build a new API.
There is no reason why I shouldn’t be able to provide a schema (potentially with some metadata controlling class relationships, visibility, authentication, etc.) and instead only provide callbacks for when certain operations are run. There is no reason why that couldn’t also be bound to a simple UI generator, maybe that could be customized with CSS variables. Subsequently, why not have one line authentication bindings to either username/password or LDAP?
This is the direction that I see software going. Most web apps could likely get to 99% shared functionality easily, with some small customization for specific features. Then, as needs evolve, components could be swapped out for lower-level abstractions that offer more customization.
We are likely still years out from this being the case, and it will take enterprises willing to invest in Open Source to realize this goal. However, I believe that this inversion will make applications much more secure, developers much more productive, and allow more innovation to happen with a smaller workforce.