Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

Lesson Four, Part 2 of online CGI course

by Ovid (Cardinal)
on Jan 06, 2002 at 10:42 UTC ( #136655=perlmeditation: print w/replies, xml ) Need Help??

I've just finished uploading lesson 4, part 2 of my CGI course. I've hacked this together pretty fast, so comments are welcome. It covers basic information about grabbing form data and how to securely store user passwords from a login form. It also hints at the information that will be contained in lesson 5: using cookies and generating session IDs.

The lesson really gets into some nit-picky details about Web-based security, so let me know if I've dropped the ball anywhere. Also, I think it may be fairly intimidating to a new Web programmer. Is it too much?

Regardless of whether or not you like the course, I'd appreciate it if you'd go to and give me a rating. I think that what I've produced so far leaves most of the other courses in the dust (yeah, they have no security info, typically hand-roll their CGI, etc). This isn't for bragging rights. I want people to see that this is a good course and hopefully take these matters to heart.


Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

  • Comment on Lesson Four, Part 2 of online CGI course

Replies are listed 'Best First'.
Re: Lesson Four, Part 2 of online CGI course
by mdillon (Priest) on Jan 06, 2002 at 23:06 UTC

    What you are doing with Digest::MD5 is not actually a crypt-style MD5 digest. It is just a simple MD5 digest with a constant component (what you have erroneously called the "salt") tacked on the end of the digest source. While it is still better than storing the plain text directly, it is not as good as actual MD5 crypt. A good explanation of what MD5 crypt is beyond a simple MD5 hash, go here (read the larger presentation about bcrypt, as well, if you like).

    Whether your simple system actually needs to use a crypt-style system is up to you. The idea of crypt and cousins is to increase the computational cost of checking a password. The trade-off is between responsiveness for legitimate users and deterrence of brute-force and dictionary attacks. The simple MD5 hash is almost certainly lower on this scale that traditional, DES-based crypt, and definitely below MD5 crypt. In my case, I would probably choose MD5 crypt (or SHA crypt or bcrypt, if feasible), in most cases, since I like to do whatever simple things I can to make myself feel more secure.

    In terms of implementation, there are two possibilities that I'll mention (who knows what others there are):

    1. Your operating system's version of crypt already supports extended variants of crypt (MD5, SHA, or bcrypt). This means that the crypt command built in to Perl already supports these variants. There is a good explanation of using built-in MD5 crypt here. (Read the reply to that node for some good caveats as well.)
    2. Use Crypt::PasswdMD5 for a pure Perl implementation of the MD5 crypt algorithm. (DISCLAIMER: I've never actually used this myself, YMMV)

    Other than that complaint, I'd say what I've read of the course is generally quite well written, thought out, and researched.

      Thanks for the information. As is obvious, cryptology is not my strong suit, so if you or anyone else cares to tackle the following question, I'd be grateful.

      From the link you provided regarding the MD5 crypt function:

      The output is the concatenation of the version identifier ``$1$'', the salt, a ``$'' separator, and the 128-bit hash output.

      So, I might get passwords that look like this:


      The eight characters after the second dollar sign are the salt. I understand that the salt and the password are repeatedly hashed together in an effort to make make cracking it computationally slow, but how exactly is that different from the constant component that I used, other than the fact that it's kept separate? I'm not sure I understand that point.

      The other point that I am trying to figure out is why the salt is included in the output. Doesn't keeping the salt secret make it more difficult to crack, since the attacker should know the salt in order to crack the password? I can see how having a different salt for each password improves security (lack of salt collisions will mean that each salt will force a different computation of the word list), but if someone has the password file, they can use the included salts at their leisure. Is there something just dead obvious that I am missing here?

      Glancing through the code for Crypt::PasswdMD5, it looks like it would be cross-platform compatible and should slow down an attacker. Once I have a better grasp of these issues, I should post an update to my course.


      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

        if the salt were secret, how would you ever check the user's password?

        the salt exists to keep dictionary attacks from being ridiculously efficient. imagine if there were no salt in the unix crypt scheme. i could calculate the hash of every word in the dictionary ahead of time and then simply compare that one list against every /etc/passwd i come across. if i were good, i could probably even remember the hash of a few of the more common passwords and be able to get an account here and there just by glancing at the passwd file. the salt just makes it so i have to run crypt on every word in the dictionary for each password i encounter because it has a different salt. no matter what i've always got to do some work.

        anders pearson

Re: Lesson Four, Part 2 of online CGI course
by Chrisf (Friar) on Jan 06, 2002 at 14:04 UTC
    Great tutorial Ovid++

    I'm glad you chose the login script, it was an excellent example.

    As I started to read through it I thought I was going to have a few valid complaints - overly descriptive error messages, storing passwords in plain text, and not checking the username before opening the file (I should have known better ;-). About 10 seconds after I thought of those I saw the bullet list describing the exact same errors and how/why they should be fixed. So there's only use CGI::Carp   qw/fatalsToBrowser/; in the final example that I'm wondering about - isn't it bad to leave that in production code?

    Also, one lowly typo to report - right after the second code box and before the bullet list there's a line that starts with "I went ahead and saved that in my cgi-gin"

    Once again, great job.

Re: Lesson Four, Part 2 of online CGI course
by coolmichael (Deacon) on Jan 06, 2002 at 15:06 UTC
    This is a fantastic tutorial Ovid. Thank you for creating it. I've already suggested it to a friend who is very new to perl and cgi. I also gave you a (well deserved) rating.

    I find CGI-Resource to be rather shoddy. Your tutorial blows the other tutorials out of the water. The highest ranked tutorial doesn't even use strict or taint checking, and has hand rolled CGI parsing. I just don't understand why people would do such a thing.

    Thanks again.

Re: Lesson Four, Part 2 of online CGI course
by Maclir (Curate) on Jan 06, 2002 at 20:14 UTC
    The first reading of this is excellent - I rated you a 10 out of 10 on the cgi resource index. Only one comment - in the sample html for the form variables at the very beginning of the lesson, you use HTML, but your example HTML in the exercises uses XHTML (with trailing slashes). It would be better to be consistent, and use XHTML compliant markup everywhere (and perhaps indicate this as such at the start of the course, along with a pointer to the W3C documentation).

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://136655]
Approved by root
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (4)
As of 2023-12-10 11:02 GMT
Find Nodes?
    Voting Booth?
    What's your preferred 'use VERSION' for new CPAN modules in 2023?

    Results (39 votes). Check out past polls.