Secure By Design
You don't need to be a security expert to write secure code. You can make your code more secure simply by following Domain Driven Design (DDD) practices.
I've been interested in security for quite a while. It started when I started my own business. The very first contract I signed had a clause that said "Must implement the latest and greatest cyber security best practices." Of course, I had no idea what those were, so I thought I better do some research. I've been listening to Security Now weekly ever since then. I've also read a handful of books and done some studying.
Should LabVIEW programmers care about security?
I feel like, as LabVIEW Programmers, we don't pay enough attention to security. I rarely hear it mentioned. Every time I bring it up, I get a response similar to: "Well our hardware is in a physically secure building and it is behind the company firewall, so I don't have to worry." We probably should worry a little more. Being behind a firewall and restricting physical access is good, but not sufficient. There are lots of threats out there, including insider threats, so we need to be more vigilant.
You Don't Need To Be A Security Expert To Write Secure Code
If I had to summarize "Secure By Design" in two sentences it would be this:
"You don't need to be a security expert to write secure code. You can make your code more secure simply by following Domain Driven Design (DDD) practices."
That is the treatise. The rest of the book explains why security is important and how things can go wrong using some eye-opening real-world examples. It explains the basics of DDD and how applying DDD can avoid many of these problems.
An example
You really should read the book, but here is an example to give you a taste of what the book is about. Let's start with a simple form that collects a piece of user-entered data. The book uses phone numbers and zip codes, but for our purposes, let's say it is the serial number for a part being tested. There is a popup with a text box. The user enters a serial number. The user hits ok. The test runs and the results get stored in a database. And for the sake of argument let's just say this particular tester exists in a place that is not under your control, such as say a contract manufacturing facility in another country.
What Could Possibly Go Wrong?
Well, there are a couple things that could go wrong here. For one, this data is getting stored in a database, so the obvious worry (if you are security-aware) is SQL injection (SQLi). With that, a user could access your database and do pretty much anything: retrieve data, destroy data, alter existing data, or even run arbitrary commands on your database server. Why would they want to do that? Any number of reasons. Maybe it's corporate espionage - the technician running the tester has been paid by some competitor to steal all your test data so they can reverse engineer your product. Or maybe, the manufacturer itself wants to alter some existing test records to hide some manufacturing problems and make some units pass that shouldn't so they can make their quota, or just erase evidence of failed tests to make the numbers look better.
The Normal Approach
The normal approach requires the developer to be aware of SQLi and sanitize the input data and/or parameterize their queries. This requires a lot of security knowledge. The developer needs to first identify that there is an issue, be aware of all possible characters or constructs that might cause an issue, and then write a sanitizing routine that removes anything that might lead to SQLi. Often you can avoid writing all that sanitizing code by simply parameterizing the query. Most databases and toolkits allow for parameterization.
Shortfalls Of The Normal Approach
Aside from the obvious knowledge and skill needed to avoid SQLi, there is another problem. These data files get uploaded to a server and there is a web application where another user can browse the data (think SystemLink or any other similar platform). The attacker-supplied serial number now gets displayed to whoever is viewing the data on the web platform.
Because this attacker-supplied data is now being loaded into a webpage, you must now worry about things like cross-site scripting (XSS). This is where someone injects a <script> tag or something similar to run arbitrary javascript in the user's browser. Even if you sanitized the data or parameterized the query correctly to avoid SQLi, you still have to worry about XSS. Your sanitization/parameterization routine probably didn't take this into account.
A Better Way
The book presents a better way to handle this situation using DDD principles. One of the DDD principles is not to use primitive datatypes like strings, but to replace them with domain primitives. Applying this technique, you would still have the text box for the user to enter some arbitrary data. You can't really get away from that (I guess you could write a Q Control if you wanted). But before you use that string anywhere you convert it into a domain primitive - in this case, a Serial Number object.
What is a domain primitive?
Well, a domain primitive is an object. The need for domain primitives comes from the fact that most primitive datatypes: string, int, float, etc. allow for a wide variety of data. For our serial number example, a string allows for an almost infinite number of possibilities. It could be an empty string, 1000 random characters, 1 billion random characters, 10 numeric digits, 5 letters, '--or 1; drop all tables', '<script> alert('XSS')</script>' or any other combination you can come up with. A domain primitive limits the possible values.
Creating a Serial Number primitive would involve taking that string primitive and applying some limits based on the problem domain to create a Serial Number object. There is some regularity to serial numbers for a particular product. Maybe it includes date codes, has a certain length, a certain valid character set, and a checksum to detect if it is valid. The DDD method is to not pass around a primitive string, but a validated Serial Number object.
How does that help security?
When you create a Serial Number domain primitive, you verify that the input string meets the domain rules. For example, for this particular product, a Serial Number is 10 characters total. It starts with a letter followed by eight numbers and then a checksum digit. Your database VI that creates your SQL query takes, not a string as an input, but a Serial Number object. That means that the Serial Number that is written to the database must conform to the rules for Serial Numbers.
Without knowing anything about security or even how this serial number is eventually being used, and simply using the domain primitive you avoid the SQLi and XSS attacks. There is no way for a letter followed by 9 digits to trigger either. By following good DDD practices, security comes along for free.
There's More
The book is full of examples of how applying DDD principles can avoid security risks. I highly suggest every LabVIEW developer read it. I found it very informative.
Help
If you'd like help making your code more secure, please reach out. I'd love to talk about how we can help.