6.5.10 Lab - Explore The Evolution of Password Methods
6.5.10 Lab - Explore The Evolution of Password Methods
Objectives
Part 1: Launch the DEVASC VM
Part 2: Explore Python Code Storing Passwords in Plain Text
Part 3: Explore Python Code Storing Passwords Using a Hash
Background / Scenario
In this lab, you will create an application that stores a username and password in plaintext in a database
using python code. You will then test the server to ensure that not only were the credentials stored correctly,
but that a user can use them to login. You will then perform the same actions, but with a hashed password so
that the credentials cannot be read. It is important to securely store credentials and other data to prevent
different servers and systems from being compromised.
Required Resources
• 1 PC with operating system of your choice
• Virtual Box or VMWare
• DEVASC Virtual Machine
Instructions
Step 1: Open the security directory in VS Code and install Python packages.
a. Open VS code. Then click File > Open Folder... and navigate to the devnet-src/security directory. Click
OK.
b. In the EXPLORER panel, click the password-evolution.py placeholder file to open it.
c. Open a terminal in VS Code. Click Terminal > New Terminal.
d. Use the following commands to install the packages needed in this lab. These packages may already be
installed on your VM. If so, you will get a Requirement already satisfied message.
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 1 of 11 www.netacad.com
Lab - Explore the Evolution of Password Methods
db_name = 'test.db'
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 2 of 11 www.netacad.com
Lab - Explore the Evolution of Password Methods
c. Save and run the password-evolution.py file. The nohup (no hangup) command keeps the process
running even after exiting the shell or terminal. The & makes the command run in the background.
devasc@labvm:~/labs/devnet-src/security$ nohup python3 password-evolution.py
&
[1] 26329
devasc@labvm:~/labs/devnet-src/security$ nohup: ignoring input and appending
output to 'nohup.out'
devasc@labvm:~/labs/devnet-src/security$
d. Press Enter to get a new command prompt.
e. Your Flask server is now running. In VS Code in the /security folder, you should see the nohup.out text
file created by Flask. Click the file to read its output.
f. Verify that the web service has started. Be sure to use HTTPS and not HTTP. The -k option allows curl to
perform "insecure" SSL connections and transfers. Without the -k option, you will receive an error
message, "SSL certificate problem: self-signed certificate". The command will display the message from
the return command you coded in your script.
devasc@labvm:~/labs/devnet-src/security$ curl -k https://0.0.0.0:5000/
Welcome to the hands-on lab for an evolution of password
systems!devasc@labvm:~/labs/devnet-src/security$
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 3 of 11 www.netacad.com
Lab - Explore the Evolution of Password Methods
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS USER_PLAIN
(USERNAME TEXT PRIMARY KEY NOT NULL,
PASSWORD TEXT NOT NULL);''')
conn.commit()
try:
c.execute("INSERT INTO USER_PLAIN (USERNAME,PASSWORD) "
"VALUES ('{0}', '{1}')".format(request.form['username'],
request.form['password']))
conn.commit()
except sqlite3.IntegrityError:
return "username has been registered."
print('username: ', request.form['username'], ' password: ',
request.form['password'])
return "signup success"
Note: Be careful of word wrap in the above code. Be sure to indent properly or the code may not work
correctly.
b. Append (copy) the following Flask code to your password-evolution.py file to verify the new account
credentials.
def verify_plain(username, password):
conn = sqlite3.connect('test.db')
c = conn.cursor()
query = "SELECT PASSWORD FROM USER_PLAIN WHERE USERNAME =
'{0}'".format(username)
c.execute(query)
records = c.fetchone()
conn.close()
if not records:
return False
return records[0] == password
c. Append (copy) the following Flask code to your password-evolution.py file. This code is used during
each login attempt to read the parameters from an HTTP request and verify the account. If the login is
successful, the message "login success" will be returned, otherwise the user will see the message
"Invalid username/password".
@app.route('/login/v1', methods=['GET', 'POST'])
def login_v1():
error = None
if request.method == 'POST':
if verify_plain(request.form['username'], request.form['password']):
error = 'login success'
else:
error = 'Invalid username/password'
else:
error = 'Invalid Method'
return error
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 4 of 11 www.netacad.com
Lab - Explore the Evolution of Password Methods
c. Use the following curl commands to create (signup) two user accounts, alice and bob, and send a POST
to the web service. Each command includes the username, password, and the signup function being
called that stores this information including the password as plaintext. You should see the "signup
success" message from the return command that you included in the previous step.
Note: After each command, press Enter to get a command prompt on a new line.
devasc@labvm:~/labs/devnet-src/security$ curl -k -X POST -F 'username=alice'
-F 'password=myalicepassword' 'https://0.0.0.0:5000/signup/v1'
signup successdevasc@labvm:~/labs/devnet-src/security$
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 5 of 11 www.netacad.com
Lab - Explore the Evolution of Password Methods
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 6 of 11 www.netacad.com
Lab - Explore the Evolution of Password Methods
conn.commit()
try:
hash_value =
hashlib.sha256(request.form['password'].encode()).hexdigest()
c.execute("INSERT INTO USER_HASH (USERNAME, HASH) "
"VALUES ('{0}', '{1}')".format(request.form['username'],
hash_value))
conn.commit()
except sqlite3.IntegrityError:
return "username has been registered."
print('username: ', request.form['username'], ' password: ',
request.form['password'], ' hash: ', hash_value)
return "signup success"
b. Append (copy) the following code to your password-evolution.py file to verify that the password has
been stored only in hashed format. The code defines the function verify_hash which compares the
username and the password in hash format. When the comparison is true, the password has been stored
only in its hash format.
def verify_hash(username, password):
conn = sqlite3.connect(db_name)
c = conn.cursor()
query = "SELECT HASH FROM USER_HASH WHERE USERNAME =
'{0}'".format(username)
c.execute(query)
records = c.fetchone()
conn.close()
if not records:
return False
return records[0] == hashlib.sha256(password.encode()).hexdigest()
c. Append (copy) the following code to your password-evolution.py file. The following code reads the
parameters from an HTTP POST request and verifies that the user has provided the correct password
during login.
@app.route('/login/v2', methods=['GET', 'POST'])
def login_v2():
error = None
if request.method == 'POST':
if verify_hash(request.form['username'], request.form['password']):
error = 'login success'
else:
error = 'Invalid username/password'
else:
error = 'Invalid Method'
return error
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 7 of 11 www.netacad.com
Lab - Explore the Evolution of Password Methods
c. Use the following curl commands to create three new user accounts with a hashed password. Notice that
two of the users, rick and allan, are using the same password.
devasc@labvm:~/labs/devnet-src/security$ curl -k -X POST -F 'username=rick' -
F 'password=samepassword' 'https://0.0.0.0:5000/signup/v2'
signup successdevasc@labvm:~/labs/devnet-src/security$
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 8 of 11 www.netacad.com
Lab - Explore the Evolution of Password Methods
db_name = 'test.db'
@app.route('/')
def index():
return 'Welcome to the hands-on lab for an evolution of password
systems!'
######################################### Plain Text
#########################################################
@app.route('/signup/v1', methods=['POST'])
def signup_v1():
conn = sqlite3.connect(db_name)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS USER_PLAIN
(USERNAME TEXT PRIMARY KEY NOT NULL,
PASSWORD TEXT NOT NULL);''')
conn.commit()
try:
c.execute("INSERT INTO USER_PLAIN (USERNAME,PASSWORD) "
"VALUES ('{0}', '{1}')".format(request.form['username'],
request.form['password']))
conn.commit()
except sqlite3.IntegrityError:
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 9 of 11 www.netacad.com
Lab - Explore the Evolution of Password Methods
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 10 of 11 www.netacad.com
Lab - Explore the Evolution of Password Methods
© 2020 - 2020 Cisco and/or its affiliates. All rights reserved. Cisco Public Page 11 of 11 www.netacad.com