+ All Categories
Home > Data & Analytics > PostgreSQL: How to Store Passwords Safely

PostgreSQL: How to Store Passwords Safely

Date post: 11-Jan-2017
Category:
Upload: juliano-atanazio
View: 537 times
Download: 1 times
Share this document with a friend
30
Juliano Atanazio PostgreSQL: How to Store Passwords Safely PostgreSQL: How to Store Passwords Safely
Transcript
Page 1: PostgreSQL: How to Store Passwords Safely

Juliano Atanazio

PostgreSQL: How to Store Passwords SafelyPostgreSQL: How to Store Passwords Safely

Page 2: PostgreSQL: How to Store Passwords Safely

2/30

About me

Juliano Atanazio

● Graduated in Computer Science for Business Management (Informática para Gestão de Negócios), FATEC Zona Sul, São Paulo – SP;

● PostgreSQL DBA;

● Linux admin;

● Instructor (PostgreSQL);

● LPIC-1, LPIC-2 Certified;

● Linux user since 2000;

● Free Software enthusiast;

● Favorite technologies: PostgreSQL, Linux, Python, Shell Script, FreeBSD, etc...;

● Headbanger :) \m/

Page 3: PostgreSQL: How to Store Passwords Safely

3/30

Plain Text Passwords

● Store passwords (in plain text) of application users in database is not a good practice;

● The DBA doesn’t need and shouldn’t know the users passwords;

● If your database is invaded, the attacker will have access to user passwords;

● The unencrypted password should never be stored in the database.

Page 4: PostgreSQL: How to Store Passwords Safely

4/30

Hashing and Salting

Hashing and salting is a technique to store passwords securely:

1. Generate a random string (salt) with a desired algorithm (e. g. blowfish based);

2. This salt and the plain text password are used to generate the hash password through hashing process;

3. Hash password is stored in the database;

The password must be encrypted in an irreversible way, that you can not decrypt it (theoretically).

Page 5: PostgreSQL: How to Store Passwords Safely

5/30

pgcrypto

pgcrypto is a extension that provides cryptographic functions for PostgreSQL.

https://www.postgresql.org/docs/current/static/pgcrypto.html

Page 6: PostgreSQL: How to Store Passwords Safely

6/30

pgcrypto

gen_salt and crypt Functions

They are specifically designed for hashing passwords. crypt() does the hashing and gen_salt() prepares algorithm parameters for it.

● gen_salt(): Generates a new random salt string for use in crypt(). The salt string also tells crypt() which algorithm to use.

● crypt(): It generate hash password through passing the password (in plain text) and salt as parameters.

Page 7: PostgreSQL: How to Store Passwords Safely

7/30

Salting and Hashing: Practice

First, you need to enable the pgcrypto extension in your database.

pgcrypto is a additional supplied module (a contrib module).

Enable the pgcrypto extension:

> CREATE EXTENSION pgcrypto;

Page 8: PostgreSQL: How to Store Passwords Safely

8/30

Salting and Hashing: Practice

Password Creation

Page 9: PostgreSQL: How to Store Passwords Safely

9/30

Salting and Hashing: Practice

Test; generate a salt string:

salt_string ------------------------------- $2a$06$YmO7UZZZxkTWZfT8s7b/GO

> SELECT gen_salt('bf') AS salt_string;

blowfish algorithm

Page 10: PostgreSQL: How to Store Passwords Safely

10/30

Salting and Hashing: Practice

Test; generate the password hash with the previous salt string:

pw_hash -------------------------------------------------------------- $2a$06$YmO7UZZZxkTWZfT8s7b/GOlO0rZpMhU674srD/dbSyplwO/clTZzi

> SELECT crypt('mypass', '$2a$06$YmO7UZZZxkTWZfT8s7b/GO') AS pw_hash;

Page 11: PostgreSQL: How to Store Passwords Safely

11/30

Salting and Hashing: Practice

Test; comparison with crypt function and previous hash string:

simple_auth_test ------------------ t

> SELECT crypt('mypass', '$2a$06$YmO7UZZZxkTWZfT8s7b/GOlO0rZpMhU674srD/dbSyplwO/clTZzi') = '$2a$06$YmO7UZZZxkTWZfT8s7b/GOlO0rZpMhU674srD/dbSyplwO/clTZzi' AS simple_auth_test;

Page 12: PostgreSQL: How to Store Passwords Safely

12/30

Salting and Hashing: Practice

Create the table:

> CREATE TABLE tb_user( username varchar(50) PRIMARY KEY, -- natural primary key password VARCHAR(72) NOT NULL);

Page 13: PostgreSQL: How to Store Passwords Safely

13/30

Salting and Hashing: Practice

Using CTE* to INSERT new user with password creation:

* CTE = Common Table Expressionshttps://www.postgresql.org/docs/current/static/queries-with.html

> WITH x AS ( SELECT 'foo'::text AS user, '123'::text AS pw, gen_salt('bf')::text AS salt ) INSERT INTO tb_user (username, password) SELECT x.user, crypt(x.pw, x.salt) -- password hash

FROM x;

Page 14: PostgreSQL: How to Store Passwords Safely

14/30

Salting and Hashing: Practice

Enable expanded display automatically (psql):

Querying username and password in the table:

username | password ----------+-------------------------------------------------------------- foo | $2a$06$RqHcf7F.nUGLkQF1fOea.OLAU0gyz/liF3dO58JWTB0oyVirzUdgK

