As I said earlier, look at interactions.
Check your program designed to be sure
the interactions are properly constrained.
In particular, network accesses
should not be scattered throughout the program.
They should be in one or a small set of modules,
and each of those modules should
have appropriate checking code.
So if something goes wrong,
the module will detect it.
That relieves the higher levels to call these modules of
the burden of checking
the network parameters or conditions.
If there's something coming back from the server,
the connection is valid.
It'll be bumped up to the process directly or to
the processes computation unit or storage unit,
and you don't have to worry about,
well, did the network fail?
If on the other hand,
the input comes in from the network,
and it's invalid for some reason
or the connection is dropped or whatever,
then the network module would detect that and send up to
its caller and notification that there was a problem,
and possibly an error code saying what the problem was.
That way, the high-level program
only has to handle error cases,
and the lower layer module analyzing the problem,
figuring out what it is in dealing with it.
Higher level location also has to handle the input or
output comes from or goes to the module.
But again, it doesn't have to know anything
about the errors that may arise from the connection.
That's the modules business.
This also leads to the issue of system resources.
If you're going to access parts of the system,
makes sure that they're protected,
and these are done appropriately within, again, modules.
The whole issue with modules goes back to a concept that
Jim Anderson developed in the early 1970's.
It's called the reference monitor.
The reference monitor is
an abstraction that has three properties,
and the property that is most relevant to
this is, it's always invoked.
Whenever you want to check security of
something or do a security operation,
it always goes into the reference monitor
to be checked for validity.
Here we're using well-defined modules
instead of reference monitors,
but it's the same idea.
The reference monitor is
other properties that do not lend it to
be implemented directly on systems nowadays,
at least most systems.
But the well-defined modules and
the proper handling within the module and the clarity of
the interfaces is an example
of something that a reference monitor would have.
Also, look out for inputs,
where the inputs checked.
This is particularly critical
if the inputs contain instructions.
For example, if you have a little language.
You want to make darn sure that
little languages properly implemented.
If the input consists
of commands that your program has to run,
for example, spawning a subcommand interpreter,
or subshell, or what have you,
how is the execution of those constraint,
especially if the program that's doing the calling,
that's taking the commanding giving it to
the subshell is privileged?
Should the subshell and
your program command you issued also be privileged?
Maybe yes, maybe no.
The other issue is validating identities.
How do you know who you are?
Or rather, how does the computer know who you are?
While this may seem simple,
while I authenticated myself when I log in,
it brings up a number of questions.
For example, what's you group identity,
what's your role identity,
what's your login identity, or rather,
what's your audit identity, and so forth.
So there are many different names that
you can have in that the computer works with,
and you should be able to validate
that those are correct.
In addition, there may be naming conflicts,
for example, two users may have the same name.
How do you handle that situation?
Or to a website,
may have a name that is actually
one thing but appears to be another.
How do you handle situations like that?
How do you handle naming conflicts, is the gist of this.
Other things with implementations,
I mentioned buffer overflows already,
and they also mentioned the use of little languages.
The indivisibility problem I
mentioned earlier is an example of a race condition.
That's a common error.
Error handling is probably where most, well,
I shouldn't say most but an awful lot of errors occur,
because if something goes wrong,
you need to handle it. How do you do it?
In a privileged program,
if an error occurs and you know why that error occurs,
or when that error occurs,
the were only this set of things
that could have gone wrong,
then go ahead and try to recover.
If you don't know what caused it,
figure out how to terminate the program.
I mentioned changing privileges and also,
any use of cryptography,
both in the implementation and in what
you're using it for.
Other issues, improper use of library functions.
We'll talk about that beautiful one in Course three,
but in general, be sure
the library functions do what you want.
This also goes for other programs
when your program depends upon them.
When you get things from the
environment, from the registry,
or from environment variables,
that's really a form of input.
So check your input.
Again, in Course three,
we'll show you a situation where you
get information from an environment variable,
and in a particular construct,
that allows you to break into the system,
because the environment variable is not properly handled.
There are a bunch of other things as well.
There are somewhat language-specific or system-specific.
For example, Linux.
If you have a two environment variables
with the same name and different values,
and yes, that can happen.
Which one gets used?
We'll talk about that in Course three.
Also, when you write your program, type checking.
How do you handle unsigned,
how do you handle signed, and so forth.
Is this function being called
with signed or an unsigned number?
Is this function being called with an integer or
a real? That sort of thing.
Parameter type mismatches are very common error,
and I already mentioned the policies and procedures.
But this next slide,
policies and procedures serves as a good refresher,
either ignore them, and do as much checking as you can,
or take them into consideration.
All right. Let's give you a little thought exercise.
I am told that my system
is never to be connected to the Internet,
either through a wire or wireless.
What is some of the assumptions here?
What steps would you take to
be sure that procedures are followed?
What might happen if they aren't?
The latter depends a lot upon the environment,
of course, as does the second.
But if you think about that one,
I'll give you a minute or so,
and then we'll talk a little bit
about some of the assumptions.
All right. There are a couple of assumptions in that.
The first one, is that the assumption,
is that the system will never
be connected to the Internet.
So one assumption is,
while there may be networking components in the system,
but they'll never be used.
So that's one assumption I would look at.
In particular, one of the other assumptions,
is that you'll be able to tell whether or
not it's connected to the Internet.
If it's through a wire, then you can unplug it.
But what about wireless?
As far as the procedures go,
one other assumption up there,
it's never to be connected to the Internet.
What about the local networks?
Can it be connected to a local network
that's not connected to the Internet?
If so, how do you know that local network is
not connected to the Internet, and so forth.
The easiest way incidentally to make sure
this policy is followed,
it's simply to remove all
networking hardware from the system.
If you don't have a wireless card,
you can't turn it on.
If you don't have ethernet cards or networking cards,
you can't connect to a network.
That solves the problem right there.
Let's go on to the next.
For that one, I should add also,
you'll have to be careful if people put in USB sticks
with wireless on them.
So it's also a good idea to remove
all networking software as well.
So even if they do put something like that in,
they won't be able to use it.