{"id":12472,"date":"2019-05-31T05:25:53","date_gmt":"2019-05-31T03:25:53","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/"},"modified":"2019-05-31T05:25:53","modified_gmt":"2019-05-31T03:25:53","slug":"securely-store-passwords-in-postgresql","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/","title":{"rendered":"Securely store passwords in PostgreSQL"},"content":{"rendered":"<p>Every application somehow needs to deal with passwords. Some use external authentication methods such as ldap, others us the the framework the database already provides and create users and roles. But it is also not uncommon that applications implement their own concept for managing users. If an application does this it should be done the right way and passwords should never be stored in plain text in the database. PostgreSQL comes with a handy extension that supports you with that.<\/p>\n<p><!--more--><\/p>\n<p>You might be already aware that PostgreSQL comes with a lot of <a href=\"https:\/\/www.postgresql.org\/docs\/current\/contrib.html\" target=\"_blank\" rel=\"noopener noreferrer\">additional modules<\/a> by default. One of these modules is <a href=\"https:\/\/www.postgresql.org\/docs\/current\/pgcrypto.html\" target=\"_blank\" rel=\"noopener noreferrer\">pgcrypto<\/a> and it can be used for the use case described above: En- and decryption of strings so you do not have to implement that on your own. Lets start with a simple table which contains usernames and their passwords: <\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# create table app_users ( id int generated always as identity ( cache 10 ) primary key\npostgres(#                        , username text not null unique\npostgres(#                        , password text not null\npostgres(#                        );\nCREATE TABLE\npostgres=# d app_users\n                         Table \"public.app_users\"\n  Column  |  Type   | Collation | Nullable |           Default            \n----------+---------+-----------+----------+------------------------------\n id       | integer |           | not null | generated always as identity\n username | text    |           | not null | \n password | text    |           | not null | \nIndexes:\n    \"app_users_pkey\" PRIMARY KEY, btree (id)\n    \"app_users_username_key\" UNIQUE CONSTRAINT, btree (username)\npostgres=# \n<\/pre>\n<p>Both, the username and password columns are implement as plain text. If you keep it like that and just insert data the password of course will be stored as plain text. So how can we use pgcrypto to improve that? Obviously the first step is to install the extension:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1; highlight: [1,8]\">\npostgres=# create extension pgcrypto;\nCREATE EXTENSION\npostgres=# dx\n                   List of installed extensions\n    Name    | Version |   Schema   |         Description          \n------------+---------+------------+------------------------------\n pg_prewarm | 1.2     | public     | prewarm relation data\n pgcrypto   | 1.3     | public     | cryptographic functions\n plpgsql    | 1.0     | pg_catalog | PL\/pgSQL procedural language\n(3 rows)\n<\/pre>\n<p>Btw: There is a catalog view which you can use to list all available extensions:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1; highlight: [1,8]\">\npostgres=# d pg_available_extensions;\n         View \"pg_catalog.pg_available_extensions\"\n      Column       | Type | Collation | Nullable | Default \n-------------------+------+-----------+----------+---------\n name              | name |           |          | \n default_version   | text |           |          | \n installed_version | text | C         |          | \n comment           | text |           |          | \n\npostgres=# select * from pg_available_extensions limit 3;\n  name   | default_version | installed_version |                comment                 \n---------+-----------------+-------------------+----------------------------------------\n plpgsql | 1.0             | 1.0               | PL\/pgSQL procedural language\n plperl  | 1.0             |                   | PL\/Perl procedural language\n plperlu | 1.0             |                   | PL\/PerlU untrusted procedural language\n(3 rows)\n<\/pre>\n<p>The function to use (provided by the pgcrypto module) for encrypting strings is crypt(). This function takes two arguments:<\/p>\n<ul>\n<li>The actual string to encrypt<\/li>\n<li>The salt to use (a random value) for encrpyption<\/li>\n<\/ul>\n<p>Adding a user with an encrypted password is as easy as:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# insert into app_users (username, password) \npostgres-#        values ( 'myuser', crypt('mypassword', gen_salt('bf')) );\nINSERT 0 1\n<\/pre>\n<p>In this case we used the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Blowfish_(cipher)\" target=\"_blank\" rel=\"noopener noreferrer\">Blowfish<\/a> algorithm to generate the salt. You can also use <a href=\"https:\/\/simple.wikipedia.org\/wiki\/MD5\" target=\"_blank\" rel=\"noopener noreferrer\">md5<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/DES-X\" target=\"_blank\" rel=\"noopener noreferrer\">xdes<\/a> and <a href=\"https:\/\/en.wikipedia.org\/wiki\/Data_Encryption_Standard\" target=\"_blank\" rel=\"noopener noreferrer\">des<\/a>.<\/p>\n<p>When we look at the password for our user we will see that it is not plain text anymore:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# select password from app_users where username = 'myuser';\n                           password                           \n--------------------------------------------------------------\n $2a$06$8wu4VWVubv\/RBYBSuj.1TOojPm0q7FkRwuDSoW0OTOC6FzBGEslIC\n(1 row)\n<\/pre>\n<p>This is for the encryption part. For comparing this encrypted string against the plain text version of the string we use the crypt() function again:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# select (password = crypt('mypassword', password)) AS pwd_match \npostgres-#   from app_users\npostgres-#  where username = 'myuser';\n pwd_match \n-----------\n t\n(1 row)\n<\/pre>\n<p>Providing the wrong password of course returns false:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# select (password = crypt('Xmypassword', password)) AS pwd_match \n  from app_users\n where username = 'myuser';\n pwd_match \n-----------\n f\n(1 row)\n<\/pre>\n<p>So finally, it is not much you need to do for storing encrypted strings in PostgreSQL. Just use it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Every application somehow needs to deal with passwords. Some use external authentication methods such as ldap, others us the the framework the database already provides and create users and roles. But it is also not uncommon that applications implement their own concept for managing users. If an application does this it should be done the [&hellip;]<\/p>\n","protected":false},"author":29,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[229],"tags":[77],"type_dbi":[],"class_list":["post-12472","post","type-post","status-publish","format-standard","hentry","category-database-administration-monitoring","tag-postgresql"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.5) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Securely store passwords in PostgreSQL - dbi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Securely store passwords in PostgreSQL\" \/>\n<meta property=\"og:description\" content=\"Every application somehow needs to deal with passwords. Some use external authentication methods such as ldap, others us the the framework the database already provides and create users and roles. But it is also not uncommon that applications implement their own concept for managing users. If an application does this it should be done the [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-05-31T03:25:53+00:00\" \/>\n<meta name=\"author\" content=\"Daniel Westermann\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@westermanndanie\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Daniel Westermann\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/securely-store-passwords-in-postgresql\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/securely-store-passwords-in-postgresql\\\/\"},\"author\":{\"name\":\"Daniel Westermann\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\"},\"headline\":\"Securely store passwords in PostgreSQL\",\"datePublished\":\"2019-05-31T03:25:53+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/securely-store-passwords-in-postgresql\\\/\"},\"wordCount\":345,\"commentCount\":0,\"keywords\":[\"PostgreSQL\"],\"articleSection\":[\"Database Administration &amp; Monitoring\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/securely-store-passwords-in-postgresql\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/securely-store-passwords-in-postgresql\\\/\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/securely-store-passwords-in-postgresql\\\/\",\"name\":\"Securely store passwords in PostgreSQL - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\"},\"datePublished\":\"2019-05-31T03:25:53+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/securely-store-passwords-in-postgresql\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/securely-store-passwords-in-postgresql\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/securely-store-passwords-in-postgresql\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Securely store passwords in PostgreSQL\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\",\"name\":\"Daniel Westermann\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"caption\":\"Daniel Westermann\"},\"description\":\"Daniel Westermann is Principal Consultant and Technology Leader Open Infrastructure at dbi services. He has more than 15 years of experience in management, engineering and optimization of databases and infrastructures, especially on Oracle and PostgreSQL. Since the beginning of his career, he has specialized in Oracle Technologies and is Oracle Certified Professional 12c and Oracle Certified Expert RAC\\\/GridInfra. Over time, Daniel has become increasingly interested in open source technologies, becoming \u201cTechnology Leader Open Infrastructure\u201d and PostgreSQL expert. \u00a0Based on community or EnterpriseDB tools, he develops and installs complex high available solutions with PostgreSQL. He is also a certified PostgreSQL Plus 9.0 Professional and a Postgres Advanced Server 9.4 Professional. He is a regular speaker at PostgreSQL conferences in Switzerland and Europe. Today Daniel is also supporting our customers on AWS services such as AWS RDS, database migrations into the cloud, EC2 and automated infrastructure management with AWS SSM (System Manager). He is a certified AWS Solutions Architect Professional. Prior to dbi services, Daniel was Management System Engineer at LC SYSTEMS-Engineering AG in Basel. Before that, he worked as Oracle Developper &amp;\u00a0Project Manager at Delta Energy Solutions AG in Basel (today Powel AG). Daniel holds a diploma in Business Informatics (DHBW, Germany). His branch-related experience mainly covers the pharma industry, the financial sector, energy, lottery and telecommunications.\",\"sameAs\":[\"https:\\\/\\\/x.com\\\/westermanndanie\"],\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/author\\\/daniel-westermann\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Securely store passwords in PostgreSQL - dbi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/","og_locale":"en_US","og_type":"article","og_title":"Securely store passwords in PostgreSQL","og_description":"Every application somehow needs to deal with passwords. Some use external authentication methods such as ldap, others us the the framework the database already provides and create users and roles. But it is also not uncommon that applications implement their own concept for managing users. If an application does this it should be done the [&hellip;]","og_url":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/","og_site_name":"dbi Blog","article_published_time":"2019-05-31T03:25:53+00:00","author":"Daniel Westermann","twitter_card":"summary_large_image","twitter_creator":"@westermanndanie","twitter_misc":{"Written by":"Daniel Westermann","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/"},"author":{"name":"Daniel Westermann","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66"},"headline":"Securely store passwords in PostgreSQL","datePublished":"2019-05-31T03:25:53+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/"},"wordCount":345,"commentCount":0,"keywords":["PostgreSQL"],"articleSection":["Database Administration &amp; Monitoring"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/","url":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/","name":"Securely store passwords in PostgreSQL - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"datePublished":"2019-05-31T03:25:53+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/securely-store-passwords-in-postgresql\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Securely store passwords in PostgreSQL"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66","name":"Daniel Westermann","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","caption":"Daniel Westermann"},"description":"Daniel Westermann is Principal Consultant and Technology Leader Open Infrastructure at dbi services. He has more than 15 years of experience in management, engineering and optimization of databases and infrastructures, especially on Oracle and PostgreSQL. Since the beginning of his career, he has specialized in Oracle Technologies and is Oracle Certified Professional 12c and Oracle Certified Expert RAC\/GridInfra. Over time, Daniel has become increasingly interested in open source technologies, becoming \u201cTechnology Leader Open Infrastructure\u201d and PostgreSQL expert. \u00a0Based on community or EnterpriseDB tools, he develops and installs complex high available solutions with PostgreSQL. He is also a certified PostgreSQL Plus 9.0 Professional and a Postgres Advanced Server 9.4 Professional. He is a regular speaker at PostgreSQL conferences in Switzerland and Europe. Today Daniel is also supporting our customers on AWS services such as AWS RDS, database migrations into the cloud, EC2 and automated infrastructure management with AWS SSM (System Manager). He is a certified AWS Solutions Architect Professional. Prior to dbi services, Daniel was Management System Engineer at LC SYSTEMS-Engineering AG in Basel. Before that, he worked as Oracle Developper &amp;\u00a0Project Manager at Delta Energy Solutions AG in Basel (today Powel AG). Daniel holds a diploma in Business Informatics (DHBW, Germany). His branch-related experience mainly covers the pharma industry, the financial sector, energy, lottery and telecommunications.","sameAs":["https:\/\/x.com\/westermanndanie"],"url":"https:\/\/www.dbi-services.com\/blog\/author\/daniel-westermann\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/12472","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/29"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=12472"}],"version-history":[{"count":0,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/12472\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=12472"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=12472"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=12472"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=12472"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}