> \x auto

> SELECT username, password FROM tb_user;

Page 15: PostgreSQL: How to Store Passwords Safely

15/30

Salting and Hashing: Practice

Password Verification

Page 16: PostgreSQL: How to Store Passwords Safely

16/30

Salting and Hashing: Practice

User authentication test with correct password:

acessed --------- t

True value (boolean) returned.

> SELECT crypt('123', password) = password AS acessed FROM tb_user WHERE username = 'foo';

Plain text (password) provided by user

Page 17: PostgreSQL: How to Store Passwords Safely

17/30

Salting and Hashing: Practice

User authentication test with wrong password:

acessed --------- f

False value (boolean) returned.

> SELECT crypt('1234', password) = password AS acessed FROM tb_user WHERE username = 'foo';

Page 18: PostgreSQL: How to Store Passwords Safely

18/30

Application Test: The Code (Python)

Continue

#!/usr/bin/env python3# _*_ encoding: utf-8 _*_

from argparse import ArgumentParserfrom getpass import getpassfrom os import systemfrom psycopg2 import connectfrom psycopg2 import Errorfrom sys import exit

Page 19: PostgreSQL: How to Store Passwords Safely

19/30

Application Test: The Code (Python)

Continue

# Argument parserparser = ArgumentParser()

# Argument help strings

help_d = 'Database'help_H = 'Hostname or IP address'help_p = 'Port'help_u = 'Username'help_w = 'With password prompt'

Page 20: PostgreSQL: How to Store Passwords Safely

20/30

Application Test: The Code (Python)

Continue

# Arguments creation

parser.add_argument('-d', '--database', type=str, help=help_d, action='store', metavar='dbname', dest='dbname', default='postgres')parser.add_argument('-H', '--host', type=str, help=help_H, action='store', metavar='dbserver', dest='host', default=None)parser.add_argument('-p', '--port', type=int, help=help_p, action='store', metavar='port_number', dest='port', default=5432)parser.add_argument('-u', '--user', type=str, help=help_u, action='store', metavar='username', dest='user', default='postgres')parser.add_argument('-w', '--with-pass', help=help_w, action='store_true', dest='password')

# Parsed argumentsargs = parser.parse_args()

Page 21: PostgreSQL: How to Store Passwords Safely

21/30

Application Test: The Code (Python)

Continue

# Test if password prompt is requiredif args.password: args.password = getpass('Database user password: ')else: args.password = None

# Connection string variable (initially as a list)conn_str = []

# Take all provided paramaters and make the connection stringfor k, v in vars(args).items(): if v: str_tmp = "{} = '{}'".format(k, v) conn_str.append(str_tmp)conn_str = ' '.join(conn_str)

Page 22: PostgreSQL: How to Store Passwords Safely

22/30

Application Test: The Code (Python)

Continue

# SQL string for PREPARE commandsql_prepare = """PREPARE q_user (text, text) ASSELECT crypt($2, password) = password

FROM tb_user WHERE username = $1;"""

# SQL string for EXECUTE commandsql_execute = "EXECUTE q_user('{}', '{}');"

# When occur authentication error...def user_pw_error(connection): print('\nError: Invalid user and password combination!') connection.close() exit(1)

Page 23: PostgreSQL: How to Store Passwords Safely

23/30

Application Test: The Code (Python)

Continue

try: # Connection conn = connect(conn_str)

# Cursor creation to execute SQL commands cursor = conn.cursor()

# Execute the SQL string in database cursor.execute(sql_prepare)

# Clear Screen system('clear')

# Get user and password of the application app_user = input('\nApplication user: ') app_user_pw = getpass('Application user password: ')

# Execute the SQL string in database cursor.execute(sql_execute.format(app_user, app_user_pw))

Page 24: PostgreSQL: How to Store Passwords Safely

24/30

Application Test: The Code (Python) # The result of the string SQL execution res = cursor.fetchone()

try:

# User login validation if res[0]: print('\nAcessed!') else: raise except: user_pw_error(conn)

except Error as e: print('\nAn error has occurred!') print(format(e)) exit(1)

# Close the database connectionconn.close()

Page 25: PostgreSQL: How to Store Passwords Safely

25/30

Application Test: Execution

$ ./salting.py

A simple test access with correct password:

Application user: fooApplication user password:

Acessed!

Page 26: PostgreSQL: How to Store Passwords Safely

26/30

Application Test: Execution

$ ./salting.py

A simple test access with wrong password:

Application user: fooApplication user password:

Error: Invalid user and password combination!

Page 27: PostgreSQL: How to Store Passwords Safely

27/30

Conclusion

PostgreSQL has its own mechanisms of encryption passwords which makes it very independent of the application.

This makes it easier for the application developer, may delegate such tasks to the database, avoiding technical adjustments in the application and finally provide a robust solution independent of programming language.

Page 28: PostgreSQL: How to Store Passwords Safely

28/30

Donate!

The elephant needs you!

Contribute!

:)

http://www.postgresql.org/about/donate/

Page 29: PostgreSQL: How to Store Passwords Safely

29/30

Save our planet!Save our planet!

Page 30: PostgreSQL: How to Store Passwords Safely

30/30

See you soon!!!

Juliano Atanazio

[email protected]

http://slideshare.net/spjuliano

https://speakerdeck.com/julianometalsp

https://juliano777.wordpress.com

:)


Recommended