Fondasi · Fase 1
Membuat Tools Keamanan Sendiri dengan Python: Port Scanner, Log Parser, dan File Encryptor
Penutup modul scripting: membuat tiga alat keamanan sendiri dengan Python. Port scanner TCP dengan socket dan kerja paralel, log parser yang menghasilkan laporan CSV, dan file encryptor berbasis PBKDF2 dan Fernet, lengkap dengan aturan main dan alasan di balik setiap keputusan desain.

Ini materi penutup modul Python dan Bash. Sebelumnya kamu sudah belajar dasar Python, regex, requests, dan Bash. Sekarang semua itu dipakai untuk membuat tiga alat keamanan sungguhan:
- Port scanner, untuk mengetahui layanan apa saja yang terbuka di sebuah perangkat.
- Log parser, untuk meringkas ribuan baris log menjadi laporan yang bisa dibuka di spreadsheet.
- File encryptor, untuk melindungi file rahasia dengan password.
Alat profesional seperti nmap atau GPG tentu jauh lebih lengkap. Tujuan membuatnya sendiri bukan untuk menggantikan alat-alat itu, melainkan supaya kamu paham cara kerjanya dari dalam. Orang yang pernah membuat port scanner sendiri akan jauh lebih mudah memahami hasil nmap, dan orang yang pernah membuat alat enkripsi sendiri akan tahu kenapa password lemah tetap berbahaya walaupun filenya dienkripsi.
Persiapan
mkdir tools-keamanan && cd tools-keamanan
python3 -m venv venv
source venv/bin/activate
pip install cryptography # hanya dibutuhkan oleh file encryptor
Ketiga alat ini memakai modul argparse, modul bawaan Python untuk membaca pilihan dari terminal, seperti -p 22,80 atau --output. Dengan argparse, skripmu otomatis punya petunjuk pemakaian lewat --help, persis seperti perintah Linux pada umumnya.
Alat 1: port scanner
Di artikel TCP, UDP, dan ICMP, kamu sudah belajar three-way handshake. Port scanner paling sederhana bekerja dengan memanfaatkannya: mencoba membuka koneksi TCP ke setiap port, lalu melihat jawabannya.

# port_scanner.py - pemindai port TCP sederhana, hanya untuk perangkat milikmu sendiri
import argparse
import socket
from concurrent.futures import ThreadPoolExecutor
PORT_UMUM = {21: "FTP", 22: "SSH", 25: "SMTP", 53: "DNS", 80: "HTTP",
443: "HTTPS", 3306: "MySQL", 3389: "RDP", 8080: "HTTP-alt"}
def cek_port(host, port, timeout):
"""Mengembalikan port kalau terbuka, atau None kalau tertutup."""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(timeout)
if s.connect_ex((host, port)) == 0: # 0 berarti koneksi TCP berhasil
return port
return None
def urai_port(teks):
"""Mengubah '22,80,8000-8010' menjadi daftar angka port."""
hasil = []
for bagian in teks.split(","):
if "-" in bagian:
awal, akhir = bagian.split("-")
hasil.extend(range(int(awal), int(akhir) + 1))
else:
hasil.append(int(bagian))
return hasil
def main():
p = argparse.ArgumentParser(description="Pemindai port TCP sederhana")
p.add_argument("host", nargs="?", default="127.0.0.1", help="alamat target (bawaan: 127.0.0.1)")
p.add_argument("-p", "--ports", default="1-1024", help="contoh: 22,80,443 atau 1-1024")
p.add_argument("-t", "--timeout", type=float, default=0.5, help="detik per port")
args = p.parse_args()
ip = socket.gethostbyname(args.host)
ports = urai_port(args.ports)
print(f"Memindai {len(ports)} port di {args.host} ({ip}) ...")
with ThreadPoolExecutor(max_workers=100) as kerja:
hasil = kerja.map(lambda port: cek_port(ip, port, args.timeout), ports)
terbuka = sorted(port for port in hasil if port)
for port in terbuka:
print(f" {port:>5}/tcp terbuka {PORT_UMUM.get(port, '')}")
print(f"Selesai: {len(terbuka)} port terbuka.")
if __name__ == "__main__":
main()
Cara kerjanya:
- Modul
socketmembuat sambungan jaringan. Fungsiconnect_ex()mencoba terhubung dan mengembalikan0kalau berhasil, artinya port terbuka. settimeout()membatasi waktu tunggu. Tanpa ini, port yang difilter firewall akan membuat pemindai menunggu sangat lama.ThreadPoolExecutormemeriksa banyak port sekaligus, bukan satu per satu. Memindai 1.024 port satu per satu dengan timeout 0,5 detik bisa memakan waktu lebih dari 8 menit. Dengan 100 pekerja paralel, cukup beberapa detik.
Teknik ini disebut TCP connect scan, sama dengan nmap -sT. Karena handshake-nya diselesaikan sampai tuntas, setiap percobaan biasanya tercatat di log target. Itulah sebabnya pemindaian seperti ini mudah terdeteksi oleh tim keamanan.
Alat 2: log parser dengan laporan CSV
Di artikel String dan Regex untuk Parsing Log, kita membuat pengurai log SSH yang menampilkan hasilnya di layar. Sekarang kita tingkatkan menjadi alat yang lebih berguna untuk pekerjaan nyata: hasilnya disimpan sebagai file CSV yang bisa dibuka di Excel atau Google Sheets, lengkap dengan waktu pertama dan terakhir setiap IP mencoba masuk.

