<?xml version="1.0" encoding="UTF-8" ?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" version="2.0"><channel><title>Caitlin Strong | CrunchyData Blog</title>
<atom:link href="https://www.crunchydata.com/blog/author/caitlin-strong/rss.xml" rel="self" type="application/rss+xml" />
<link>https://www.crunchydata.com/blog/author/caitlin-strong</link>
<image><url>https://www.crunchydata.com/build/_assets/default.png-W4XGD4DB.webp</url>
<title>Caitlin Strong | CrunchyData Blog</title>
<link>https://www.crunchydata.com/blog/author/caitlin-strong</link>
<width>256</width>
<height>256</height></image>
<description>PostgreSQL experts from Crunchy Data share advice, performance tips, and guides on successfully running PostgreSQL and Kubernetes solutions</description>
<language>en-us</language>
<pubDate>Wed, 03 Nov 2021 05:00:00 EDT</pubDate>
<dc:date>2021-11-03T09:00:00.000Z</dc:date>
<dc:language>en-us</dc:language>
<sy:updatePeriod>hourly</sy:updatePeriod>
<sy:updateFrequency>1</sy:updateFrequency>
<item><title><![CDATA[ Patroni & etcd in High Availability Environments ]]></title>
<link>https://www.crunchydata.com/blog/patroni-etcd-in-high-availability-environments</link>
<description><![CDATA[ A deep dive into Patroni, etcd, and the etcd consensus protocol to diagnose common communication and system issues. ]]></description>
<content:encoded><![CDATA[ <p>Crunchy Data products often include High Availability. <a href=https://access.crunchydata.com/documentation/patroni/latest/>Patroni</a> and etcd are two of our go-to tools for managing those environments. Today I wanted to explore how these work together. Patroni relies on proper operation of the etcd cluster to decide what to do with PostgreSQL. When communication between these two pieces breaks down, it creates instability in the environment resulting in failover, cluster restart, and even the the loss of a primary database. To fully understand the importance of this relationship, we need to understand a few core concepts of how these pieces work. First, we'll start with a brief overview of the components involved in HA systems and their role in the environment.<h2 id=overview-of-ha-infrastructure><a href=#overview-of-ha-infrastructure>Overview of HA Infrastructure</a></h2><p><a href=/blog/database-terminology-explained-postgres-high-availability-and-disaster-recovery>HA systems</a> can be setup in a single or multi-datacenter configuration. Crunchy supports HA on <a href=https://www.crunchydata.com/products/crunchy-bridge>cloud</a>, <a href=https://www.crunchydata.com/products/crunchy-high-availability-postgresql>traditional</a>, or <a href=https://www.crunchydata.com/products/crunchy-postgresql-for-kubernetes>containerized</a> infrastructure. When used in a single datacenter, the environment is typically setup as a 3-node cluster on three separate database hosts. When used across multiple datacenters, the environment typically has an active datacenter, where the primary HA cluster and applications are running, and one or more standby datacenters, each containing a replica HA cluster that is always available. Although the setup may be different, the basic components and <a href=https://www.crunchydata.com/case-studies/top-6-canada-bank>primary function of the environment</a> remains the same.<h3 id=main-ha-components><a href=#main-ha-components>Main HA components</a></h3><p>For this article, we will focus on three basic components which are essential in both single datacenter and multi-datacenter environments:<ul><li>PostgreSQL cluster: the database cluster, usually consisting of a primary and two or more replicas<li>Patroni: used as the failover management utility<li>etcd: used as a <dfn>distributed configuration store</dfn> (<abbr>DCS</abbr>), containing cluster information such as configuration, health, and current status.</ul><h3 id=how-ha-components-work-together><a href=#how-ha-components-work-together>How HA components work together</a></h3><p>Each PostgreSQL instance within the cluster has one application database. These instances are kept in sync through streaming replication. Each database host has its own Patroni instance which monitors the health of its PostgreSQL database and stores this information in etcd. The Patroni instances use this data to:<ul><li>keep track of which database instance is primary<li>maintain quorum among available replicas and keep track of which replica is the most "current"<li>determine what to do in order to keep the cluster healthy as a whole</ul><p>Patroni manages the instances by periodically sending out a heartbeat request to etcd which communicates the health and status of the PostgreSQL instance. etcd records this information and sends a response back to Patroni. The process is similar to a heart monitoring device. Consistent, periodic pulses indicate a healthy database.<h3 id=etcd-consensus-protocol><a href=#etcd-consensus-protocol>etcd Consensus Protocol</a></h3><p>The etcd consensus protocol requires etcd cluster members to write every request down to disk, making it very sensitive to disk write latency. If Patroni receives an answer from etcd indicating the primary is healthy before the heartbeat times out, the replicas will continue to follow the current primary.<p>If the etcd system cannot verify writes before the heartbeats time out, or if the primary instance fails to renew its status as leader, Patroni will assume the cluster member is unhealthy and put the database into a fail-safe configuration. This will trigger an election to promote a new leader and the old primary is demoted and becomes a replica.<p><img alt="etcd consensus"loading=lazy src=https://fs.hubspotusercontent00.net/hubfs/2283855/etcd%20consensus.png><h2 id=common-causes-of-communication-failures><a href=#common-causes-of-communication-failures>Common Causes of Communication Failures</a></h2><p>Communication failure between Patroni and etcd is one of the most common reasons for failover in HA environments. Some of the most common reasons for communication issues are:<ul><li>an under-resourced file system<li>I/O contention in the environment<li>network transit timeouts</ul><h3 id=under-resourced-file-system><a href=#under-resourced-file-system>Under-resourced file system</a></h3><p>Because HA solutions must be sufficiently resourced at all points at all times to work well, the proper resources must be available to the etcd server in order to mitigate failovers. As mentioned before, etcd consensus protocol requires etcd cluster members to write every request down to disk and every time a key is updated for a cluster, a new revision is created. When the system runs low on space (usage above 75%), etcd goes read/delete only until revisions and keys are removed or disk space is added. For optimal performance, we recommend keeping disk usage below 75%.<h3 id=io-contention><a href=#io-contention>I/O contention</a></h3><p>The etcd consensus protocol requires etcd cluster members to write every request down to disk, making it very sensitive to disk write latency. Systems under heavy loads, particularly during peak or maintenance hours, are susceptible to I/O bottlenecks as processes are forced to compete for resources. This contention can increase I/O wait time and prevent Patroni from receiving an answer from etcd before the heartbeat times out. This is especially true when running virtual machines as neighboring machines can impact I/O. Other sources of contention might be heavy I/O from PostgreSQL and excessive paging due to high connection rates and/or memory starvation.<h3 id=network-delay><a href=#network-delay>Network Delay</a></h3><p>The etcd system, which is critical for the stability of the HA solution, is experiencing issues that register as network transit timeouts. This could be due to either actual network timeouts or massive resource starvation at the etcd level. If you notice timeout errors typically coincide with periods of heavy network traffic, then network delay could be the root cause of these timeout errors.<h2 id=diagnosing-the-system><a href=#diagnosing-the-system>Diagnosing the system</a></h2><h3 id=confirm-the-issue><a href=#confirm-the-issue>Confirm the issue</a></h3><p>When troubleshooting your system, the best place to start is by checking the logs. If communication issues between Patroni and etcd are at the heart of the issue, you will most likely see errors in your log files like the examples below.<p>First, check PostgreSQL logs in order to rule out any issues with the PostgreSQL host itself. By default, these logs are stored under <code>pg_log</code> in the PostgreSQL data directory. If your logs are not in the default location, you can determine the exact location by running the command <code>show log_directory ;</code> in the database. Check for any indication of other PostgreSQL processes crashing or being killed prior to the error message. For example:<pre><code class=language-text>WARNING:  terminating connection because of crash of another server process
DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
HINT:  In a moment you should be able to reconnect to the database and repeat your command.
</code></pre><p>If no other PostgreSQL processes crashed, check the Patroni logs for any errors or events that may have occurred shortly before this error was logged by PostgreSQL. Messages like <code>demoted self because failed to update leader lock in DCS</code> and <code>Loop time exceeded</code> indicate communication and timeout issues with etcd.<pre><code class=language-text>Feb  1 13:45:05 patroni: 2021-02-01 13:45:05,510 INFO: Selected new etcd server http://10.84.32.146:2379
Feb  1 13:45:05 patroni: 2021-02-01 13:45:05,683 INFO: demoted self because failed to update leader lock in DCS
Feb  1 13:45:05 patroni: 2021-02-01 13:45:05,684 WARNING: Loop time exceeded, rescheduling immediately.
Feb  1 13:45:05 patroni: 2021-02-01 13:45:05,686 INFO: closed patroni connection to the postgresql cluster
Feb  1 13:45:05 patroni: 2021-02-01 13:45:05,705 INFO: Lock owner: None; I am pg1
Feb  1 13:45:05 patroni: 2021-02-01 13:45:05,706 INFO: not healthy enough for leader race
Feb  1 13:45:06 patroni: 2021-02-01 13:45:06,657 INFO: starting after demotion in progress
Feb  1 13:45:09 patroni: 2021-02-01 13:45:09,521 INFO: postmaster pid=1521
Feb  1 13:45:11 patroni: /var/run/postgresql:5434 - rejecting connections
</code></pre><p>If you see a message like the one above, the next step is to check etcd logs. Look for messages logged right before the message logged in the Patroni logs. If communication issues are to blame for your environment's behavior, you will likely see errors like the one below.<pre><code class=language-text>Feb  1 13:44:21 etcd: failed to send out heartbeat on time (exceeded the 100ms timeout for 39.177252ms)
Feb  1 13:44:21 etcd: server is likely overloaded
</code></pre><h3 id=narrow-down-the-cause><a href=#narrow-down-the-cause>Narrow down the cause</a></h3><h4 id=check-disk-space><a href=#check-disk-space>Check disk space</a></h4><p>To see if a lack of disk space is the root of the problem, check the disk space available to the etcd system by running the linux command <code>df</code> on the etcd directory, typically <code>/var/lib/etcd</code>. The disk space available to this directory should be checked on all servers, including the Patroni server. For optimal performance, we recommend keeping disk usage below 75%. If the amount of space used is approaching or exceeding 75%, then allocating more space to this directory may resolve the issue. (More information in the Recommendation section further below.)<h4 id=analyze-performance-metrics><a href=#analyze-performance-metrics>Analyze performance metrics</a></h4><p>If the file system still has plenty of space available, we will need to dig deeper to find the source of the problem by analyzing the overall performance of the system. A good place to start is with the <code>sar</code> command which is part of the Linux <code>sysstat</code> package and can be run on the system by any user. This command provides additional information about the system, such as system load, memory and CPU usage which can be used to pinpoint any bottlenecks or pain points in your system. By default, the command displays CPU activity and collects these statistics every 10 minutes.<p>The nice thing about <code>sar</code> is that it stores historical data by default with a one-month retention. On RHEL/CentOS/Fedora distributions, this data is stored under <code>/var/log/sa/</code> for Debian/Ubuntu systems, it's stored under <code>/var/log/sysstat/</code>. The log files are named <code>sa*dd*</code>, where <code>dd</code> represents the day of the month. For example, the log file for the first of the month would be <code>sa01</code>, the file for the 15th would be <code>sa15</code>.<p>This means that if the <code>sysstat</code> package was installed and running on the server when the etcd timeout occurred, we can go back and analyze the performance data around the time of the incident. <strong>Note:</strong> Because the <code>sar</code> command only reports on local activities, each of the servers in the etcd quorum will need to be checked. If the <code>sysstat</code> package was not installed or was not running during the time of the incident, it will need to be installed and enabled so that this information will be available the next time the etcd timeout issue occurs. For our purposes, we will assume the package was running.<p>Going back to the etcd log example we looked at earlier, we can see that the timeout issue occurred at 13:44:21 on the first of the month. By specifying the relevant file name along with a start and end time in our <code>sar</code> command, we can extract the information relevant to the time of the incident. <em>Note:</em> Use a start time slightly before the timestamp of the error in order to see the state of the system before the timeout was triggered. For example:<pre><code class=language-shell>sar -f /var/log/sa/sa01 -s 13:35:00 -e 13:50:00
</code></pre><p>Where:<ul><li><code>-f</code>: file name and path<li><code>-s</code>: start time, in HH:MM:SS format<li><code>-e</code>: end time, in HH:MM:SS format</ul><p>Should give us an output that looks something like:<pre><code class=language-shell>$ sar -f /var/log/sa/sa01 -s 13:30:00 -e 13:51:00

01:30:01 PM     CPU      %usr     %nice      %sys    %iowait    %steal    %idle
01:40:01 PM     all      2.71      0.00      2.02      0.92      0.00     94.32
01:50:01 PM     all      2.10      0.00      1.79      7.86      0.00     88.22
Average:        all      2.41      0.00      1.91      4.39      0.00     91.27
</code></pre><p>Here we can see a jump in <code>%iowait</code> between 1:40pm and 1:50pm, indicating a sudden burst of activity around the time of the etcd error, as suspected.<p>Adding the <code>-d</code> flag to the command will let us take a closer look at each device block and allow us to compare how long the I/O request took from start to finish (<code>await</code> column) with how long the requests actually took to complete (the <code>svctm</code> column):<pre><code class=language-shell>$ sar -f /var/log/sa/sa01 -s 13:30:00 -e 13:51:00 -d

01:30:01 PM       DEV       tps  rd_sec/s  wr_sec/s  avgrq-sz  avgqu-sz     await     svctm     %util
01:40:01 PM    dev8-0      4.36      2.19     49.63     11.88      0.03      7.59      5.67      2.47
01:40:01 PM    dev8-1      0.66      1.92    317.55    480.49      0.05     74.76      6.63      0.44
01:40:01 PM    dev8-2      0.09      0.85      1.05     21.13      0.00      4.31      4.31      0.04
01:40:01 PM    dev8-3      7.14      0.43    175.16     24.58      0.06      7.97      3.81      2.72
01:50:01 PM    dev8-0      4.40      1.91     45.88     10.86      1.00    226.16     28.65     12.61
01:50:01 PM    dev8-1      0.48      0.00     10.07     20.83      0.12    245.13     73.72      3.56
01:50:01 PM    dev8-2      0.24      0.00     57.48    241.24      0.27   1123.66    235.00      5.60
01:50:01 PM    dev8-3      6.91      0.01    165.57     23.98      0.78    112.61     19.24     13.28
</code></pre><p>Since requests can lose time waiting in a queue if the device is already busy and won't accept additional concurrent requests, it is not unusual for the service time to be <em>slightly</em> smaller than the waiting time. However, in this example we can see that I/O requests on dev8-2 took an average of 1123.66ms from start to finish even though they only took an average of 235ms to actually complete, which is a significant increase from where is was previously, when both <code>await</code> and <code>svctm</code> only took 4.31ms. Considering these times are averages, it isn't hard to imagine that any spikes that may have occurred were likely much higher than the time shown in this output. If you find similar jumps in your environment, then an under-resourced system is likely the cause of the timeout errors.<h2 id=solutions-and-suggested-steps><a href=#solutions-and-suggested-steps>Solutions and Suggested Steps</a></h2><p>Now that we have a better idea of what might be causing the issue, here are some things we can do to fix it:<h3 id=increase-resources><a href=#increase-resources>Increase resources</a></h3><p>If the etcd directory is running low on space (i.e. the amount of space used is approaching or exceeding 75%), allocate more disk space to this directory and see if the heartbeat timeout issue is resolved. Similarly, if you find spikes of <code>%iowait</code> and I/O contention that correlate with the time of the timeout incident, we recommend increasing the IOPS on all systems running the etcd quorum.<h3 id=find-the-cause-of-io-spikes><a href=#find-the-cause-of-io-spikes>Find the cause of I/O spikes</a></h3><p>While increasing resources may help in the short term, identifying the cause of the await jump is key to determining a long-term solution. Work with your systems administrator to diagnose and resolve the underlying cause of I/O contention in your environment.<h3 id=relocate-your-etcd><a href=#relocate-your-etcd>Relocate your etcd</a></h3><p>If etcd is sharing a storage device with another resource, consider relocating the etcd data to its own dedicated device to ensure that etcd has a dedicated I/O queue for any I/O that it needs. In a multi-node environment, this means one node should be dedicated entirely to etcd. For optimum performance choose a device with low-latency networking and low-latency storage I/O.<p>Please note: If the underlying issue is the disk itself, rather than just the disk performance, moving the etcd data to a new storage device may not fully correct the issue if other parts of the cluster are still reliant on the disk.<h3 id=resolve-network-delay><a href=#resolve-network-delay>Resolve network delay</a></h3><p>If communication errors persist after you have increased resources to the etcd system, then the only remaining cause is network delay. For a long-term solution, you will need to work with your network administrator to diagnose and resolve the underlying cause of network delay in your environment.<h3 id=increase-timeout-intervals><a href=#increase-timeout-intervals>Increase Timeout Intervals</a></h3><p>While increasing resources and resolving the underlying issue of I/O contention and/or network delay are the only way to fully resolve the issue, a short-term solution to the problem would be to increase the timeout interval. This will give etcd more time to verify and write requests to disk before timing out and Patroni triggers an election.<p>If you are using <a href=https://www.crunchydata.com/products/crunchy-high-availability-postgresql>Crunchy Data's High-Availability</a> solution, this can be accomplished by changing the <code>heartbeat_interval</code> parameter in your <code>group_vars/etcd.yml</code> file and rerunning your playbook. Below is an example as to how it should look like:<pre><code class=language-yaml>etcd_user_member_parameters:
  heartbeat_interval: &#60value>
</code></pre><p>If you are using another solution in your environment, you should be able to increase this setting by changing the parameter in your etcd configuration file, typically located under <code>/etc/default/etcd</code>.<p><strong>IMPORTANT</strong>: Setting the heartbeat interval to a value that's too high will result in long election timeouts and the etcd cluster will take longer to detect leader failure. This should be treated as a last-ditch effort and only used as a way of mitigating the issue until the underlying cause can be diagnosed and resolved.<h2 id=conclusion><a href=#conclusion>Conclusion</a></h2><p>Hopefully you now have a better understanding of why Patroni's timely and consistent communication with etcd is essential to maintaining a healthy HA environment as well what you can do to diagnose and fix communication issues between the two.<p>Crunchy Data strongly recommends ensuring a good, reliable network to your DCS to prevent failover from occurring. We also strongly recommend <a href=/blog/postgresql-monitoring-for-application-developers-dba-stats>monitoring</a> your environment for disk space issues, archiving issues, failover occurrences, and replication slot failures. ]]></content:encoded>
<category><![CDATA[ Production Postgres ]]></category>
<author><![CDATA[ Caitlin.Strong@crunchydata.com (Caitlin Strong) ]]></author>
<dc:creator><![CDATA[ Caitlin Strong ]]></dc:creator>
<guid isPermalink="false">https://blog.crunchydata.com/blog/patroni-etcd-in-high-availability-environments</guid>
<pubDate>Wed, 03 Nov 2021 05:00:00 EDT</pubDate>
<dc:date>2021-11-03T09:00:00.000Z</dc:date>
<atom:updated>2021-11-03T09:00:00.000Z</atom:updated></item>
<item><title><![CDATA[ Preventing SQL Injection Attacks in Postgres ]]></title>
<link>https://www.crunchydata.com/blog/preventing-sql-injection-attacks-in-postgresql</link>
<description><![CDATA[ Learn about SQL injection attacks and how to prevent them in Postgres. ]]></description>
<content:encoded><![CDATA[ <p>More and more frequently, customers are being given access to company databases for purposes of account management, receiving customer support, or placing and tracking an order. Although this provides great convenience for the end user, it also opens the database up to <a href=/blog/postgresql-defaults-and-impact-on-security-part-1>certain vulnerabilities</a>. Any feature that allows a user to search or edit content within a database runs the risk of an attacker exploiting this feature to obtain additional access to company information. When a user subverts the original intent of your SQL statements, this is known as a SQL injection attack.<p>What are SQL injection attacks?<p>SQL injection attacks are malicious attacks in which data is “injected” into your SQL query using certain destructive phrases or unescaped parameters. Hackers use this technique to gain access to business data and personal information, as well as modify or delete the content within your database. One of the most recent examples of a SQLi attack is the <a href=https://www.bleepingcomputer.com/news/security/new-meow-attack-has-deleted-almost-4-000-unsecured-databases/>“Meow” attack</a>, which wiped out nearly 4,000 unsecured databases in July 2020.<p>Typically, attacks occur through a web interface, such as a web page or application, that allows users to search the database or log in to an account. Many times this is done through automated scripts. If inputs on your web application are not properly validated and escaped, attackers can use these features to alter your database with destructive phrases such as <code>DROP TABLE</code>, <code>DELETE FROM</code>, <a href=/blog/a-walk-through-insert><code>INSERT</code></a>, <code>UPDATE</code>, a double-dashed sequence ‘--’, or a semicolon <code>;</code>, or download your entire database using <code>SELECT</code> statements.<p>Needless to say, the fallout from these kinds of attacks can be devastating, not only to the contents of your database, but to the integrity and reputation of your company as well.<h2 id=types-of-sql-injection-attacks><a href=#types-of-sql-injection-attacks>Types of SQL injection Attacks</a></h2><p>SQL injection attacks fall under three main categories: In-band (also known as “classic” or “simple” attacks), inferential (or “blind”), and out-of-band attacks.<h3 id=in-band-attacks><a href=#in-band-attacks>In-band Attacks</a></h3><p>In a simple, or in-band attack, commands are sent to the database in order to extract content and return results directly to the end user. Even error messages from invalid inputs can be used to determine the underlying structure of the database, which can then be exploited to extract data from other tables in the database through restructuring the original query. For example, if a website lets customers to track their orders online by calling the database with a SQL statement such as the following:<pre><code class=language-pgsql>SELECT * FROM orders WHERE order_id= ‘ user + input ’
</code></pre><p>A hacker could exploit this statement to extract additional information from the database by appending a simple <code>UNION SELECT</code> statement onto an order number. Something like:<pre><code class=language-pgsql>SELECT * FROM orders WHERE order_id= ‘123 UNION SELECT username, password from customers --’
</code></pre><p>would return information about order number 123, along with the usernames and passwords of all customers in the database.<h3 id=inferential-blind-attacks><a href=#inferential-blind-attacks>Inferential (Blind) Attacks</a></h3><p>With inferential, or blind attacks, an attacker sends commands to the database but does not receive any content back. Instead, this technique is used to learn as much about the system’s behavior as possible. There are two main types of inferential attacks, boolean based and time based. Boolean based attacks use true or false statements to extract information based on whether the web browser reloads with either an empty or non-empty response. Time based attacks can use functions like pg_sleep, or be used in conjunction with boolean based attacks to gather information from the database based on the time it takes the web browser to reload.<h3 id=out-of-band-attacks><a href=#out-of-band-attacks>Out-of-band Attacks</a></h3><p>Out-of-band attacks are reserved for cases when the data cannot be extracted through the same channel that is gathering information about the system, such as when dealing with slow, unstable systems, or systems under heavy loads. Hackers use this technique to send data to an external server that the hacker controls using DNS requests or UTL_HTTP packages.<h2 id=prevention><a href=#prevention>Prevention</a></h2><p>Now that we know what SQL injection attacks are, the question is, how do you prevent them from happening? Luckily, there are some simple steps you can take to protect yourself and your system from attacks.<h3 id=validating-inputs><a href=#validating-inputs>Validating inputs</a></h3><p>First and foremost, inputs from SQL statements should be validated, or “sanitized”, before being sent to the database. This can be done by making use of parameterized SQL statements, which separate the query statements from the data. Parameterized statements use stored queries that have markers, known as parameters, to represent the input data. Instead of parsing the query and the data as a single string, the database reads only the stored query as query language, allowing user inputs to be sent as a list of parameters that the database can treat solely as data.<p>As an added precaution, parameterized statements can be set to deny the caller the right to execute certain commands such as <code>DROP TABLE</code>. You can also run all inputs through a filter to weed out certain destructive phrases such as <code>DROP TABLE</code>, <code>DELETE FROM</code>, <code>SELECT * FROM</code>, a double-dashed sequence ‘--’, or a semicolon <code>;</code>.<h3 id=proactive-monitoring><a href=#proactive-monitoring>Proactive monitoring</a></h3><p>The best way to find suspicious activity is to be proactive in looking for suspicious activity. <a href=/blog/pgaudit-auditing-database-operations-part-1>Database audits</a>, along with regularly reviewing log statements, will help identify any potential threats to your system.<h3 id=audit-your-database><a href=#audit-your-database>Audit your database</a></h3><p>Regular auditing and vacuuming will help maintain your PostgreSQL environment. Extensions like <a href=https://www.pgaudit.org/>pg_audit</a> provide a deeper level of detailed session and object logging than the standard logging found in PostgreSQL. This level of detail can help pinpoint any unusual or irregular queries; for example, queries to system tables. System tables, like those found under the information_schema, are not regularly accessed by users and should be treated with suspicion. Auditing also provides information about which tables, views, procedures, and functions are no longer in use. Removing these items reduces the chances of an attacker injecting them with malicious code which can go undetected for years. Check out this blog post for more information about <a href=https://www.crunchydata.com/blog/pgaudit-auditing-database-operations-part-1>auditing your database operations</a>.<h3 id=adjust-default-settings-in-postgresql><a href=#adjust-default-settings-in-postgresql>Adjust default settings in PostgreSQL</a></h3><p>Consider <a href=/blog/optimize-postgresql-server-performance>adjusting the default PostgreSQL settings</a> to maximize information captured in your log files. A good place to start is with the <code>log_statement</code> and <code>log_min_error_statement</code> parameters in your postgresql.conf file. (Note: these changes must be set by a superuser.)<pre><code class=language-pgsql>log_statement = all
log_min_error_statement = ERROR
</code></pre><p>As these settings will increase the size of your log files, you will need to adjust your storage settings and log backup procedures accordingly. By setting the <code>log_statement</code> parameter to “all”, log files will capture all SQL statements executed in the database. The only exception would be statements that contain simple syntax errors because these statements fail before the execute phase. These statements can be captured by setting the <code>log_min_error_statement</code> parameter to “ERROR”.<p>More information on logging can be found in the <a href=https://www.postgresql.org/docs/12/runtime-config-logging.html>PostgreSQL documentation</a>.<h3 id=securing-your-system><a href=#securing-your-system>Securing your system</a></h3><p>While monitoring your system and validating inputs are the best ways to guard against attacks, there are a few additional steps you can take to secure your system.<ul><li>Turn off external customer user visibility of database errors on live production sites to avoid revealing information about system structure and behavior.<li>Make sure any applications which connect to the database do not use accounts with administrator privileges, especially web applications.<li>Keep your OS and PostgreSQL up to date with the latest security patches.<li>Use vulnerability scanners and <dfn>web application firewalls</dfn> (<abbr>WAFs</abbr>) to make sure your applications are secure before being released to production servers.</ul><h2 id=detecting-attacks><a href=#detecting-attacks>Detecting Attacks</a></h2><p>While the steps above will help protect your system against attacks, nothing is infallible. Hackers are relentlessly refining their techniques, and all systems are vulnerable to attack.<p>If you suspect your database has been compromised, the first thing you should do is shut down your system. Then, go through and analyze your logs, to find any potential holes that may have been exploited. Some key things to look for are:<ul><li>SQL errors. Attacks almost always generate SQL errors so this is a good place to start. It’s also the best way to detect an attack while it’s happening.<li>Permissions errors. Any time an unauthorized user tries to access or modify the database, it could indicate an attack.<li>References to system tables. Attackers don’t always know your specific table names, so queries to system tables should raise a red flag.</ul><p>Once you have identified and patched any potential points of entry, it is a good idea to go back and review your application code. Using version control when writing new code and procedures will allow you to detect where SQL injection holes originated. On this note, it always helps to have another application developer check your code to point out any potential areas that could be exploited.<h2 id=conclusion><a href=#conclusion>Conclusion</a></h2><p>SQL injection attacks can be detrimental not only to your data, but to your company’s reputation and integrity as well. Unfortunately, there is no silver bullet solution to prevent these attacks, but by implementing simple safeguards, such as sanitizing SQL inputs and proactive monitoring, you can mitigate your chances of an attack, while detailed logging can provide you with a roadmap for identifying potential vulnerabilities within your system.<h3 id=further-reading><a href=#further-reading>Further Reading</a></h3><p><a href=/blog/pgaudit-auditing-database-operations-part-1>Auditing your database</a><p><a href=https://www.postgresql.org/docs/12/runtime-config-logging.html>PostgreSQL Error Reporting and Logging</a> ]]></content:encoded>
<category><![CDATA[ Production Postgres ]]></category>
<author><![CDATA[ Caitlin.Strong@crunchydata.com (Caitlin Strong) ]]></author>
<dc:creator><![CDATA[ Caitlin Strong ]]></dc:creator>
<guid isPermalink="false">https://blog.crunchydata.com/blog/preventing-sql-injection-attacks-in-postgresql</guid>
<pubDate>Thu, 20 Aug 2020 05:00:00 EDT</pubDate>
<dc:date>2020-08-20T09:00:00.000Z</dc:date>
<atom:updated>2020-08-20T09:00:00.000Z</atom:updated></item></channel></rss>