Security policies are something that everybody knows they should have, but which are deceptively simple to get wrong. A set of simple steps to check when you’re implementing them is something that I think it’s important to share. You know when you come up a set of steps, you suddenly realise that you’ve got a couple of vowels in there and you think, “wow, I can make an acronym!”?[1] This was one of those times. The problem was that when I looked at the different steps, I decided that DDEAVMM doesn’t actually have much of a ring to it. I’ve clearly still got work to do before I can name major public sector projects, for instance[2]. However, I still think it’s worth sharing, so let’s go through them in order. Order, as for many sets of steps, is important here.
I’m going to give an example and walk through the steps for clarity. Let’s say that our CISO, in his or her infinite wisdom, has decided that they don’t want anybody outside our network to be able to access our corporate website via port 80. This is the policy that we need to implement.
1. Define
The first thing I need is a useful definition. We nearly have that from the request[3] noted above, when our CISO said “I don’t want anybody outside our network to be able to access our corporate website via port 80”. So, let’s make that into a slightly more useful definition.
“Access to IP address mycorporate.network.com on port 80 must be blocked to all hosts outside the 10.0.x.x to 10.3.x.x network range.”
I’m assuming that we already know that our main internal network is within 10.0.x.x to 10.3.x.x. It’s not exactly a machine readable definition, but actually, that’s the point: we’re looking for a definition which is clear and human understandable. Let’s assume that we’re happy with this, at least for now.
2. Design
Next, we need to design a way to implement this. There are lots of ways of doing this – from iptables[4] to a full-blown, commercially supported firewall[6] – and I’m not fluent in any of them these days, so I’m going to assume that somebody who is better equipped than I has created a rule or set of rules to implement the policy defined in step 1.
We also need to define some tests – we’ll come back to these in step 5.
3. Evaluate
But we need to check. What if they’ve mis-implemented it? What if they misunderstood the design requirement? It’s good practice – in fact, it’s vital – to do some evaluation of the design to ensure it’s correct. For this rather simple example, it should be pretty to check by eye, but we might want to set up a test environment to evaluate that it meets the policy definition or take other steps to evaluate its correctness. And don’t forget: we’re not checking that the design does what the person/team writing it thinks it should do: we’re checking that it meets the definition. It’s quite possible that at this point we’ll realise that the definition was incorrect. Maybe there’s another subnet – 10.5.x.x, for instance – that the security policy designer didn’t know about. Or maybe the initial request wasn’t sufficiently robust, and our CISO actually wanted to block all access on any port other than 443 (for HTTPS), which should be allowed. Now is a very good time to find that out.
4. Apply
We’ve ascertained that the design does what it should do – although we may have iterated a couple of times on exactly “what it should do” means – so now we can implement it. Whether that’s ssh-ing into a system, uploading a script, using some sort of GUI or physically installing a new box, it’s done.
Excellent: we’re finished, right?
No, we’re not. The problem is that often, that’s exactly what people think. Let’s move to our next step: arguably the most important, and the most often forgotten or ignored.
5. Validate
I really care about this one: it’s arguably the point of this post. Once you’ve implemented a security policy, you need to validate that it actually does what it’s supposed to do. I’ve written before about this, in my post If it isn’t tested, it doesn’t work, and it’s absolutely true of security policy implementations. You need to check all of the different parts of the design. This, you might hope, would be really easy, but even in the simple case that we’re working with, there are lots of tests you should be doing. Let’s say that we took the two changes mentioned in step 3. Here are some tests that I would want to be doing, with the expected result:
- FAIL: access port 80 from an external IP address
- FAIL: access port 8080 from an external IP address
- FAIL: access port 80 from a 10.4.x.x address
- PASS: access port 443 from an external IP address
- UNDEFINED: access port 80 from a 10.5.x.x
- UNDEFINED: access port 80 from a 10.0.x.x address
- UNDEFINED: access port 443 from a 10.0.x.x address
- UNDEFINED: access port 80 from an external IP address but with a VPN connection into 10.0.x.x
Of course, we’d want to be performing these tests on a number of other ports, and from a variety of IP addresses, too.
What’s really interesting about the list is the number of expected results that are “UNDEFINED”. Unless we have a specific requirement, we just can’t be sure what’s expected. We can guess, but we can’t be sure. Maybe we don’t care? I particularly like the last one, because the result we get may lead us much deeper into our IT deployment than we might expect.
The point, however, is that we need to check that the actual results meet our expectations, and maybe even define some new requirements if we want to remove some of the “UNDEFINED”. We may be fine to leave some the expected results as “UNDEFINED”, particularly if they’re out of scope for our work or our role. Obviously, if the results don’t meet our expectations, then we also need to make some changes and apply them and then re-validate. We also need to record the final results.
When we’ve got more complex security policy – multiple authentication checks, or complex SDN[7] routing rules – then our tests are likely to be much, much more complex.
6. Monitor
We’re still not done. Remember those results we got in our previous tests? Well, we need to monitor our system and see if there’s any change. We should do this on a fairly frequent basis. I’m not going to say “regular”, because regular practices can lead to sloppiness, and also leave windows of opportunities open to attackers. We also need to perform checks whenever we make a change to a connected system. Oh, if I had a dollar for every time I’ve heard “oh, this won’t affect system X at all.”…[8]
One interesting point is that we should also note when results whose expected value remains “UNDEFINED” change. This may be a sign that something in our system has changed, it may be a sign that a legitimate change has been made in a connected system, or it may be a sign of some sort of attack. It may not be quite as important as a change in one of our expected “PASS” or “FAIL” results, but it certainly merits further investigation.
7. Mitigate
Things will go wrong. Some of them will be our fault, some of them will be our colleagues’ fault[10], some of them will be accidental, or due to hardware failure, and some will be due to attacks. In all of these cases, we need to act to mitigate the failure. We are in charge of this policy, so even if the failure is out of our control, we want to make sure that mitigating mechanism are within our control. And once we’ve completed the mitigation, we’re going to have to go back at least to step 2 and redesign our implementation. We might even need to go back to step 1 and redefine what our definition should be.
Final steps
There are many other points to consider, and one of the most important is the question of responsibility, touched on in step 7 (and which is particularly important during holiday seasons), special circumstances and decommissioning, but if we can keep these steps in mind when we’re implementing – and running – security policies, we’ve got a good chance of doing the right thing, and keeping the auditors happy, which is always worthwhile.
1 – I’m really sure it’s not just me. Ask your colleagues.
2 – although, back when Father Ted was on TV, a colleague of mine and I came up with a database result which we named a “Fully Evaluated Query”. It made us happy, at least.
3 – if it’s from the CISO, and he/she is my boss, then it’s not a request, it’s an order, but you get the point.
4 – which would be my first port[5] of call, but might not be the appropriate approach in this context.
5 – sorry, that was unintentional.
6 – just because it’s commercially support doesn’t mean it has to be proprietary: open source is your friend, boys and girls, ladies and gentlemen.
7 – Software-Defined Networking.
8 – I’m going to leave you hanging, other than to say that, at current exchange rates, and assuming it was US dollars I was collecting, then I’d have almost exactly 3/4 of that amount in British pounds[9].
9 – other currencies are available, but please note that I’m not currently accepting bitcoin.
10 – one of the best types.