http://qs321.pair.com?node_id=1223031

theravadamonk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

with CGI, I want to have multiple usernames and passwords from a password.txt file.

In front end I have a login form login.html.

here it is

<HTML> <HEAD> <TITLE>Verifying a username and a password.</TITLE> </HEAD> <BODY> Type in your username and password below. <FORM ACTION = "/cgi-bin/login.cgi" METHOD = "POST"> Username:<INPUT SIZE = "40" NAME = "USERNAME"><br> Password:<INPUT SIZE = "40" NAME = "PASSWORD" TYPE = PASSWORD><br> <INPUT TYPE = "SUBMIT" VALUE = "Enter"> </FORM> </BODY> </HTML>

here's my login.cgi code

#!/usr/bin/perl use CGI qw(:standard); use strict; use warnings; my $var_username = param( "USERNAME" ); my $var_password = param( "PASSWORD" ); my $url="http://host.redirectdomain.com:9999/"; my $t=1; # time until redirect activates print "Content-Type: text/html; charset=utf-8\n\n"; open ( FILE, "/tmp/password.txt" ) || die "The file could not be opene +d"; while ( my $line = <FILE> ) { chomp $line; ( my $username, my $password ) = split( ",", $line ); if ( ( $var_username eq $username ) && ( $var_password eq $password + ) ) { print "$var_username, $var_password <br>"; # I will remove this in +real world print "Permission has been granted <br>"; print "<META HTTP-EQUIV=refresh CONTENT=\"$t;URL=$url\">\n"; } elsif ( ( $var_username eq $username ) && ( $var_password ne $passw +ord ) ) { print "$var_username, $var_password <br>"; # I will remove this in +real world print "You entered an invalid password. <br>"; print "Access has been denied. <br>"; } elsif ( ( $var_username ne $username ) && ( $var_password eq $passw +ord ) ) { print "$var_username, $var_password <br>"; # I will remove this in +real world print "You entered an invalid username. <br>"; print "Access has been denied. <br>"; } else{ print "$var_username, $var_password <br>"; # I will remove this in +real world print "You were denied access to this server. <br>"; } } close( FILE );

here's my /tmp/password.txt file

account1,password1

this works for a Single username and passowrd.

When I have multiple usernames and passwords in this way

account1,password1 account2,password2 account3,password3

It check all. The question is if I type username as account1 and password as let's say pass, It prints "You entered an invalid password" and "You were denied access to this server". when I give correct username and password, it redirects as expected but prints the latter else statement. These are issues. If INPUTS are Wrong, How can I have single error message instead of multiple errors. If INPUTS are right, How can I have single message like "Permission has been granted" and redirection to the url

How to solve this? I DO need multiple usernames and passwords

  • Comment on with CGI, How to have multiple usernames and passwords from a txt file (password.txt) file
  • Select or Download Code

Replies are listed 'Best First'.
Re: with CGI, How to have multiple usernames and passwords from a txt file (password.txt) file
by GrandFather (Saint) on Sep 26, 2018 at 06:54 UTC

    There are many problems with what you are doing, but the worst is working with plain text passwords. Never, ever, for any reason store plain text passwords, especially paired with user names!

    A fairly light weight technique that is much more secure and needs very little extra work is to store a cryptographic hash of the password combined with a seed (often the user name can be used as the seed). To check a supplied password use the same hash process that was used to generate the hash originally then compare the two hash codes.

    use strict; use warnings; use Digest::MD5; print Digest::MD5::md5_hex("username" . "SamplePassword");

    Prints:

    c0075ad4e26ec3dee225ccb6387b0b77
    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

      Hi Grandfather,

      Thanks for your effort. I want to understand what you say since it is beneficial for me

      What do you actually say?

      I included encrypted password in /tmp/password.txt file in following way.

      username,c0075ad4e26ec3dee225ccb6387b0b77

      Then, I input USERNAME as username and PASSWORD as SamplePassword. But, It won't work. Why?

      But, IF I input USERNAME as username and PASSWORD as c0075ad4e26ec3dee225ccb6387b0b77 , it will work..

      Is it the way?

      > To check a supplied password use the same hash process that was used to generate the hash originally then compare the two hash codes.

      How can I do it? Pls help me to complete the code with security.

        "Then, I input USERNAME as username and PASSWORD as SamplePassword. But, It won't work. Why?"

        Because you're comparing 'SamplePassword' against 'c0075ad4e26ec3dee225ccb6387b0b77', which isn't the same string.

        "How can I do it? Pls help me to complete the code with security"

        Grandfather explains that you have to do the same process with the user supplied password as you did you generate the password, compare the resulting value against the one you have stored.

