Writing a Secure Application

only for RuBoard - do not distribute or recompile

In the preceding part of this chapter, we ve surveyed a number of security problems and discussed techniques for dealing with them. In this section, we ll write an application that uses several of these methods to show how they apply in practice. The basic scenario is somewhat like one of those presented in Chapter 7, Performing Searches, where we wrote a couple of applications to display a staff directory consisting of records that describe individual staff members. The primary focus for those applications was on the presentation of read-only information from the directory. Here, we ll use a similar table that contains information about the people listed in it, but we ll be more concerned about providing write access, and doing so in a secure manner: We ll allow users to update their own record over the Web using a browser. This goal is deceptively modest, because although it sounds almost trivial, implementing it in a secure way actually involves a number of issues:

  • Unauthorized users must be kept out. Only people who are listed in the table should be able to use the application. We can achieve this by using a login step that requires people to identify themselves before the application will cooperate by presenting an editing form containing the appropriate record. The application also will generate a session ID for authorized users. When the editing form is submitted, the session ID is a user s proof of having logged in, because you can t acquire a valid session ID otherwise.

  • People who have successfully logged in must be given access only to their own record and not allowed to trick the application into updating the wrong record. We can accomplish this by including the record ID in the editing form, but encoded in such a way that we can detect tampering. Also, because the application generates UPDATE statements based on user input, we ll need to thwart attempts at entering input intended to cause the application to create SQL that does something other than we intend. This is done through proper use of placeholders.

  • Third parties should not be able to eavesdrop on network traffic generated by the login and editing phases to steal passwords or to intercept and modify information submitted by legitimate users. To handle this, we can use a secure connection between each user and the application.

Setting Up the Table