# log_parser.py - mengurai log SSH dan menyimpan ringkasan ke file CSV
import argparse
import csv
import re
from collections import defaultdict
POLA = re.compile(
r"^(?P<waktu>\w{3}\s+\d+ [\d:]{8}) \S+ sshd\[\d+\]: "
r"(?P<status>Failed|Accepted) password for (?:invalid user )?(?P<user>\S+) "
r"from (?P<ip>\d{1,3}(?:\.\d{1,3}){3}) port \d+"
)
def urai(nama_file):
data = defaultdict(lambda: {"gagal": 0, "berhasil": 0, "akun": set(), "pertama": None, "terakhir": None})
with open(nama_file, encoding="utf-8", errors="replace") as f:
for baris in f:
m = POLA.search(baris)
if not m:
continue
d = data[m["ip"]]
d["gagal" if m["status"] == "Failed" else "berhasil"] += 1
d["akun"].add(m["user"])
d["pertama"] = d["pertama"] or m["waktu"]
d["terakhir"] = m["waktu"]
return data
def main():
p = argparse.ArgumentParser(description="Ringkasan login SSH per alamat IP")
p.add_argument("log", help="file log, misalnya /var/log/auth.log")
p.add_argument("-o", "--output", default="ringkasan.csv", help="file CSV hasil")
p.add_argument("-b", "--batas", type=int, default=5, help="batas login gagal untuk ditandai")
args = p.parse_args()
data = urai(args.log)
with open(args.output, "w", newline="", encoding="utf-8") as f:
tulis = csv.writer(f)
tulis.writerow(["ip", "gagal", "berhasil", "jumlah_akun", "pertama", "terakhir", "status"])
for ip, d in sorted(data.items(), key=lambda x: -x[1]["gagal"]):
if d["gagal"] >= args.batas:
status = "CURIGA"
elif d["gagal"] and d["berhasil"]:
status = "PERIKSA"
else:
status = "-"
tulis.writerow([ip, d["gagal"], d["berhasil"], len(d["akun"]), d["pertama"], d["terakhir"], status])
print(f"{ip:<15} gagal={d['gagal']:<3} berhasil={d['berhasil']} akun={len(d['akun'])} {status}")
print(f"Ringkasan disimpan di {args.output}")
if __name__ == "__main__":
main()
Hal baru di skrip ini:
defaultdictotomatis membuat data kosong untuk alamat IP yang baru pertama kali muncul, sehingga kita tidak perlu memeriksanya dulu.set()menyimpan nama akun tanpa duplikat. Jumlah akun yang berbeda adalah petunjuk penting: satu IP yang mencoba banyak nama akun hampir pasti sedang menebak-nebak.- Modul
csvmenulis tabel dengan format yang benar, termasuk menangani tanda koma di dalam data. - Status
PERIKSAmenandai IP yang pernah gagal lalu berhasil masuk, pola yang kita temukan di artikel sebelumnya.
Alat 3: file encryptor
Enkripsi menjaga kerahasiaan (confidentiality), huruf C pada CIA Triad. Alat ini mengenkripsi satu file dengan password, sehingga isinya hanya bisa dibaca oleh orang yang tahu password tersebut.
Ada satu aturan emas dalam kriptografi: jangan pernah membuat algoritma enkripsi sendiri. Algoritma buatan sendiri hampir pasti punya celah. Karena itu kita memakai pustaka cryptography yang sudah diuji banyak ahli, dan bagian kita hanya merangkainya dengan benar.

