BSD, C, httpd, SQLite

% vi main.c
You've deployed BCHS. Your editor is open.
Where do you begin?

Don't just write C. Write portable and secure C.

Anybody can write crappy, bug-ridden and insecure code. In any language. Good news: with C, it's even easier! So familiarise yourself with common (and common-sense) pitfalls noted in the SEI CERT C coding standard and comp.lang.c FAQ.

To encourage sharing, consider style(9) as a guide for the style of your C code. It makes a significant difference when bringing on victims^Wfellow programmers!

Be familiar with CGI and FastCGI.

If you don't want to parse content by hand—and you really, really don't—let a library do it for you. Install and use kcgi or fcgi from packages.

Caveat emptor on FastCGI. Be careful! CGI scripts run by slowcgi(8) already have their privileges dropped and file-system constrained. With FastCGI, you'll need to use a framework that does so for you!

Get to know your security tools.

OpenBSD has pledge(2). Embrace the pledge.

Your application will be under assault every moment it's running. And it will have bugs: limit the damage caused by inevitable mistakes by constraining (sandboxing) the environment available to your application. Oh, right: there's also chroot(2), dropping privileges, etc…

For more on these security tools, see Secure CGI.

Databases: simplicity rules.

Spend time carefully reading through the SQLite documentation. For a simpler API (and some significant security features), consider using ksql(3). Most folks knee-jerk into needing the biggest Oracle or NoSQL database they can find. But for most applications, it's perfectly alright to start with SQLite and vanilla SQL, then slowly expand as necessary. The usual path is from SQLite to PostgreSQL.

Static source testing.

Statically scan your binary with LLVM (from packages). There's also frama-c and splint, both also in packages.

These static analysis tools can help catch source-level bugs. An alternative compiler (LLVM) can also prevent you from relying too much on gcc(1)'s extensions, which reduces portability.

If your project is open source, you can register it with Coverity, too.

Dynamic source testing.

Run your application under valgrind (from packages) and make sure your malloc.conf(5) flags are unforgiving.

Memory errors are often the subtlest (next to race conditions, maybe). Use these tools as much as possible to catch any run-time issues that can't be ferreted with static analysis tools.

Fuzz testing.

Parsing data? Push your parsers into libraries and use AFL (from packages) to put them through inputs you haven't tested.

The thought that this input could never happen is your adversary's favourite. It will happen. Make sure any parsing sequences are being run through as many code-paths as possible with this tool.

Convinced? See it in action.

Don't forget: BSD is a community of professionals. Go to conferences (EuroBSDCon, AsiaBSDCon, BSDCan, etc.). Subscribe to the mailing lists. Donate. And lastly but most important of all: use the man pages!