<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: chris</title>
    <description>The latest articles on DEV Community by chris (@cristiancfm).</description>
    <link>https://dev.to/cristiancfm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1825613%2Fafe2ddf5-af64-433e-b964-a082748f7007.jpeg</url>
      <title>DEV Community: chris</title>
      <link>https://dev.to/cristiancfm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cristiancfm"/>
    <language>en</language>
    <item>
      <title>Encrypting PostgreSQL database columns in Spring Boot JPA entities</title>
      <dc:creator>chris</dc:creator>
      <pubDate>Wed, 24 Jul 2024 08:20:54 +0000</pubDate>
      <link>https://dev.to/cristiancfm/encrypting-postgresql-database-columns-in-spring-boot-jpa-entities-4915</link>
      <guid>https://dev.to/cristiancfm/encrypting-postgresql-database-columns-in-spring-boot-jpa-entities-4915</guid>
      <description>&lt;p&gt;A simple tutorial on how to encrypt single columns in a PostgreSQL database using JPA entities in a Spring Boot project. Let's start!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv9qurkd44kyqq28x0f5d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv9qurkd44kyqq28x0f5d.png" alt="Database with encrypted columns"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Storing the encryption key
&lt;/h2&gt;

&lt;p&gt;We will use a property in the &lt;em&gt;application.yml&lt;/em&gt; file to store the encryption key. &lt;/p&gt;

&lt;p&gt;⚠ This is not the best practice in a production environment, so consider looking for a more secure way.&lt;/p&gt;

&lt;p&gt;Create a property called &lt;code&gt;encryptionSecretKey&lt;/code&gt; in the &lt;em&gt;application.yml&lt;/em&gt; file under &lt;code&gt;security-properties&lt;/code&gt; &amp;gt; &lt;code&gt;security&lt;/code&gt; and assign it a random string:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;security-properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;encryptionSecretKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1234567890123456&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can use a different property instead, but make sure to adapt the code from the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Making the key available to the database
&lt;/h2&gt;

&lt;p&gt;We have to create a temporary parameter in the database to store the key, in order to access it in the next step. The &lt;code&gt;set_config()&lt;/code&gt; function from PostgreSQL is what we need.&lt;/p&gt;

&lt;p&gt;Create a property called &lt;code&gt;connectionInitSql&lt;/code&gt; in the &lt;em&gt;application.yml&lt;/em&gt; file under &lt;code&gt;spring&lt;/code&gt; &amp;gt; &lt;code&gt;datasource&lt;/code&gt; &amp;gt; &lt;code&gt;hikari&lt;/code&gt; and assign it the following query:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hikari&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;connectionInitSql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;select set_config('encryption.key', '${security-properties.encryptionSecretKey}', &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This code will run the function &lt;code&gt;set_config( setting_name, new_value, is_local)&lt;/code&gt; each time a new database connection is created. The third parameter of the function is set to &lt;code&gt;false&lt;/code&gt;, so the encryption key will apply to the current database session instead of the current transaction only.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Adding the &lt;code&gt;pgcrypto&lt;/code&gt; extension
&lt;/h2&gt;

&lt;p&gt;The database needs to have the &lt;em&gt;pgcrypto&lt;/em&gt; extension added to work properly. Execute this query on a database console:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="c1"&gt;-- Create pgcrypto extension&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;pgcrypto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  4. Encrypting the actual data
&lt;/h2&gt;

&lt;p&gt;We have an entity called &lt;em&gt;UMUser&lt;/em&gt; with an email and a login field that need to be encrypted. We just need to add the annotations &lt;code&gt;@ColumnTransformer&lt;/code&gt; and &lt;code&gt;@Column&lt;/code&gt; to each one:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="cm"&gt;/** An user. */&lt;/span&gt;
&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Table&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"um_user"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UMUser&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="nd"&gt;@ColumnTransformer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pgp_sym_decrypt("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"login, "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"current_setting('encryption.key')"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;")"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;write&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pgp_sym_encrypt("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"?::text,"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"current_setting('encryption.key')"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;")"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
  &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"login"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columnDefinition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"bytea"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@ColumnTransformer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pgp_sym_decrypt("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"email, "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"current_setting('encryption.key')"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;")"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;write&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pgp_sym_encrypt("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"?::text,"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"current_setting('encryption.key')"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;")"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nd"&gt;@Column&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columnDefinition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"bytea"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;See how we use the &lt;code&gt;pgp_sym_decrypt()&lt;/code&gt; and &lt;code&gt;pgp_sym_encrypt()&lt;/code&gt; functions from PostgreSQL, which access the key to read and write the fields using &lt;code&gt;current_setting()&lt;/code&gt;. The &lt;code&gt;@Column&lt;/code&gt; annotation needs to include &lt;code&gt;columnDefinition = "bytea"&lt;/code&gt;, since the encrypted value is stored in bytes.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>springboot</category>
      <category>postgres</category>
    </item>
  </channel>
</rss>
