# PostgreSQL 連線安全設定指南
最近在看資料庫的 log 時發現以下的 log 。
這就表示有人在嘗試以 postgres
這個帳號登入,那當然這就是很典型的入侵攻擊,那透過程式可以暴力嘗試大量的密碼,最終就可以獲得 postgres
這個帳號的密碼,接著就會進行一系列的攻擊。
那可以藉由一些機制來調整 PostgreSQL 的設定,透過正確地調整設定可以減少被入侵攻擊的風險。
# postgresql.conf
其中有兩個設定 listen_addresses
, port
是跟連線相關的。
# listen_addresses
listen_addresses = 'localhost' # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to 'localhost'; use '*' for all
# (change requires restart)
port = 5432 # (change requires restart)
listen_addresses
預設是 localhost
,如果你的 Web Application 與 DB 是在同一台主機的話,用這樣的設定最好,PostgreSQL 就只會綁定在 localhost 上,所以也只能接受 localhost 的連線。
用 netstat
看會是這樣的狀態,PostgreSQL 就只有 LISTEN 127.0.0.1:5432
。
# netstat -na | grep LIST
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
如果設定為 *
就會綁定到主機所有可用的 IP 上。
用 netstat
看會是這樣的狀態,PostgreSQL 會 LISTEN 0.0.0.0:5432
跟 :::5432
。
# netstat -na | grep LIST
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:5432 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 :::5432 :::* LISTEN
如果 Web Application 跟 DB 不在同一台主機,但是在同一個區網內,也可以設定 localhost, 192.168.0.1
這樣就會綁定在 localhost 跟 192.168.0.1 上面,這樣 DB 就可以接受同一個區網的連線。
用 netstat
看會是這樣的狀態,PostgreSQL 會 LISTEN 127.0.0.1:5432
跟 192.168.0.1:5432
。
# netstat -na | grep LIST
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 192.168.0.1:5432 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
如果你的 Web Application 與 DB 是在同一台主機或同個區網的話,基本上建議就綁在 localhost 或是區網的 IP 這樣就可以減少 PostgreSQL 受到嘗試登入的攻擊。
# port
如果 PostgreSQL 一定得綁在 Public IP 上面的話,建議可以更改 port ,這樣也可以減少受到嘗試登入的攻擊。因為無目的性的入侵大概就是用工具掃 IP 跟 port ,用PostgreSQL 預設 port 5432 就比較容易被掃到,雖然改 port 有點鴕鳥,不過對於這無差別攻擊還是有小小的防禦效果。😆
當然,如果你被針對,改 port 這招還是沒效,畢竟用工具也是可以很快掃出這個 IP 有開放哪些 port 。
# pg_hba.conf
pg_hba.conf 是 PostgreSQL Client Authentication Configuration File 可以設定 PostgreSQL 資料庫內帳號與資料庫存取的規則
設定檔大概長這樣
# DO NOT DISABLE!
# If you change this first entry you will need to make sure that the
# database superuser can access the database using some other method.
# Noninteractive access to all databases is required during automatic
# maintenance (custom daily cronjobs, replication, and similar tasks).
#
# Database administrative login by Unix domain socket
local all postgres peer
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 md5
host web_app web_app 127.0.0.1/32 md5
host all admin_account 0.0.0.0/0 md5
# IPv6 local connections:
host all all ::1/128 md5
host all admin_account ::0/0 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all peer
host replication all 127.0.0.1/32 md5
host replication all ::1/128 md5
# 限制帳號只能連線某個資料庫
建議每個 web_app 最好都有帳號,不要共用,這樣就可以限制 web_app1 只能連線 web_app1 的資料庫,像下面的設定一樣。
host web_app1 web_app1 127.0.0.1/32 md5
# 開放帳號可以透過網際網路連線資料庫
如果要開放某個帳號(例:admin_account)可以從網際網路連線資料庫可以這樣設定。
host all admin_account 0.0.0.0/0 md5
host all admin_account ::0/0 md5
這樣(admin_account)就可以從網際網路來連線到所有的資料庫,或是把 all
改為某個資料庫,這樣就只能連線那個資料庫。
不過這邊也是建議不要開放帳號可以透過網際網路的方式來連線資料庫,如果要的話可以用 over SSH 的方式,後面的段落會介紹 over SSH 的方式
# 不要使用 postgres 這個帳號
postgres
這個帳號是 PostgreSQL 預設的 superuser 帳號,基本上就很容易被針對,可以看到文章開始的 log 都是針對 postgres 帳號來進行嘗試登入,所以除了 shell 管理之外,都不要使用 postgres 這個帳號,application 及管理用途再額外開帳號就好。
# iptables
再來是透過防火牆的方式來限制連線,如果你的 Web Application 跟 DB 不在同一個區網內,但是有固定的 IP 那就可以用防火牆的方式來限制連線,Linux 系統可以用 iptables 來設定。
# iptables -A INPUT -i lo -p tcp --dport 5432 -j ACCEPT
# iptables -A INPUT -s your_ip -p tcp --dport 5432 -j ACCEPT
# iptables -A INPUT -p tcp --dport 5432 -j DROP
# ip6tables -A INPUT -i lo -p tcp --dport 5432 -j ACCEPT
# ip6tables -A INPUT -s your_ip -p tcp --dport 5432 -j ACCEPT
# ip6tables -A INPUT -p tcp --dport 5432 -j DROP
像是這樣就可以限制只有 localhost
跟 your_ip
可以連線
# DB connection over SSH
前面提了很多方式來保護資料庫的連線安全,那管理人員要從網際網路登入管理就會受到很大的限制,那這邊有一個方式是官方也推薦的方式就是使用 SSH Tunnel 的方式來連線到要管理的資料庫。
首先先建立 SSH Tunnel,利用 SSH 將 your_db_host 的 port 5432 轉到 localhost 的 port 54320 上。
# ssh -L 54320:your_db_host:5432 your_account@your_db_host
這時需要輸入主機上的帳號密碼,輸入後就會登入主機,接著保持這條連線不要關閉。
接著再用 psql 連到 localhost 的 port 5432 上面。
# psql -h localhost -p 54320 postgres
這樣就可以透過 SSH Tunnel 的方式來連線到 PostgreSQL 資料庫。
# GUI 工具
一般來說也會使用 GUI 工具來管理 PostgreSQL,院長是使用 Valentina Studio (opens new window) 跟 Postico (opens new window) 這兩套來管理資料庫。
這兩套 GUI 工具都有支援以 SSH Tunnel 的方式連線到 PostgreSQL 資料庫。
Valentina Studio
Postico
這樣一來就可以不用指令建 SSH Tunnel 直接透過 GUI 工具內的機制達成,可說是方便不少。
# 結語
資安的領域博大精深,除了本文介紹的連線安全之外,還有很多機制可以保護資料庫,那這部分就之後有機會再跟大家分享囉。
# 參考資料
- 渡鴉之丘: postgresql.conf 的 listen_addresses 到底在幹麻的? (opens new window)
- How to list all iptables rules with line numbers on Linux - nixCraft (opens new window)
- How To List and Delete Iptables Firewall Rules | DigitalOcean (opens new window)
- Iptables Essentials: Common Firewall Rules and Commands | DigitalOcean (opens new window)
- IPTables only allow localhost access - Server Fault (opens new window)
- Ubuntu Server 如何永久儲存iptables的設定? | MagicLen (opens new window)
- PostgreSQL: Documentation: 12: 18.11. Secure TCP/IP Connections with SSH Tunnels (opens new window)