Coding safely using ASP
This guide applies to Microsoft's
ASP server-side scripting
technology when used with VBScript, it is not limited to one specific implementation or version of it since
the majority of the points are simply good coding practices we get out of the habit of doing thanks to the
simplicity of writing the code under
VBScript.
Where ever possible I have tried to provide the problem and a solution as the absolute minimum, as well as
optionally an explaination of why this stops the problem and/or what is possible if the problem was to
be exploited. The bulk of the items listed are non-invasive methods which will not be registered as an attack
by any automated detection systems which is why they have such potential to be dangerous - an attacker can
probe all day and no-one will be any wiser since all they see is someone having problems using their site.
-
Avoid using .inc extensions for your includes as, by default, they are not processed by the asp engine
prior to being delivered to the client - this means the client gets the entire script, not just the rendered
output, but the entire script including the server-side VBScript. Since the way IIS handles filetypes is a
property of the files extension, simply using .asp extensions on your includes will stop this from
happening (alternately you could just add .inc into the list of processed types so that it will be
processed prior to being delivered).
-
Trap and log any errors which could be generated by your scripts, solving a few problems in the process.
Firstly it makes you write better code since a good solution will not generate errors in everyday operation,
instead it will attempt to ensure that all actions it allows to happen will succeed, thereby eliminating
regular errors. Secondly it allows you to inform the user an error has occured and that you are dealing with
it rather than just leaving them wondering what some overly cryptic message generated by the server actually
means - one word of caution if you do show the user error messages be aware of the possibility that these
messages may be disclosing important information such as settings, paths and filenames.
When done properly this sequence of log and report allows you to be aware of any errors your system generates,
while at the same time hiding the true nature of these errors from the users as well as keeping a record of
how they caused this particular problem.
This method is a very good defence against having the logic of your system probed by people who are looking
for a way to bypass your system, as the majority of the time you will see errors in the logs alerting
you to look for an actual intrusion - additionally you make the task of someone probing logic that little
bit harder by denying them access to full error messages.
-
Option Explicit is your friend! Adding this declaration to your pages forces you to code accurately
and with a degree of forward planning, it also means logic issues arise less often since you can't put a value
into a new variable without declaring it first so a simple slip of the finger no longer yeilds a hard to trace
error.
-
Convert any input which you do not have total control over into the correct datatype before you start to
work with it. This avoids problems where a procedure gets given invalid input and (since VBScript lacks typing
of variables) this input is passed on as it is, from there the invalid input is used in a manner unforseen by
the original coder and neatly breaks, exploits or bypasses a component used in the procedure.
-
When using objects with default properties remember to use the full name of the property rather than relying on
the asp engine to get the default as this involves more work and is wasteful, secondly it also poses a problem
if the asp engine finds that your original request generates an error as instead of reporting an error it simply
uses the object as requested which gives you two problems. Firstly your error reporting gets thrown out and
any subsequent actions may fail, but also you find that your variable does not contain the type of data you
expect.
-
When creating tests and rules always ensure that they will fail closed so if they encounter a problem they
cannot handle they will return a negative result instead of a positive one. This avoids the problem where
it becomes possible to pass invalid input and have it reported as valid, allowing whatever malicious input
that was passed to reach the next stage of processing.
-
If you are dealing with any variable which you do not have total control over then it should be treated as
invalid until it can be proved otherwise - this not only extends to user input but also to headers as the
majority of these are user-controlled, equally it applies to cookies since handling of these is delegated
to the client. Once someone has control over an input it introduces the possibility that that same input
may be used as to insert hostile code into your application.
-
When parsing input always code against a known set of finite allowed values rather than an infinite number of
invalid values. Although both methods will work the first is more secure and portable since it operates on
the idea that everything is bad unless it is proven otherwise, the second will often cause problems due to
it's nature in that it needs to be maintained and updated whenever some new exploit for your system is
discovered where-as the first method can be assembled and then ignored without any problems.
-
Learn which items in the header the user does and doesn't have control over so if you are going to attempt to
use one of them for authentication you can be sure that it cannot be easily spoofed. An example of this in
action is the user-agent and referrer headers which (if truth be known) are trivial to spoof,
however you will quite often find people who blindly believe that using referrer is a fool-proof technique
for stopping people linking directly into their pages because they can't break it therefore clearly it cannot
be done. Equally you have the user-agent which I have seen generate multiple errors because it was being
used without first being parsed and with no error handling around it, again because the people that wrote the
code did not understand the nature of the input they were using.
-
Client-side scripts are good as they make the user's life easier but they are totally unreliable due to the
relative ease with which they can be disabled. If you implement a filter or rule on the client side then as
a minimum it also needs to be included on the server-side as well to avoid someone being able to break the code
simply by editing the page they got sent.
-
Files which are never supposed to be accessible via the web are far more secure outside of the webroot as this
simply puts them out of harms way, since once outside they are next to impossible for the casual intruder to
get access to.
-
Protected content needs to be protected by authentication of some description if it is not supposed to be
available to the general public. The thing about relying on a secret directory is that it is only providing
the illusion of security as the moment someone leaves a link to it somewhere, or a search engine finds it or
someone manages to guess the name it becomes as secure as any public access website.