A plea to security pros
Dip your toe into best-practice engineering when building your next open-source tool
Modern cybersecurity tools are on a painstakingly slow journey to simplify - something that has come faster in other areas of technology - but has been adopted slower with security tool developers.
Why is this?
The people who know how to use the tools aren’t the same as those building them. So tools either end up being too simple and don’t work well or they work wonderfully but are crippled with complexity.
For proof, look at nearly any modern open-source cybersecurity tool on GitHub.
If the tool was built by security pros, it has a greater than normal chance of being exceedingly complex to install and use, nevermind chock full of quality assurance bugs. If you really want to test the efficacy of a given tool, after installing and using it normally, try using it on another browser or operating system, which is often an effective way to cough up routine issues.
I would never criticize an open-source project - as creating tools for open-source is a great thing - but I instead want to draw attention to the overall lack of best-practice engineering. This is a solvable problem. Because the security industry relies on open-source more than other sectors of technology, it's critical the tooling available starts to shift toward a higher level of quality.
In talking with many security pros, I've heard the same rationale over and over again: "I'm not a programmer." That is true in one sense and false in the other. The truth is, as someone pushing out a tool that others will rely on, you are indeed a programmer. In fact, you may be a really popular one, depending on the following of your tools.
Job titles in technology have gotten watered down in recent years, losing most of their value. Traditionally, there have been software engineers, senior software engineers (those with 5+ years experience) and principal software engineers (those with 10+ years under their belt). In security, job titles are even more evasive. There are red-teamers, blue-teamers, malware analysts, engineers, intelligence analysts and... the list goes on.
Each category has a mixture of junior, senior and principal levels, often unpredictable in terms of skill sets, as experience often isn’t a determining factor for a promotion. Because there are more job openings than workers, companies often feel pressured to promote an individual before they're ready, compounding an already compounded issue.
Among this group has emerged a new breed of security worker: the cyber security engineer. These engineers are supposed to bridge the gap between security and engineering. Ideally, these engineers will know best-practice software engineering and operational cyber security.
Cybersecurity engineers are the next revolution of technology workers. As security relies more heavily on coding, programming knowledge will become required not optional - for all security workers.
When designing open-source security projects, you don't need to have a computer-science degree or extensive time with an IDE to adopt basic principles. Let's examine two design patterns which can be used to create great software.
Model-view-controller, or MVC as it's often referred to, is a design pattern that has been accepted as best practice in engineering for decades.
Designing your code with MVC means dividing it into three logical parts, each available behind an interface:
Model: The data layer. This is the code which manages the storage and retrieval of the data that powers your system. Whether your data is in a traditional database, only available in RAM or based on the file-system, the model should be the only part of your code that accesses it.
View: The visualization layer. The view could be a GUI for a website or a chart that you want to display to an end user. Or it could be the terminal interface to your program.
Controller: The logic layer. The controller should sit between your model and view and handle the "business logic" of your system. This crunches the data and runs your algorithms. This is the meat of your system. There should be an interface into it (which the view uses) and it should use an interface (to get data from the model).
Micro-services, sometimes referred to as service-oriented-architecture (SOA), is a design concept which arranges all code in an application into loosely coupled "services". A service is an independent module or part of hte code which does a category of work. Sound generic? It's supposed to be. There is no single definition of micro-services, as it has many common design implementations.
To visualize a micro-service application, consider this example:
An API may have endpoints for storing, for accessing and updating data. You may design a service which has three service classes, one for each use. The code could easily be written into a single class but you may split it out to create smaller modules which are focused on a single thing. This design pattern will help you swap out components, say the access data service, without impacting the other services in your application.
A few principles to guide you
Whichever design pattern you apply, there are a few best-practice engineering principles you should keep in mind. These principles are taught in most computer science curriculum - but I'll pull out the ones you should dwell on when designing your own software
Don't Repeat Yourself (DRY). This is simple, if you write code, don't rewrite it somewhere else in your application. Instead figure out a way to reuse it.
Keep It Simple Stupid (KISS). Another simple principle. If someone else cannot read your code, keep rewriting it until it is the simplest version of itself.
You Aren't Gonna Need It Again (YAGNIA). This one is a little tougher to grok. Most programmers overbuild when writing software. They add every getter, every setter and attempt to cover all bases at once. Fight this urge and instead write only the code you are using. With code, less is more. A project with 2,000 lines of code (LOC) is easier to understand than one with 20,000, all else being equal.
SOLID. This is an overarching concept that contains several principles. It stands for: Single Responsibility (every "thing" should have only 1 responsibility), Open-closed (software should be open for extension but closed for modification), Liskov substitution (an inherited class should complement not replace a base class), Interface segregation (code shouldn't be forced to depend on methods it doesn't use), Dependency inversion (always code against interfaces, not implementations).
With the emergence of the cyber security engineer job title, there is a real chance that open-source tools start to shift from proof-of-concept innovations to extendable, scalable solutions.
In designing code like a software engineer, each module we write becomes a building block for future work. This focus on design will allow more reuse of security tools which in turn enables faster development for the tools that keep us safer.
Cybersecurity is powered by community. Just imagine how much good the community can do if it's focused on solving the real problems, not on rewriting software.