We ll use a table called bio that contains descriptive (biographical) information about each person listed in it. The table lists the username and password of the person who owns each record; to gain access to the record, that person must authenticate by supplying both values at login time. The final piece of information included in the table is the user s email address. This is useful because a common problem with passwords is that people forget them. If we have email addresses, we can mail forgotten passwords to their owners. (This feature also has the salutary effect of reducing the number of I forgot my password, can you tell me what it is? messages that the application administrator receives!) The bio table looks like this:

 CREATE TABLE bio  (     id          INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,      username    CHAR(20) BINARY NOT NULL,   # user name and password      UNIQUE (username),      password    CHAR(20) BINARY NOT NULL,      email       CHAR(50) NOT NULL,      bio         CHAR(255) NOT NULL          # biographical information  ) 

Notice that the username and password columns are declared as BINARY ; this is done to make them case sensitive. CHAR columns normally are not case sensitive, which results in less strict matching. That is often useful, but not for authentication purposes. It isn t very secure to allow a password of ABC to be matched not only by ABC, but also by abc, Abc, and so forth.

Obviously, the bio table is quite minimal. It doesn t even have a column for the user s real name. I m keeping the table simple because the emphasis here is on the application s security aspects, not its ability to present fancy display or editing pages.

To initialize the table, use an INSERT statement such as the following one. The passwords are the usernames backward, which is convenient for testing, but of course not a good idea in general:

 INSERT INTO bio (username,password,email,bio)      VALUES          ('Dopey','yepoD','dopey@snake.net','I\'m a dwarf'),          ('Mickey','yekciM','mickey@snake.net','I\'m a mouse'),          ('George','egroeG','president@whitehouse.gov','I\'m a president'),          ('Paul','luaP','paul@snake.net','Awaiting further instructions') 

Now we can proceed to write an application edit_bio.pl that enables users listed in the table to log in and edit their biographical information. The implementation requires that you have session support set up as described in Chapter 8, Session Management, because it uses the sessions table and the WebDB::Session module developed in that chapter.

Overall Application Flow

The edit_bio.pl application will operate as follows. When you first invoke it, it presents a login page as a gateway that you have to get past to gain access to your record. The page contains a form containing username and password fields and buttons labeled Log In and Email Password. If you can t remember your password, you can fill in just the username and select the Email Password button. The application will look for a record that matches your username, and then mail the password to your address as listed in that record. Otherwise, to identify yourself, fill in both fields and select the Log In button. If the name and password match a record in the bio table, the application proceeds to the editing stage.

After you log in, the application generates a unique session ID and presents an editing form initialized with the contents of your record. The form will contain editable fields for your email address and biographical information, and also include the session ID and record ID in the form as a hidden field. The session ID is proof that you ve logged in and the record ID indicates which record you re editing. To modify your record, edit the fields appropriately and select the Update button. The application applies the changes to your record and displays the result in a confirmation page that contains a Continue Editing button in case you want to make further changes, and a Log Out button if you re finished.

Preventing Session and Record ID Tampering

In the editing form sent to the browser, edit_bio.pl includes the session ID for the client to use as proof of passing the login stage, and the record identifier to indicate which record is being edited. However, these values must be protected to keep the user from modifying them and gaining access to another person s record. To accomplish this, edit_bio.pl uses both checksums and encryption:

  • A checksum is calculated from the session and record identifiers; this checksum becomes part of the form sent to the client. It helps prevent mischief, because if the user were to modify the session or record ID, a new checksum calculated from the submitted values won t match the checksum in the form. (A mismatch indicates that the user modified either the IDs or the checksum. It doesn t really matter which; either way, edit_bio.pl will reject the form.)

  • A weakness of checksums is that if an attacker can guess your algorithm for calculating them, it s still possible to modify the form as follows: pick ID values to substitute for the real ones, then run them through the algorithm and use the result to replace the checksum, too. edit_bio.pl would never know the difference. To make this kind of attack more difficult, we ll encrypt the checksum and the session and record identifiers. This adds another layer of protection, because an attacker must perform a successful decryption first before attempting to tamper with the values. In addition, we ll incorporate a key value into the checksum and encryption operations; the attacker must also know this key to break the code.

The use of a key presents its own problem: How do you keep it secret? I ll take the expedient route here of writing the key literally into the text of the script. Remote clients cannot view the script to see the key, but remember that if you re sharing a Web server with other people, your scripts are readable to them (see Dangers from Other Users with Apache Access ). With access to your script s source code, these users also have access to your checksum and encryption algorithms as well.

edit_bio.pl performs checksumming and encryption/decryption using a pair of functions, encode() and decode(), that complement each other. encode() takes an argument list consisting of data values to be processed and produces an encrypted string that contains the values along with a checksum calculated from them.To encode a session ID $sess_id and record ID $id, use the function like this:

 $secret_stuff = encode ($sess_id, $id); 

The result will become the value of a hidden field named secret_stuff in the editing form. When the user returns the form, we can unpack the value to recover the session and record IDs. In the meantime, while the user has access to the form, the value is protected against tampering.

To verify the integrity of a submitted form, we pass the value of the secret_stuff parameter to decode(). This function takes an encrypted string and decrypts it to recover the original data values and the associated checksum. It verifies the values against the checksum to make sure they weren t modified, and returns the values as an array if they re okay, or an empty array to signal tampering:

 ($sess_id, $id) = decode ($secret_stuff) or die "Hey, I smell trouble\n"; 

The Perl CPAN offers a number of Perl modules for computing checksums and for performing encryption. Visit the security and encryption area of the Perl CPAN to look through the possibilities. The ones I ve chosen are extremely simple to use. edit_bio.pl uses Digest::MD5 to compute checksums. You give it your input values and it grinds them up and spits out a checksum based on them. To perform encryption, edit_bio.pl uses Crypt::CBC (cipher block chaining) in conjunction with Crypt::Blowfish. As usual, you can use perldoc to read module documentation:

 % perldoc Digest::MD5  % perldoc Crypt::CBC  % perldoc Crypt::Blowfish 

To use the modules in our edit_bio.pl script, we must include the appropriate use statements:

 use Digest::MD5;  use Crypt::CBC;  use Crypt::Blowfish; 

Then we can implement encode() as follows. It combines the input values with a key that only edit_bio.pl knows to produce a checksum, and then encrypts the checksum along with the values and returns the result as a string of hexadecimal digits:

 sub encode  { my @val = @_;  my $key = "This is the key value";  my $md = Digest::MD5->new ();  my $cipher = Crypt::CBC->new ($key, "Blowfish");  my $checksum;      $md->add (join ("", $key, @val));      $checksum = $md->hexdigest ();      return ($cipher->encrypt_hex (join (":", $checksum, @val)));  } 

encode() uses a colon ( : ) as the delimiter between the checksum and the data values in constructing the string to be encrypted, so that they can be separated later by decode(). This is not a good choice if any of your values might contain a colon, but all of the ones we re using are drawn from the set of hexadecimal digits, so we re safe.

The decode() function decrypts the enciphered string to recover the checksum and the data values, and then runs the checksum algorithm on the values to verify their integrity. A match between the new checksum and the one in the encrypted string indicates that no attempt was made to modify the information, in which case decode() returns the original data values. Otherwise, it returns an empty list to indicate tampering:

 sub decode  { my $ciphertext = shift;  my $key = "This is the key value";  my $md = Digest::MD5->new ();  my $cipher = Crypt::CBC->new ($key, "Blowfish");  my ($checksum, $checksum2);  my @val;      ($checksum, @val) = split (/:/, $cipher->decrypt_hex ($ciphertext));      $md->add (join ("", $key, @val));      $checksum2 = $md->hexdigest ();      return (@val) if $checksum eq $checksum2;   # everything's okay      return ();                                  # looks like tampering  } 

If you want to calculate checksums using a module such as Digest::HMAC_MD5 or Digest::HMAC_SHA1 rather than Digest::MD5, the interfaces for all three are very similar. Just include the appropriate use statement, and alter the new() call slightly. For example, to use Digest::HMAC_SHA1, include this statement:

 use Digest::HMAC_SHA1; 

Then create the message digest object in encode() and decode() like this:

 my $md = Digest::HMAC_SHA1->new ($key); 

As just shown, Crypt::Blowfish is one encryption module that works with Crypt::CBC, but there are others, such as Crypt::DES and Crypt::IDEA. You may in fact find it necessary to use one of these alternatives. I ve had mixed results installing the various modules on different versions of UNIX, so if you have trouble installing Crypt::Blowfish, try one of the others and modify edit_bio.pl to use it.

Checksums and Encryption Are Not Only for Form Data

The techniques described in this section to protect information in hidden fields are not limited to form data. You can also use checksums and encryption with information that you send to clients in URLs or in cookies.

Main Dispatch Logic

The main part of the script implements the application logic by checking the conditions with the strictest requirements first, and falling back to less restrictive conditions as necessary:

  • If the user is logged in (that is, if a valid session ID is present), we re already in the middle of presenting an editing session. The actions available to the user are Update to submit changes, Continue Editing to return to the editing form, and Log Out to quit.

  • If no session ID is found, but the choice parameter is present, the user just submitted the login form. The actions here might be Log In or Email Password.

  • Failing both of the preceding conditions, just present the login page.

Following this logic, the main part of the script looks like this:

 use strict;  use lib qw(/usr/local/apache/lib/perl);  use CGI qw(:standard escape escapeHTML);  use Mail::Sendmail;  use Digest::MD5;  use Crypt::CBC;  use Crypt::Blowfish;  use WebDB;  use WebDB::Session;  my $sess_id;                        # session ID  my $sess_ref;                       # reference to session record  my $id;                             # bio record ID  my $choice = lc (param ("choice")); # any button user may have selected  my $page;                           # contents of page to be displayed  # Extract the encoded session and record identifiers.                    If they're  graphics/ccc.gifpresent,  # make sure the session record is valid.                                 If these checks  graphics/ccc.gifare successful,  # the user has passed the login phase and is editing a bio record.  if (defined (param ("secret_stuff"))      && (($sess_id, $id) = decode (param ("secret_stuff"))))  {     # Use open_with_expiration() so we get undef if the session has expired.      $sess_ref = WebDB::Session->open_with_expiration (undef, $sess_id);  }  if (defined ($sess_ref))                # user is already logged in  {     # Shove IDs into environment for other functions to find      param (-name => "sess_id", -value => $sess_id);      param (-name => "id", -value => $id);      if ($choice eq "update")                # submit changes      {         $page .= submit_changes ();      }      elsif ($choice eq "continue editing")   # do some more editing      {         $page .= continue_editing ();      }      elsif ($choice eq "log out")            # user wants to quit      {         $page .= p ("Good bye.");          $sess_ref->delete ();               # destroy session          undef ($sess_ref);      }      else      {         $page .= escapeHTML ("Logic error: unknown choice: $choice");      }      $sess_ref->close () if defined ($sess_ref);  }  elsif ($choice eq "log in")             # user wants to log in  {     $page .= start_editing ();  }  elsif ($choice eq "email password")    # user requested password  {     $page .= email_password ();  }  else                                    # present the login page  {     $page .= login_page ();  }  print header (),          start_html (-title => "Edit Biographical Information",                      -bgcolor => "white"),          $page,          end_html (); 

Presenting the Login Page

The initial login page that the user sees is generated by the login_page() function:

 sub login_page  { my $page;      $page .= start_form (-action => url ())              . p ("Please log in. If you cannot remember your password,\n"                  . "enter your user name and select Email Password to\n"                  . "have your password sent to you via email.")              . p ("User name:")              . textfield (-name => "username")              . p ("Password:")              . textfield (-name => "password")              . br () . br ()              . submit (-name => "choice", -value => "Log In")              . " "              . submit (-name => "choice", -value => "Email Password")              . end_form ();      return ($page);  } 

If the user has forgotten the password and selects the Email Password button to receive it by email, edit_bio.pl invokes email_password(), which expects to find a username in the form contents. This function uses the name to look up the email address and the password, generates a message, and mails it to the user:

 sub email_password  { my ($dbh, $page);  my ($username, $email, $password);      # Make sure username is present in the login form      $username = WebDB::trim (param ("username"));      if ($username eq "")      {         $page .= p ("Error: You must supply a username.")                  . login_page ();          return ($page);      }      # Look for a matching record in the bio table      $dbh = WebDB::connect ();      ($email, $password) = $dbh->selectrow_array (                 "SELECT email, password FROM bio WHERE username = ?",                  undef, $username);      $dbh->disconnect ();      if (!defined ($email))      # no matching record found      {         $page .= p ("Error: Invalid username or no email address\n"                  . "available; cannot mail password.")                  . login_page ();          return ($page);      }      # Mail the password and indicate the status of the attempt      my %mail = (    # hash containing mail message information                             graphics/ccc.gif                           # hash containing mail message information              From    => $email,              To      => $email,              Subject => "Your bio record password",              Message => "Your password is: $password\n"      );      if (sendmail (%mail))      {         $page .= p (escapeHTML ("Password has been mailed to $email."));      }      else      {         $page .= p (escapeHTML ("An error occurred sending mail to $email."));      }      return ($page);  } 

edit_bio.pl will send the password only to the address listed in the record. It does not allow users to specify the address where they d like the password sent. That would enable anyone to get any password just by guessing a valid username.

If the user enters both the name and password into the login form and selects Log In, start_editing() uses the name to look up the user s record, checks the password to make sure it s correct, then initializes the session and presents the entry form:

 sub start_editing  { my ($dbh, $sth, $bio_ref, $sess_ref, $page);  my ($username, $password);      # Make sure username and password are present in the form      $username = WebDB::trim (param ("username"));      $password = WebDB::trim (param ("password"));      if ($username eq "" || $password eq "")      {         $page .= p ("Error: You must supply bot a username and password.")                  . login_page ();          return ($page);      }      # Look for a matching record in the bio table.      $dbh = WebDB::connect ();      $sth = $dbh->prepare (                 "SELECT * FROM bio                  WHERE username = ? AND password = ?");      $sth->execute ($username, $password);      $bio_ref = $sth->fetchrow_hashref ();      $sth->finish ();      $dbh->disconnect ();      if (!defined ($bio_ref))    # no matching record found      {         $page .= p ("Error: Login failed; username or password were invalid.")                  . login_page ();          return ($page);      }      # Generate a session record with a lifetime of 24 hours. Put the      # session ID and the contents of the bio record into the script      # environment for editing_form() to find.      if (!defined ($sess_ref = WebDB::Session->open (undef, undef)))      {         $page .= p ("Error: could not create session ID")                  . login_page ();          return ($page);      }      $sess_ref->expires ($sess_ref->now () + 60 * 60 * 24);      param (-name => "sess_id", -value => $sess_ref->session_id ());      foreach my $key (keys (%{$bio_ref}))      {         param (-name => $key, -value => $bio_ref->{$key});      }      $page .= editing_form ();      $sess_ref->close ();                # done with session; close it      return ($page);  } 

Presenting the Editing Page

The editing_form() function generates the form that enables the user to make changes. It encodes the session and record IDs to protect them and places the result in the hidden secret_stuff field, displays the username as static text, and the email address and biographical information values as editable text. The form includes an Update button for submitting changes, as well as a Log Out button so the user can quit without changing anything:

 sub editing_form  { my $secret_stuff;  my $page;      $secret_stuff = encode (param ("sess_id"), param ("id"));      $page .= start_form (-action => url ())              . p ("Please edit your record to make the desired changes,\n"                  . "then select Update (or Log Out to cancel changes).")              . hidden (-name => "secret_stuff",                          -value => $secret_stuff, -override => 1)              . hidden (-name => "username",                          -value => param ("username"), -override => 1)              . p (escapeHTML ("User name:" .. param ("username")))              . p ("Email address:")              . textfield (-name => "email")              . p ("Biographical information:")              . textarea (-name => "bio", -rows => 3, -columns => 80)              . br () . br ()              . submit (-name => "choice", -value => "Update")              . " "              . submit (-name => "choice", -value => "Log Out")              . end_form ();      return ($page);  } 

Confirming the User s Changes

After the user submits the editing form, submit_changes() is called to update the corresponding record in the database. We don t need to check the integrity of the session or record IDs that s already been done by the main part of the script, which invokes decode() to check the values before submit_changes() gets called. (You can try hacking the form to make sure that edit_bio.pl refuses to cooperate with you if you change the value of the secret_stuff field. It should notice the tampering and throw you back to the login page.)

 sub submit_changes  { my $sess_id = param ("sess_id");  my $id = param ("id");  my $email = WebDB::trim (param ("email"));  my $bio = WebDB::trim (param ("bio"));  my $secret_stuff;  my $dbh;  my $page;      # The only validation is to make sure the email      # field contains a valid address.      if ($email eq "" || !WebDB::looks_like_email ($email))      {         $page .= p ("Error: The email field must be filled in with\n"                      . "a valid address")                      . editing_form ();          return ($page);      }      $dbh = WebDB::connect ();      $dbh->do ("UPDATE bio SET email = ?, bio = ? WHERE id = ?",                                  undef, $email, $bio, $id);      $dbh->disconnect ();      $secret_stuff = encode ($sess_id, $id);      $page .= p ("Your record has been updated. The new values are:")              . table (                 Tr (                     td ("Email address:"),                      td (escapeHTML ($email))                  ),                  Tr (                     td ("Biographical information:"),                      td (escapeHTML ($bio))                  )              )              . start_form (-action => url ())              . p ("Select Continue Editing to make further changes,\n"                  . "Log Out to quit.")              . hidden (-name => "secret_stuff",                          -value => $secret_stuff, -override => 1)              . submit (-name => "choice", -value => "Continue Editing")              . " "              . submit (-name => "choice", -value => "Log Out")              . end_form ();      return ($page);  } 

When submit_changes() extracts parameter values from its environment, it uses trim() to trim off any extra whitespace from the values entered into the form by the user. It doesn t use trim() for the session or record ID values; the dispatch code placed those into the environment after extracting them from the hidden secret_stuff field, so they are usable as is.

The confirmation page generated by submit_changes() contains a Continue Editing button should the user decide to make more changes to the record. The function continue_editing() handles this case. It s somewhat similar to start_editing(), but doesn t create a session ID because there is already a session in place. It also knows the ID of the record to look up, so there s no need to solicit the username and password again.

 sub continue_editing  { my ($dbh, $sth, $bio_ref, $page);      # Look for the current record in the bio table.      $dbh = WebDB::connect ();      $sth = $dbh->prepare ( "SELECT * FROM bio WHERE id = ?");      $sth->execute (param ("id"));      $bio_ref = $sth->fetchrow_hashref ();      $sth->finish ();      $dbh->disconnect ();      if (!defined ($bio_ref))    # no matching record found (shouldn't happen)      {         $page .= p ("Error: Could not retrieve your record.")                  . login_page ();          return ($page);      }      # Put the contents of the bio record into the script      # environment for editing_form() to find.      foreach my $key (keys (%{$bio_ref}))      {         param (-name => $key, -value => $bio_ref->{$key});      }      $page .= editing_form ();      return ($page);  } 

Making the Session Secure

Thus far, we ve made sure that unauthorized users cannot gain access to the application, by means of a login page. We ve also protected the session and record IDs from tampering to ensure that once logged in, a user can t modify someone else s record. Our final safeguard will be to protect the user s privacy from eavesdroppers by allowing the entire session from login to logout to be performed over a secure connection. Assuming your Web server is set up to support SSL (as described in Using Secure Connections ) and that the user s browser also understands SSL, a secure connection can be provided quite easily. We can just require that the user invoke the script using https rather than http when requesting the edit_bio.pl script:

 https://www.snake.net/cgi-perl/edit_bio.pl 

This requires no changes to edit_bio.pl at all. The user gets a secure connection and we don t have to do any work. But it s not really a very good idea to rely on clients remembering to invoke the script using https and not http.[5] What are our options here for helping the user? One possibility is to put an SSLRequire directive in the Apache configuration file to prevent the script from being run unless the URL begins with https.[6] However, that approach probably is not very helpful. It keeps a user from using a non-secure connection, but doesn t tell the user what do instead. Another possibility is to have edit_bio.pl check for itself when the user first connects whether the connection is secure. If not, the login page can offer the option of logging in securely, in the form of a link that points to the login page but that begins with https. This is easy to do with a small modification to login_page(). At the end of that function, you ll find a line like this:

[5] Try asking several Web users sometime if they ve ever even noticed that secure connections use https.

[6] If you want to try this, see the mod_ssl manual for information about the capabilities that SSLRequire offers you.

 return ($page); 

To change the function to offer a secure login, add the following code just before the return statement:

 # If the user isn't logging in over a secure connection,  # offer the option of doing so.  if (!defined ($ENV{HTTPS}))  {     my $url = url ();      $url =~ s/^http:/https:/i; #http -> https      $page .= p ("Note: you are about to log in over an insecure\n"                  . "connection. To log in securely, select\n"                  . a ({-href => $url}, "this link") . ".");  } 

The code here uses the fact that mod_ssl defines the HTTPS environment variable if the connection is secure. If the connection is insecure, we construct a secure URL that begins with https rather than with http. (The pattern match and substitution operations use the i modifier for a non-case-sensitive test because the URL might begin with HTTP, Http, or some other lettercase variation.) Then we generate a paragraph containing warning message and offer a link that uses the secure URL.

After you make this change to the script, invoke it using a URL that begins with http to make sure it properly detects the non-secure connection and offers you the secure login link. Then select the link to verify that you get a secure connection.

The preceding change to login_page() offers users a secure login option by modifying the URL to begin with https. Does that mean we need to modify other parts of the script to generate URLs that begin with https, too? No. If the user follows the secure link, subsequent URLs produced by the script are generated in relation to that link and thus also will begin with https.

Our application draws on several of the techniques discussed earlier in the chapter. It includes methods for preventing the client from connecting without authenticating, for preventing the connected client from illegitimately modifying information, and for preventing third parties from snooping. At this point, I m willing to say that I believe edit_bio.pl to be reasonably secure from several kinds of attack, both from outsiders attempting to gain unauthorized access and from authorized users attempting to modify someone s record other than their own. Of course, the trouble with saying something like that is that I may have made some boneheaded mistake or oversight that renders the application insecure. If so, I m sure some reader will be delighted (perhaps a little too delighted!) to point that out. If that reader is you, please let me know. When it comes to security, it s better to know about a problem so that it can be fixed than not to know about it and have someone silently exploit it.

Suggested Modifications

The application enables users to request their password by email if they can provide the username in the login form. But if a person can t even remember the correct username, there s a problem. To handle this, add some descriptive text to the login page that indicates how to contact the application administrator in the event of such problems.

Allow the user to change the password in the editing form. If you implement this by presenting a password field so that onlookers can t gawk at the browser window to see what the user is typing, you should probably present two fields and require that they match. Otherwise, it s very easy for the user to make a mistake and end up with a password different from what was intended.

Store the record ID in the session record on the server side rather than on the client side in a hidden field. Then you only have to perform checksumming and encrypting on a single value (the session ID).

Transmit the session ID using a cookie rather than in a hidden field. This doesn t eliminate the need to prevent tampering (users can modify cookie contents), but it does allow an editing session to be resumed if the user accidentally closes the editing window. Is this good or bad?

The passwords in the bio table are stored as plain text, so anyone with SELECT access to the table can find out all the passwords easily. Can you prevent this by encrypting the passwords? (Some of the possibilities here include MySQL s PASSWORD(), ENCRYPT(), MD5(), ENCODE(), and DECODE() functions.) Does your solution break the application s capability to mail passwords to record owners? That is, does the encryption method offer reversibility? If it is reversible, is the encryption reversible only by the application? Will your solution work if some other MySQL user has UPDATE access to the bio table?

In this chapter, we ve covered a number of security issues that present themselves when you develop Web applications, as well as techniques for preventing security breaches. One area for which security generally has a very high priority is e-commerce, because such applications quite often involve private or sensitive information or financial transactions. In Chapter 10, E-Commerce Applications, we ll put some of these techniques for addressing security and privacy concerns to use in contexts that engage users in commercial interaction.

only for RuBoard - do not distribute or recompile


MySQL and Perl for the Web
MySQL and Perl for the Web
ISBN: 0735710546
EAN: 2147483647
Year: 2005
Pages: 77
Authors: Paul DuBois

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net