Re: with CGI, How to have multiple usernames and passwords from a txt file (password.txt) file
by marto (Cardinal) on Sep 26, 2018 at 06:37 UTC

    Some side notes, storing your passwords.txt in /tmp isn't wise, nor is having passwords in plain text. You use CGI then manually print headers. You don't set a session, so after you validate the login details you redirect to a URL which isn't ensuring the visitor is logged in. Make life easy on yourself, see CGI::Alternatives.

      "storing your passwords.txt in /tmp isn't wise"

      I move it to /etc/httpd/password.txt

      "You don't set a session"

      how to set a session? Pls guide me. I will add it.

      "see CGI::Alternatives."

      What Can I get from it to enhance the code?

      I am runnig Apache with http. If run it with httpS and self signed certificate , Will it be better?

      I am also trying to add "onclick"funtion to my below login.html file to a give error message, if wrong inputs were entered. I am currently having them in login.cgi code. which way is better?

      <INPUT TYPE = "SUBMIT" VALUE = "Enter">

      I am some miles away from completing a nice and secure code..

      I hope perl monks will come up with their views..

        "I move it to /etc/httpd/password.txt"

        Also consider permissions, who else can get access to this file? I tend to keep this sort of thing in a database.

        "What Can I get from it to enhance the code?"

        Well it contains a lot of advice which you shouldn't ignore, examples of sane ways to approach such problems in modern frameworks.. Developing secure web applications isn't easy. What you have right now is a splash page redirecting those with a valid username and password to another page, which has no authentication on it whatsoever, nothing to stop anyone emailing the URL to someone else, who would be able to see it without any login details.

        CGI::Alternatives suggests other ways to achieve what you're actually trying to do, which will make your life easy if you take the time to learn the basics of what you're doing, rather than trying to implement something where security is "a MUST" without understanding such things. One of those is Mojolicious, which has fantastic documentation, you should pay special attention to the Basics. Tutorial gets you started. Growing goes on to show (wait for it) an example of how to implement an application which requires users to login. Finally HTTPS, for sure, https://letsencrypt.org/ may be of interest.

        This requires you to invest time in yourself, learning how to achieve what you want and what the tools available to you do. Modern frameworks make life easier. It's not the mid 1990s anymore (thankfully).

        Update: Fixed some typos.

        I am runnig Apache with http. If run it with httpS and self signed certificate , Will it be better?

        Yes it will because then your users' passwords will not be sent over the wire in the clear for any malefactor to read. It would be better still if your certificate were not self-signed.

        I am also trying to add "onclick"funtion to my below login.html file to a give error message, if wrong inputs were entered. I am currently having them in login.cgi code. which way is better?

        Both is better. Having it on the front-end prevents unnecessary round trips. Having it on the back-end too allows handling for those with javascript disabled.

        Note that neither of these questions have much to do with Perl. You might benefit from reading up on the general basics of web server (and web application) security first.

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: with CGI, How to have multiple usernames and passwords from a txt file (password.txt) file
by huck (Prior) on Sep 26, 2018 at 05:42 UTC

    There are many ways to do what you want, one is

    #!/usr/bin/perl use CGI qw(:standard); use strict; use warnings; my $var_username = param( "USERNAME" ); my $var_password = param( "PASSWORD" ); my $url="http://host.redirectdomain.com:9999/"; my $t=1; # time until redirect activates print "Content-Type: text/html; charset=utf-8\n\n"; open ( FILE, "/tmp/password.txt" ) || die "The file could not be opene +d"; my $didmsg=0; while ( my $line = <FILE> ) { chomp $line; ( my $username, my $password ) = split( ",", $line ); if ( ( $var_username eq $username ) && ( $var_password eq $password + ) ) { print "$var_username, $var_password <br>"; # I will remove this in +real world print "Permission has been granted <br>"; print "<META HTTP-EQUIV=refresh CONTENT=\"$t;URL=$url\">\n"; $didmsg=1; last; } elsif ( ( $var_username eq $username ) && ( $var_password ne $passw +ord ) ) { print "$var_username, $var_password <br>"; # I will remove this in +real world print "You entered an invalid password. <br>"; print "Access has been denied. <br>"; $didmsg=1; last; } } close( FILE ); unless($didmsg) { print "$var_username, $var_password <br>"; # I will remove this in +real world print "You entered an invalid username. <br>"; print "Access has been denied. <br>"; }
    Notice the use of the $didmsg flag, and "last" to terminate the read loop early

      Hi

      Thanks for writing the code with $didmsg flag and "last". $didmsg is something new for me. This is the first time I used it. It is really what I expected. Now it's time to add security, just as Monk grand farther says. But, it is still difficult to understand it even it is a very little extra work. ( i.e - Digest::MD5::md5_hex ). I am still unable to include it to the code..

Re: with CGI, How to have multiple usernames and passwords from a txt file (password.txt) file
by karlgoethebier (Abbot) on Oct 01, 2018 at 16:40 UTC

    Take a look at Digest to get the idea. Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help