]> granicus.if.org Git - apache-authnz-external/blob - mod_authnz_external/AUTHENTICATORS
Note about SQL injection.
[apache-authnz-external] / mod_authnz_external / AUTHENTICATORS
1             How To Implementation External Authentication Programs
2                for mod_authnz_external or mod_auth_external
3                                 Version 3.3.x
4
5 LANGUAGES
6
7  External authenticators can be written in almost any language.  The sample
8  authenticators in the 'test' directory are in Perl and PHP.  The 'pwauth'
9  authenticator is in ANSI C.  The example code fragments in this document
10  are in C.
11
12  If the authenticator is a script rather than a compiled program, it normally
13  has to start with a "#!/bin/sh" or "#!/usr/bin/perl" type directive.  Scripts
14  without such directives may get interpreted by the shell, or may just not
15  work, depending on your installation.
16
17 SECURITY
18
19  The authenticator program should be written with great care because it runs
20  as a privileged user and handles privileged data.  A poorly written
21  authenticator could substantially compromise the security of your system.
22  You get points for paranoia.  Some notes:
23
24  - Don't make any assumptions about the length of the login names and
25    passwords given by the user.  I *think* Apache will never pass you ones
26    that are longer than 8192 characters, but don't depend this.  Check very
27    carefully for buffer overflows.
28
29  - Don't make assumptions about the content of the login and password strings.
30    For example, if you are using them in an SQL query, do proper checking
31    and/or quoting to insure that nobody is doing SQL injection.
32
33  - Think about locking.  It is possible to get lots of hits at your website
34    very fast, so there may be many programs simultaneously reading your
35    authentication database, plus updates may be going on at the same time.
36    Probably some form of locking is needed to make all this work right.
37
38  - Think about core dumps.  On some systems core dump files can be publically
39    readable.  A core dump from your authenticator is likely to contain the
40    user's plain text password, and may include large chunks of your password
41    database that may have been in buffers.  For C programs on most versions of
42    Unix, it is possible to disable core dumps by doing something like:
43    
44     rlim.rlim_cur = rlim.rlim_max = 0;
45     (void)setrlimit(RLIMIT_CORE, &rlim);
46
47    Actually, core dumps seem to be mostly a thing of the past. Most modern
48    Unixes don't seem to generate them.
49
50  It may not hurt to spend a little time looking at the features of the pwauth
51  authenticator, which is the most secure external authenticator that I have
52  written.
53
54 PASSWORD AUTHENTICATORS
55
56  Authenticators communicate their result by the exit status code they return.
57  A value of 0 indicates that the password is correct.  Other values indicate
58  that the password is incorrect, or something else is wrong.  It can be
59  useful to return different error codes for different kinds of errors.  These
60  will be logged in the Apache error log file, and can be helpful in diagnosing
61  problems.  This version of mod_authnz_external does not have any provision for
62  returning textual error messages from the external authenticator.  You might
63  be able to use syslog() for this.  This might be improved in future releases.
64
65  Returned error codes should not be negative.  Negative values are used
66  internally to mod_authnz_external to indicate problems launching your program.
67
68  How the external authentication program gets its arguments depends on
69  the method used.  The method used is determined by the 'SetExternalAuthMethod'
70  command in your Apache configuration file.  You need implement only the
71  method that you plan to use in your configuration.
72
73  PIPE METHOD
74
75   In the "pipe" method, the arguments are read from standard input.  The
76   user name will be on the first line, and the password will be on the
77   second.  Here's a typical chunk of C code to read that:
78
79   main()
80   {
81       char user[100], password[100], *p;
82
83       if (fgets(user, sizeof(user), stdin) == NULL) exit(2);
84       if ((p= strchr(user, '\n')) == NULL) exit(4)
85       *p= '\0';
86
87       if (fgets(password, sizeof(password), stdin) == NULL) exit(3);
88       if ((p= strchr(password, '\n')) == NULL) exit(5)
89       *p= '\0';
90
91       if (check_password(user, password) == OK)
92            exit(0);     /* Good Password */
93       else
94            exit(1);     /* Incorrect Password */
95   }
96
97   Here we simply read two lines from stdin, being careful not to allow
98   buffer overflows and stripping off trailing newlines.
99
100   We assume "check_password()" is some function that checks the validity of a
101   password and returns 'OK' if it is good.
102   
103   Note that we exit with different non-zero error codes in different error
104   cases.  This will be helpful for debugging, as those values will be logged
105   when authentication fails, giving you some clue as to what went wrong.
106   It'd really be better for check_password() to return more detailed error
107   codes, but I wanted to keep the example simple.
108
109  CHECKPASSWORD METHOD
110
111   The "checkpassword" method is identical to the "pipe" method, except
112   that the user name and password are terminated by NUL ('\0') characters
113   instead of newline characters, and they must be read from file descriptor
114   3 instead of standard input.  Documentation for the checkpassword
115   interface is at http://cr.yp.to/checkpwd.html.
116
117  ENVIRONMENT METHOD
118
119   In the "environment" method, the arguments are passed in environment
120   variables.  The user id and the clear-text password are passed in the
121   USER and PASS environment variables respectively.
122   
123   Note that the environment method has fundamental security weaknesses,
124   and should probably not be used unless you have cause to believe it is
125   safe on your system. I wouldn't be surprised if it is marginally faster
126   than the pipe method. Most applications should use the pipe method instead.
127
128   A typical chunk of C code to authenticate with the environment method
129   might be like:
130
131   main()
132   {
133       char *user, *password;
134
135       if ((user= getenv("USER")) == NULL) exit(2);
136       if ((password= getenv("PASS")) == NULL) exit(3);
137
138       if (check_password(user, password) == OK)
139            exit(0);     /* Good Password */
140       else
141            exit(1);     /* Incorrect Password */
142   }
143
144 GROUP AUTHENTICATORS
145
146  Security is generally less of a issue with group authenicators, since they
147  are not handling any data as sensitive as clear-text passwords.  They are
148  only passed a user name (presumably already authenticated), and a list of
149  group names.  They exit with status code 0 if that user is in one of those
150  groups, and a non-zero code otherwise.
151
152  In versions of mod_auth_external before 2.1.8, external authenticators were
153  always passed just one group name.  If the Apache "require group" directive
154  listed more than one group, then the external authenticator would be called
155  once with each group name, which could be inefficient if you have a large
156  number of groups.  Mod_auth_external will still behave this way if you
157  issue the "GroupExternalManyAtOnce off" directive.
158
159  Newer versions of mod_auth_external and mod_authnz_external will pass all
160  group names, separated by spaces.  There will only be multiple calls if more
161  than one "require group" directive applies to the same program (e.g., if
162  different parent directories contain such directives in their .htaccess
163  files - for efficiency, this should be avoided).  The list of group names
164  is passed in exactly as they appear on the "require group" directive - if
165  your program can't handle multiple spaces between group names, don't put
166  them there.
167
168  Arguments are passed in a manner similar to password authenticators.  The
169  method used is determined by the 'SetExternalGroupMethod' command in your
170  Apache configuration file.
171
172  ENVIRONMENT METHOD
173
174   In the "environment" method, the arguments are passed in environment
175   variables.  The user id and the group names are passed in the USER and
176   GROUP environment variables respectively.  A typical chunk of C code to
177   fetch the arguments and check each group might be like:
178
179   main()
180   {
181       char *user, *groups, *group;
182
183       if ((user= getenv("USER")) == NULL) exit(2);
184       if ((groups= getenv("GROUP")) == NULL) exit(3);
185
186       group= strtok(groups, " ");
187       while (group != NULL)
188       {
189           if (check_group(user, group) == OK)
190                 exit(0);        /* User is in group */
191           group= strtok(NULL, " ");
192       }
193       exit(1);                  /* User is not in any group */
194   }
195
196   Here "check_group()" is some function that looks in your database to see if
197   user is in group and returns 'OK' if he is.
198
199  PIPE METHOD
200
201   In the "pipe" method, the arguments are read from standard input.  The
202   user name will be on the first line, and the group name will be on the
203   second.  Here's a typical chunk of C code to read that:
204
205   main()
206   {
207       char user[100], groups[100], *group, *p;
208
209       if (fgets(user, sizeof(user), stdin) == NULL) exit(2);
210       if ((p= strchr(user, '\n')) == NULL) exit(4)
211       *p= '\0';
212
213       if (fgets(groups, sizeof(groups), stdin) == NULL) exit(3);
214       if ((p= strchr(groups, '\n')) == NULL) exit(5)
215       *p= '\0';
216
217       group= strtok(groups, " ");
218       while (group != NULL)
219       {
220           if (check_group(user, group) == OK)
221                 exit(0);        /* User is in group */
222           group= strtok(NULL, " ");
223       }
224       exit(1);                  /* User is not in any group */
225   }
226
227   Here we simply read two lines from stdin, being careful not to allow
228   buffer overflows and stripping off trailing newlines.  We loop through
229   all groups, checking each.
230
231  CHECKPASSWORD METHOD
232
233   Mod_auth_external will happily try to do group authentication via the
234   checkpassword method, piping NUL terminated user and group names to
235   the child process's file descriptor 3, but this isn't actually allowed
236   for in the checkpassword protocol specification, so I don't recommend it.
237
238 OTHER ENVIRONMENT VARIABLES
239
240  In all cases (pipe or environment method, password or group authentication),
241  the following additional environment variables will be supplied to the
242  authenticator:
243
244     AUTHTYPE  either "PASS" or "GROUP" depending on whether we are doing
245               password or group authentication.  This is handy if you are
246               using one program to do both.
247
248     CONTEXT   a string whose value is set by an "AuthExternalContext"
249               directive in the .htaccess file or "<Directory>" block for
250               the directory.  This can be used to select different
251               authentication behaviors in different directories.  It is
252               undefined if there is no "AuthExternalContext" directive.
253
254     IP        the client's ip-address.
255
256     HOST      the host name corresponding to IP, if Apache has
257               "HostnameLookups On".
258
259     PATH      the httpd's path environment variable.
260
261     COOKIE    all cookie values passed in by the client.
262
263     HTTP_HOST the server's host name, as given in the HTTP request.  May
264               be useful if you have multiple virtual hosts sharing an
265               authenticator.
266
267     URI       the document requested.  This is the URL including any extra
268               path information, but not including the hostname or any CGI
269               arguments.
270
271  These may be useful for logging, or you may want to accept logins from
272  certain users only if they are connecting from certain locations or requesting
273  certain documents.
274
275  Note that if you have configured Apache with "HostnameLookups Off" then HOST
276  will usually not be set.  If you really want hostnames, either turn on
277  HostnameLookups or do your own gethostbyaddr() calls from the authenticator
278  when HOST is not defined.  Note that if the user is coming from an
279  unresolvable IP, then hostname lookups can be very slow.
280
281  Note that using IP addresses to track a user through your site is not
282  reliable.  Users of services like AOL and WebTV use proxy servers, so that 
283  their IP addresses appear to change constantly since each request may come
284  through a different proxy.  A single user's requests for successive pages,
285  or for different images on the same page may all come from different IP
286  addresses.
287
288  The PATH environment variable passed to the authenticator is just whatever
289  PATH was in effect when Apache was launched, and may differ if the server
290  was launched automatically during a reboot or manually by an admin. 
291  Probably your program should set its own PATH if it needs one.
292
293  The COOKIE environment variable contains all cookies set in the current
294  request.  This has the same format as the HTTP_COOKIES ("key=val;key=val")
295  passed to a CGI program.  This should be used with caution.  Cookies come
296  from the user's computer and might have been created, editted or deleted
297  by the user rather than your website.  This severely limits their use for
298  authentication.  It is not possible to set cookies from an authentication
299  module.
300
301  The URI variable is there because various people want it.  Mostly it
302  is useful not for authentication ("who is this person?") but for access
303  control ("is this person permitted to do this?"), and good design usually
304  dictates separating those functions.  Strictly speaking, an authenticator
305  is not the right place to be doing access control.  However,
306  mod_authnz_external is 50% a kludge-builder's tool, so we won't fuss if you
307  want to break the rules.