# file_encryptor.py - mengenkripsi dan mendekripsi satu file dengan password
import argparse
import base64
import getpass
import os
import sys
from cryptography.fernet import Fernet, InvalidToken
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
PUTARAN = 600_000 # jumlah pengulangan agar password sulit ditebak massal
def buat_kunci(password, salt):
"""Mengubah password menjadi kunci enkripsi yang kuat."""
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=PUTARAN)
return base64.urlsafe_b64encode(kdf.derive(password.encode()))
def enkripsi(path, password):
salt = os.urandom(16) # acak, berbeda setiap kali
with open(path, "rb") as f:
data = f.read()
token = Fernet(buat_kunci(password, salt)).encrypt(data)
with open(path + ".enc", "wb") as f:
f.write(salt + token) # salt disimpan di depan, tidak rahasia
print(f"Terenkripsi: {path}.enc (file asli tidak diubah)")
def dekripsi(path, password):
with open(path, "rb") as f:
isi = f.read()
salt, token = isi[:16], isi[16:]
try:
data = Fernet(buat_kunci(password, salt)).decrypt(token)
except InvalidToken:
sys.exit("Gagal: password salah atau file sudah diubah.")
keluaran = path.removesuffix(".enc") + ".dec"
with open(keluaran, "wb") as f:
f.write(data)
print(f"Terdekripsi: {keluaran}")
def main():
p = argparse.ArgumentParser(description="Enkripsi dan dekripsi satu file dengan password")
p.add_argument("aksi", choices=["enkripsi", "dekripsi"])
p.add_argument("file")
args = p.parse_args()
password = getpass.getpass("Password: ") # tidak tampil di layar
if args.aksi == "enkripsi":
if password != getpass.getpass("Ulangi password: "):
sys.exit("Password tidak sama.")
enkripsi(args.file, password)
else:
dekripsi(args.file, password)
if __name__ == "__main__":
main()
| Komponen | Fungsinya | Kenapa penting |
|---|---|---|
| PBKDF2 | Mengubah password menjadi kunci 32 byte | Diulang 600.000 kali sehingga setiap tebakan password jadi lambat dan mahal bagi penyerang |
| Salt | 16 byte acak yang dicampur ke password | Password yang sama menghasilkan kunci berbeda di setiap file, sehingga penyerang tidak bisa memakai tabel tebakan siap pakai |
| Fernet | Mengenkripsi data dengan AES dan melindunginya dengan HMAC | Menjaga kerahasiaan sekaligus keutuhan: file yang diubah satu byte saja akan ditolak saat didekripsi |
| getpass | Meminta password tanpa menampilkannya di layar | Password tidak terlihat orang di sebelahmu dan tidak tersimpan di riwayat terminal |
Perhatikan dua keputusan desain yang disengaja. Pertama, alat ini tidak menghapus file asli, supaya kamu tidak kehilangan data kalau lupa password atau terjadi kesalahan. Kedua, alat ini hanya mengenkripsi satu file yang kamu pilih sendiri. Alat yang otomatis mengenkripsi banyak file lalu menghapus aslinya adalah ciri khas ransomware, dan bukan sesuatu yang kita buat di sini.
Ringkasan ketiga alat
| Alat | Modul utama | Konsep yang dipakai | Alat profesional |
|---|---|---|---|
| Port scanner | socket, concurrent.futures | TCP handshake, timeout, kerja paralel | nmap, masscan |
| Log parser | re, csv, collections | Regex, grup bernama, agregasi data | SIEM seperti Wazuh, Splunk, atau Elastic |
| File encryptor | cryptography, getpass | Penurunan kunci, salt, enkripsi terautentikasi | GPG, VeraCrypt, 7-Zip dengan AES |
Kenapa ini penting untuk keamanan siber
Membuat alat sendiri melatih kemampuan yang dibutuhkan di semua bidang keamanan: memahami protokol sampai level paket, mengolah data dalam jumlah besar, dan memakai kriptografi dengan benar. Di dunia kerja, kamu akan sering menemui situasi saat alat yang ada tidak pas dengan kebutuhan, misalnya format log khusus milik aplikasi kantor, atau pemeriksaan rutin yang ingin diotomatiskan. Di saat seperti itu, kemampuan menulis alat kecil sendiri menjadi pembeda.
Ringkasan
- Port scanner memakai
socket.connect_ex()untuk mencoba koneksi TCP, dengan timeout dan kerja paralel agar cepat. - Log parser memakai regex untuk mengurai log, lalu merangkumnya per IP dan menyimpannya sebagai CSV.
- File encryptor memakai PBKDF2 dengan salt untuk membuat kunci dari password, lalu Fernet untuk mengenkripsi dan melindungi keutuhan file.
argparsemembuat skrip bisa dipakai seperti perintah Linux, lengkap dengan--help.- Pindai hanya perangkat milikmu sendiri, jangan membuat algoritma enkripsi sendiri, dan pakai password yang kuat.
Tonton dan baca juga
- Video: Bikin port scanner
- Video: Bikin log parser
- Video: Bikin file encryptor
- Dokumentasi Fernet di pustaka cryptography (bahasa Inggris)
Dengan materi ini, kamu menyelesaikan modul Python dan Bash Scripting. Modul berikutnya kembali ke konsep inti keamanan, dimulai dengan CIA Triad yang dibahas lebih dalam lewat kasus-kasus nyata di Indonesia. Buka di roadmap untuk melanjutkan.