Set IP ditinjau kembali
Sudah ada jawaban yang menyebutkan set IP. Namun, ini agak satu dimensi karena berfokus pada perolehan kinerja dibandingkan aturan klasik dan fakta bahwa set IP mengurangi masalah yang dimiliki seseorang dengan banyak alamat IP individual yang tidak dapat dengan mudah dinyatakan sebagai subnet dalam notasi CIDR.
Notasi digunakan di bawah ini
Karena ipset
saya akan menggunakan notasi yang dibaca ipset restore
dan ditulis oleh ipset save
.
Sejalan dengan iptables
(dan ip6tables
) aturan, saya akan menggunakan notasi yang dibaca iptables-restore
dan ditulis oleh iptables-save
. Ini menghasilkan notasi yang lebih pendek dan memungkinkan saya untuk menyoroti aturan IPv4-only (prefixed -4
) atau only-IPv6 (prefixed -6
).
Dalam beberapa contoh kita akan mengalihkan aliran paket ke rantai lain. Rantai diasumsikan ada pada saat itu, sehingga garis-garis untuk membuat rantai tidak diproduksi (juga tidak ada nama tabel yang disebutkan atau perintah-perintah COMMIT
di akhir).
Set IP tingkat lanjut
Set IP dapat melakukan lebih banyak daripada yang disebutkan dalam jawaban lain dan Anda harus membaca dokumentasi set IP ( ipset(8)
) bersama dengan iptables-extensions(8)
tambahan entri singkat ini di sini.
Sebagai contoh saya akan terutama berfokus pada tiga jenis set: hash:ip
, hash:net
dan list:set
, tetapi ada lebih dari mereka dan mereka semua memiliki kasus penggunaan valid.
Misalnya, Anda juga dapat mencocokkan nomor port, bukan hanya alamat IP .
Menyimpan dan memulihkan set IP seperti dengan iptables-save
daniptables-restore
Anda dapat membuat deklarasi set IP secara massal dan mengimpornya dengan memasukkannya ke dalam pip ipset restore
. Jika Anda ingin membuat perintah Anda lebih tangguh terhadap entri yang sudah ada, gunakan ipset -exist restore
.
Jika aturan Anda ada dalam file yang disebut default.set
Anda akan menggunakan:
ipset -exist restore < default.set
File seperti itu dapat berisi entri untuk create
ditetapkan dan add
entri ke dalamnya. Tetapi umumnya sebagian besar perintah dari baris perintah tampaknya memiliki versi yang sesuai dalam file. Contoh (membuat satu set server DNS):
create dns4 hash:ip family inet
create dns6 hash:ip family inet6
# Google DNS servers
add dns4 8.8.8.8
add dns4 8.8.4.4
add dns6 2001:4860:4860::8888
add dns6 2001:4860:4860::8844
Di sini satu set dibuat untuk IPv4 ( dns4
) dan satu set untuk IPv6 ( dns6
).
Timeout pada set IP
Timeout dalam set IP dapat ditetapkan sebagai default per set dan juga per entri. Ini sangat berguna untuk skenario di mana Anda ingin memblokir seseorang untuk sementara waktu (mis. Untuk pemindaian port atau berusaha memaksa server SSH Anda dengan kasar).
Cara kerjanya adalah sebagai berikut (default selama pembuatan set IP):
create ssh_loggedon4 hash:ip family inet timeout 5400
create ssh_loggedon6 hash:ip family inet6 timeout 5400
create ssh_dynblock4 hash:ip family inet timeout 1800
create ssh_dynblock6 hash:ip family inet6 timeout 1800
Kami akan kembali ke set khusus di bawah ini dan alasan mengapa mereka mengaturnya.
Jika Anda ingin mengatur batas waktu Anda untuk alamat IP tertentu, Anda bisa mengatakan:
add ssh_dynblock4 1.2.3.4 timeout 7200
Untuk memblokir IP 1.2.3.4 selama dua jam, alih-alih setengah (standar) default.
Jika Anda melihatnya ipset save ssh_dynblock4
setelah beberapa saat, Anda akan melihat sesuatu seperti:
create ssh_dynblock4 hash:ip family inet hashsize 1024 maxelem 65536 timeout 1800
add ssh_dynblock4 1.2.3.4 timeout 6954
Peringatan batas waktu
- batas waktu adalah fitur pada set yang diberikan. Jika set tidak dibuat dengan dukungan batas waktu Anda akan menerima kesalahan (misalnya
Kernel error received: Unknown error -1
).
- batas waktu diberikan dalam detik. Gunakan ekspresi aritmatika Bash untuk mendapatkan dari menit ke detik, misalnya. Misalnya:
sudo ipset add ssh_dynblock4 1.2.3.4 timeout $((120*60))
Memeriksa apakah ada entri dalam set IP yang diberikan
Di dalam skrip Anda dapat bermanfaat untuk melihat apakah entri sudah ada. Ini dapat dicapai dengan ipset test
yang mengembalikan nol jika entri ada dan bukan nol sebaliknya. Jadi cek biasa dapat diterapkan dalam skrip:
if ipset test dns4 8.8.8.8; then
echo "Google DNS is in the set"
fi
Namun, dalam banyak kasus Anda lebih suka menggunakan -exist
sakelar ipset
untuk mengarahkannya agar tidak mengeluh tentang entri yang ada.
Mengisi set IP dari iptables
aturan
Ini, menurut saya, adalah salah satu fitur pembunuh set IP. Anda tidak hanya dapat mencocokkan dengan entri set IP, Anda juga dapat menambahkan entri baru ke set IP yang ada.
Misalnya dalam jawaban untuk pertanyaan ini, Anda memiliki:
-A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --update --seconds 15 -j DROP
-A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --set -j ACCEPT
... dengan tujuan untuk menilai batas upaya koneksi ke SSH (TCP port 22). Modul yang digunakan recent
melacak upaya koneksi terbaru. Alih-alih state
modul, saya lebih suka conntrack
modul.
# Say on your input chain of the filter table you have
-A INPUT -i eth+ -p tcp --dport ssh -j SSH
# Then inside the SSH chain you can
# 1. create an entry in the recent list on new connections
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
# 2. check whether 3 connection attempts were made within 2 minutes
# and if so add or update an entry in the ssh_dynblock4 IP set
-4 -A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock4 src --exist
-6 -A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock6 src --exist
# 3. last but not least reject the packets if the source IP is in our
# IP set
-4 -A SSH -m set --match-set ssh_dynblock4 src -j REJECT
-6 -A SSH -m set --match-set ssh_dynblock6 src -j REJECT
Dalam hal ini saya mengarahkan aliran ke SSH
rantai sedemikian rupa sehingga saya tidak perlu mengulangi sendiri -p tcp --dport ssh
untuk setiap aturan tunggal.
Untuk mengulangi:
-m set
membuat iptables
sadar bahwa kita sedang menggunakan switch dari set
modul (yang menangani IP set)
--match-set ssh_dynblock4 src
memberitahu iptables
agar mencocokkan sumber ( src
) alamat dengan set bernama ( ssh_dynblock4
)
- ini sesuai dengan
sudo ipset test ssh_dynblock4 $IP
(di mana $IP
berisi alamat IP sumber untuk paket)
-j SET --add-set ssh_dynblock4 src --exist
menambah atau memperbarui alamat sumber ( src
) dari paket ke dalam set IP ssh_dynblock4
. Jika ada entri ( --exist
) itu hanya akan diperbarui.
- ini sesuai dengan
sudo ipset -exist add ssh_dynblock4 $IP
(di mana $IP
berisi alamat IP sumber untuk paket)
Jika Anda ingin mencocokkan alamat target / tujuan, Anda akan menggunakannya dst
sebagai gantinya src
. Konsultasikan manual untuk opsi lebih lanjut.
Set set
Set IP dapat berisi set lainnya. Sekarang jika Anda mengikuti artikel sampai di sini Anda akan bertanya-tanya apakah mungkin untuk menggabungkan set. Dan tentu saja. Untuk set IP dari atas kita dapat membuat dua set gabungan ssh_dynblock
dan ssh_loggedon
masing - masing berisi set IPv4-only dan IPv6-only:
create ssh_loggedon4 hash:ip family inet timeout 5400
create ssh_loggedon6 hash:ip family inet6 timeout 5400
create ssh_dynblock4 hash:ip family inet timeout 1800
create ssh_dynblock6 hash:ip family inet6 timeout 1800
# Sets of sets
create ssh_loggedon list:set
create ssh_dynblock list:set
# Populate the sets of sets
add ssh_loggedon ssh_loggedon4
add ssh_loggedon ssh_loggedon6
add ssh_dynblock ssh_dynblock4
add ssh_dynblock ssh_dynblock6
Dan pertanyaan berikutnya yang harus muncul dalam pikiran Anda adalah apakah ini memungkinkan kami untuk mencocokkan dan dan memanipulasi set IP dalam mode IP versi-agnostik.
Dan jawabannya adalah: Ya! (Sayangnya, ini tidak didokumentasikan secara eksplisit terakhir kali saya periksa)
Akibatnya aturan dari bagian sebelumnya dapat ditulis ulang untuk dibaca:
-A INPUT -i eth+ -p tcp --dport ssh -j SSH
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
-A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock src --exist
-A SSH -m set --match-set ssh_dynblock src -j REJECT
yang jauh lebih ringkas. Dan ya, ini dicoba dan diuji dan bekerja seperti pesona.
Menyatukan semuanya: SSH brute-force defense
Di server saya, saya memiliki skrip yang dijalankan sebagai cron
pekerjaan yang mengambil banyak nama host dan menyelesaikannya ke alamat IP, kemudian memasukkannya ke dalam set IP untuk "host tepercaya". Idenya adalah bahwa host tepercaya mendapatkan lebih banyak upaya untuk masuk ke server dan tidak harus diblokir selama orang lain.
Sebaliknya, saya memiliki seluruh negara yang diblokir dari menghubungkan ke server SSH saya, dengan pengecualian (potensial) dari host tepercaya (yaitu urutan aturan masalah).
Namun, itu dibiarkan sebagai latihan untuk pembaca. Di sini saya ingin menambahkan solusi yang rapi yang akan menggunakan set yang terkandung dalam ssh_loggedon
set untuk memungkinkan upaya koneksi berikutnya untuk diberikan dan tidak menjadi subyek pengawasan yang sama dengan paket lainnya.
Penting untuk mengingat batas waktu default 90 menit ssh_loggedon
dan 30 menit ssh_dynblock
ketika melihat iptables
aturan berikut :
-A INPUT -i eth+ -p tcp --dport ssh -j SSH
-A SSH -m set --match-set ssh_loggedon src -j ACCEPT
-A SSH -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
-A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock src --exist
-A SSH -m set --match-set ssh_dynblock src -j REJECT
Sekarang Anda harus bertanya pada diri sendiri bagaimana alamat IP yang menghubungkan berakhir di ssh_loggedon
sub-set. Jadi baca terus ...
Bonus: menambahkan IP yang Anda masuk dengan selama SSH masuk
Jika Anda telah bereksperimen dengan sshrc
dan berteman, Anda akan mengetahui kekurangannya. Tapi PAM datang untuk menyelamatkan. Modul bernama pam_exec.so
memungkinkan kita untuk memanggil skrip selama masuk SSH pada titik di mana kita tahu bahwa pengguna diterima.
Di /etc/pam.d/sshd
bawah pam_env
dan pam_selinux
entri menambahkan baris berikut:
session optional pam_exec.so stdout /path/to/your/script
dan pastikan versi skrip Anda (di /path/to/your/script
atas) ada dan dapat dieksekusi.
PAM menggunakan variabel lingkungan untuk mengomunikasikan apa yang terjadi, sehingga Anda dapat menggunakan skrip sederhana seperti ini:
#!/bin/bash
# When called via pam_exec.so ...
SETNAME=ssh_loggedon
if [[ "$PAM_TYPE" == "open_session" ]] && [[ -n "$PAM_RHOST" ]]; then
[[ "x$PAM_RHOST" != "x${PAM_RHOST//:/}" ]] && SETNAME="${SETNAME}6" || SETNAME="${SETNAME}4"
ipset -exist add $SETNAME "$PAM_RHOST"
fi
Sayangnya ipset
utilitas tersebut tampaknya tidak memiliki kecerdasan netfilter bawaan. Jadi kita perlu membedakan antara set IP IPv4 dan IPv6 saat menambahkan entri kita. Kalau tidak ipset
akan menganggap kita ingin menambahkan set lain ke set set, bukan IP. Dan tentu saja itu tidak mungkin bahwa akan ada satu set bernama setelah IP :)
Jadi kami memeriksa :
alamat IP dan menambahkan 6
nama yang ditetapkan dalam kasus tersebut dan 4
sebaliknya.
Tamat.