Everyday I spend time working on products for our great clients, I specifically spend a great deal of it writing code and building features. But I’m not just creating new features, I’m also creating new opportunities…opportunities to break that product. Here are the questions developers need to ask before turning in their tasks, and how they’re going to help you code smarter.
- How can I break this?
- Where’s Murphy hiding?
- Who do I trust?
- What’s dangerous?
- What are the real limits?
- Who is this for?
For example, what could go wrong with this example?
<?php _e( 'What could go wrong here?' ); ?>
Well, it turns out, a lot.
Have you ever tried breaking this by adding malicious scripts in language file? Turns out an innocent function, like this, opens a huge opportunity for people to break things. This was my own revelation a few weeks ago, and it dawned on me that I do not spend enough time trying to break things and learning the skills I need to detect these hidden opportunities in my code. The first step was simply realizing that with every new feature, comes new opportunities, but the following are a few steps I’ve been taking before I complete and turn in any new feature.
How can I break this? (Go break it)
It takes more than just trusting functions and methods to get the job done. You have to actually get in there and try and break what it is you just made. I feel we aren’t encouraged enough to go in there (and especially spend the time) and be a hacker. But I call all developers out! Become a hacker daily! Break your stuff! In doing so, you are going to build better products, serve your clients better, increase the reliability of your company, and, ultimately, become a better developer.
I also encourage CEOs, business owners, leads, and project managers to change the rhetoric behind security to go beyond just coding, but making the actual act of hacking your own solutions a part of the development process. Tell your developers to ask themselves, before turning in a task or pull request, “How can I break this?” And give developers permission to take the time to become a hacker.
Where’s Murphy hiding?
Anything that can go wrong, will go wrong. – Murphy’s Law
So we’re trying to hack our new feature, and we find a way that a user can pass a combination of query arguments, and somehow, logged in as a subscriber, could possibly run a server-intensive script we just built over and over. I feel (admittedly, through my own experience) we tell ourselves too much that they would never figure out how to do that, and we move on. But someone will!
I’ve just created a problem that will happen in the future. Thinking of these findings as problems that will undoubtedly happen, no matter how unlikely we think it is, will help us keep the internet and clients safe. It allows us to strategize.
Who do I trust?
Developers can be too trusting, and we shouldn’t be. Never trust anyone.
<?php _e( 'What could go wrong here?' ); ?>
In our example here, we might admit that the only one who could really cause a problem are the people who translate. Maybe they’re our own people, maybe they’re strangers, or maybe they’re future translators that a client hired six months down the road that know nothing about WordPress. Whoever it is, I say, they automatically get the “I don’t trust you” stamp of non-approval. It’s strange, but developers have to live in a very untrustworthy world, and we’re better developers for it! Having an skeptical approach will lead you to creating more secure code and features. Take your paranoia and make something rock solid.
What’s dangerous?
In the spirit of Murphy’s Law and trusting no one, you have to see information itself as a potential transmitters for viruses, illnesses, and things that cause bad things to happen and blow up the Internet. Data and information are dangerous! By shifting your view of information to something dangerous, and hiding some disease inside, we can be better devs.
An example.
$image = get_the_post_thumbnail(); echo $image;
In this example, we might view $image
as completely innocent and trustworthy.
But it’s not.
Did you know that get_the_post_thumbnail()
has a filter? Yeah, it’s post_thumbnail_html
and anyone can filter the output and push out a harmful script! $image
is dangerous; variables are dangerous! How do you know someone with server access didn’t inject a Must-Use plugin that filters that output?
If we put on our Hat Of Mistrust, we’ll be aware that leaving that variable alone is risky, and take action:
$image = get_the_post_thumbnail(); echo wp_kses_post( $image );
This should allow img
tags that are allowed in the WordPress post editor, and if anyone tries to inject a harmful script, it won’t let them. We need to start seeing information as potentially dangerous, and ask ourselves if it is, because we don’t know all the filters or ways people can turn information against us. Using critical thinking and strategy in the ways we work helps us stay one step ahead of people who either don’t know or possess malintent.
If we were really paranoid, we might write something like:
$image = get_the_post_thumbnail(); echo ( is_string( $image ) && stristr( $image, '<img' ) ) ? wp_kses_post( $image ) : '';
What are the real limits?
Another question I think developers rarely ask themselves are, “What are the real limits?”
Really thinking about this question can produce interesting answers.
For instance, what is the limit of get_posts
? At first, you might think, well -1
(I did). Set that posts_per_page
to -1
and we’ll get all the things, yeah baby! But, a smarter developer might find that…
- The server’s execution time is a limit
- The server’s memory is a limit
- 15, the limit is 15; there will always be 15
We should be thinking about real limits, not just limits in code, and what happens when these limits are reached. Like the server’s execution time or memory limits resulting in a 503. Or, getting fifteen posts–no harm there, right? Have you ever asked yourself how many posts_per_page
actually result in a timeout or a 503 on your server? It’s a good question.
Our job as developers is to eliminate the harmful effects of reaching real limits and we need to be aware of what these limits are and make sure we’re not breaking them.
Who is this for?
“Who is this for?”
I think every feature should have a name associated with it. Is it all administrators, or all authors? Is it just Jane or Joe? Is it the United States? Are they English speakers or Spanish speakers? Who are these people!?
Knowing (or even guessing at) who will be using our features, by giving our features ownership, helps make sure we’re prepared to create features with privilege in mind.
Even if your answer is “everyone,” we probably should be looking hard at the detailed, real time answers. For instance, “everyone” includes many languages; how many Spanish speakers need to use your product? Do you have a plan to have your content translated? What about A11y? That includes everyone too! Thinking of your features as privileged and belonging to someone helps us take more responsibility with our features, who has access, and who shouldn’t. This also allows you expand your reach and make sure that people who might otherwise be excluded in a generic “everyone” can access what you made.
What about you?
Do you have any tactics that help you build more secure features? What are some ways you work secure features into your build?