
แนวคิด: เปรียบเทียบโปรโตคอลที่ไม่ปลอดภัย vs. ปลอดภัย ใช้งานจริงได้ทันที — บทนี้พาสำรวจโปรโตคอลการถ่ายโอนไฟล์ตั้งแต่ FTP ดั้งเดิมที่ส่งข้อมูลแบบ Plaintext ไปจนถึง SFTP, FTPS, SCP และ SSH ที่มีการเข้ารหัส พร้อมตัวอย่างการใช้งานจริงบน Linux
FTP (File Transfer Protocol) เป็นโปรโตคอลสำหรับการถ่ายโอนไฟล์ผ่านเครือข่าย TCP/IP ที่เก่าแก่ที่สุดโปรโตคอลหนึ่ง ถูกออกแบบในยุคที่ความปลอดภัยยังไม่ใช่ความกังวลหลัก ทำให้มีช่องโหว่ด้าน Security มากมาย
flowchart LR
subgraph era1["ยุคเริ่มต้น Early Era (1971–1985)"]
A["1971\nRFC 114\nFTP ต้นแบบ Original FTP"]
B["1980\nRFC 765\nปรับปรุงครั้งแรก First Update"]
C["1985\nRFC 959\nมาตรฐานปัจจุบัน Current Standard"]
A --> B --> C
end
subgraph era2["ยุคอินเทอร์เน็ต Internet Era (1990–2000)"]
D["1994\nFTP Passive Mode\nแก้ปัญหา Firewall/NAT"]
E["1997\nRFC 2228\nFTP Security Extensions"]
F["1999\nRFC 2640\nรองรับ Unicode Support"]
D --> E --> F
end
subgraph era3["ยุคปลอดภัย Secure Era (1999–ปัจจุบัน)"]
G["1999\nSSH-2 + SFTP\nทางเลือกปลอดภัย Secure Alternative"]
H["2005\nFTPS RFC 4217\nFTP over TLS"]
I["2014\nRFC 7151\nFTP HOST Command"]
J["ปัจจุบัน Present\nFTP ถูกแทนที่\nด้วย SFTP/FTPS/SCP"]
G --> H --> I --> J
end
era1 --> era2 --> era3
FTP ใช้โมเดล Client-Server โดยมีคุณสมบัติเฉพาะตัวที่แตกต่างจากโปรโตคอลอื่น คือการใช้ การเชื่อมต่อ 2 ช่องทาง (Dual-Channel Architecture):
sequenceDiagram participant C as FTP Client (ผู้ใช้งาน) participant S as FTP Server (เซิร์ฟเวอร์) Note over C,S: Control Connection (TCP Port 21) — ช่องทางควบคุม C->>S: TCP SYN (เชื่อมต่อ Port 21) S-->>C: 220 Service Ready (พร้อมให้บริการ) C->>S: USER student01 S-->>C: 331 Password Required (ต้องการรหัสผ่าน) C->>S: PASS P@ssw0rd2024 S-->>C: 230 Login Successful (เข้าสู่ระบบสำเร็จ) C->>S: PWD (ขอดู Directory ปัจจุบัน) S-->>C: 257 "/home/student01" C->>S: LIST (แสดงรายการไฟล์) Note over C,S: Data Connection (TCP Port 20) — ช่องทางข้อมูล S->>C: เปิด Data Connection Port 20 S-->>C: 150 Opening Data Connection S-->>C: ส่งข้อมูล Directory Listing S-->>C: 226 Transfer Complete (ถ่ายโอนสำเร็จ) C->>S: QUIT (ออกจากระบบ) S-->>C: 221 Goodbye
ใน Active Mode เซิร์ฟเวอร์เป็นฝ่ายเริ่มต้น Data Connection กลับมาหา Client:
PORT พร้อมระบุ IP และ Port ที่ตัวเองรับฟังปัญหาหลัก: Firewall ที่ Client มักบล็อก Incoming Connection จาก Server Port 20
sequenceDiagram participant C as Client (IP: 192.168.1.100) participant F as Client Firewall (ไฟร์วอลล์ผู้ใช้) participant S as FTP Server (IP: 203.0.113.10) C->>S: Control: PORT 192,168,1,100,200,50 (แจ้ง Port 51250 สำหรับรับข้อมูล) S-->>C: 200 PORT Command OK S->>F: Data: SYN จาก Port 20 → Port 51250 F-->>S: BLOCKED! Firewall ปฏิเสธการเชื่อมต่อขาเข้า Note over C,S: Active Mode ล้มเหลวเมื่อมี Firewall/NAT
ใน Passive Mode Client เป็นฝ่ายเริ่มต้น Data Connection แก้ปัญหา Firewall/NAT ได้:
PASV เพื่อขอให้ Server เปิด Port รอรับsequenceDiagram participant C as Client (IP: 192.168.1.100) participant S as FTP Server (IP: 203.0.113.10) C->>S: Control: PASV (ขอโหมด Passive) S-->>C: 227 Entering Passive Mode (203,0,113,10,195,149) → Port 50069 พร้อมรับ C->>S: Data: SYN จาก Ephemeral Port → Port 50069 S-->>C: Data: SYN-ACK (ตอบรับ) Note over C,S: Passive Mode ทำงานได้แม้มี NAT/Firewall S-->>C: 150 File Status Okay (กำลังส่งไฟล์) S-->>C: File Data (ข้อมูลไฟล์) S-->>C: 226 Transfer Complete
การคำนวณ Port จาก PASV Response:
เมื่อ Server ตอบ 227 Entering Passive Mode (203,0,113,10,195,149) ค่าสองตัวสุดท้ายคือ p₁ และ p₂ ใช้สูตร:
ตัวอย่างการคำนวณ: จาก Response (203,0,113,10,195,149):
# ตรวจสอบด้วย Linux
echo $((195 * 256 + 149))
# ผลลัพธ์: 50069
| คำสั่ง (Command) | ความหมาย | ตัวอย่าง |
|---|---|---|
USER |
ส่งชื่อผู้ใช้ | USER student01 |
PASS |
ส่งรหัสผ่าน (Plaintext!) | PASS P@ssw0rd2024 |
LIST |
แสดงรายการไฟล์ละเอียด | LIST /home |
RETR |
ดาวน์โหลดไฟล์ | RETR report.pdf |
STOR |
อัปโหลดไฟล์ | STOR data.csv |
DELE |
ลบไฟล์ | DELE old_file.txt |
MKD |
สร้าง Directory | MKD /backup |
CWD |
เปลี่ยน Directory | CWD /home/student01 |
PWD |
แสดง Directory ปัจจุบัน | PWD |
QUIT |
ออกจากระบบ | QUIT |
PASV |
เข้าสู่ Passive Mode | PASV |
PORT |
ระบุ Port สำหรับ Active Mode | PORT 192,168,1,100,200,50 |
TYPE |
กำหนดโหมดการส่ง (A=ASCII, I=Binary) | TYPE I |
| FTP Response Code | ความหมาย |
|---|---|
| 220 | Service Ready — พร้อมให้บริการ |
| 230 | User Logged In — เข้าสู่ระบบสำเร็จ |
| 331 | Password Required — ต้องการรหัสผ่าน |
| 530 | Not Logged In — ไม่ได้เข้าสู่ระบบ |
| 150 | File Status Okay — เริ่มถ่ายโอน |
| 226 | Closing Data Connection — ถ่ายโอนเสร็จสิ้น |
| 421 | Service Not Available — ไม่พร้อมให้บริการ |
| 550 | File Unavailable — ไม่พบไฟล์หรือไม่มีสิทธิ์ |
สมมติสภาพแวดล้อมดังนี้:
192.168.1.10, ติดตั้ง vsftpd บน Ubuntu 22.04192.168.1.100student01 / รหัสผ่าน: P@ssw0rd2024network_lab.txt ขนาดประมาณ 1.37 MBขั้นตอนที่ 1: ติดตั้ง FTP Server (vsftpd)
# ติดตั้ง vsftpd บน Ubuntu/Debian
sudo apt update && sudo apt install vsftpd -y
# สร้างผู้ใช้ทดสอบ
sudo useradd -m -s /bin/bash student01
echo "student01:P@ssw0rd2024" | sudo chpasswd
# กำหนดค่าพื้นฐาน (ไม่ปลอดภัย — ใช้เพื่อสาธิตเท่านั้น!)
sudo tee /etc/vsftpd.conf << 'EOF'
listen=YES
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
EOF
sudo systemctl restart vsftpd
sudo systemctl status vsftpd
ขั้นตอนที่ 2: สร้างไฟล์ทดสอบ
# สร้างไฟล์ทดสอบขนาดประมาณ 1 MB
dd if=/dev/urandom bs=1024 count=1024 | base64 > /home/student01/network_lab.txt
ls -lh /home/student01/network_lab.txt
# -rw-r--r-- 1 student01 student01 1.4M Jun 10 10:00 network_lab.txt
ขั้นตอนที่ 3: เชื่อมต่อ FTP และใช้งาน
# ติดตั้ง ftp client
sudo apt install ftp -y
# เชื่อมต่อ FTP Server
ftp 192.168.1.10
# Connected to 192.168.1.10.
# 220 (vsFTPd 3.0.5)
# Name: student01
# 331 Please specify the password.
# Password: [พิมพ์ P@ssw0rd2024]
# 230 Login successful.
# คำสั่งพื้นฐานใน FTP prompt
ftp> pwd # ดู directory ปัจจุบัน
ftp> ls -la # แสดงไฟล์ทั้งหมด
ftp> get network_lab.txt # ดาวน์โหลดไฟล์
# 1433600 bytes received in 0.23 secs (6238.52 kB/s)
ftp> put /tmp/upload.txt # อัปโหลดไฟล์
ftp> bye # ออกจากระบบ
ขั้นตอนที่ 4: ดักจับ Packet ด้วย tcpdump (แสดงช่องโหว่)
# บน Machine ในเครือข่ายเดียวกัน — ดักจับ FTP Traffic
sudo tcpdump -i eth0 -A 'port 21' -w /tmp/ftp_capture.pcap &
# ทำการ Login FTP ใหม่จาก Client
ftp 192.168.1.10 # ใส่ student01 / P@ssw0rd2024
# หยุด tcpdump
sudo kill %1
# ตรวจสอบ — เห็น Credentials แบบ Plaintext!
sudo tcpdump -r /tmp/ftp_capture.pcap -A | grep -E 'USER|PASS'
# ผลลัพธ์ที่น่ากลัว:
# ..USER student01..
# ..PASS P@ssw0rd2024.. ← รหัสผ่านโชว์แจ้งๆ!
⚠️ คำเตือนสำคัญ: รหัสผ่านปรากฏใน Packet แบบ Cleartext นี่คือเหตุผลหลักที่ไม่ควรใช้ FTP บน Production
การคำนวณ Transfer Rate:
จากตัวอย่าง: ไฟล์ขนาด 1,433,600 bytes ถ่ายโอนใน 0.23 วินาที
แปลงเป็น Megabits per second (Mbps):
ตัวแปร: R = Transfer Rate, S = File Size (bytes), T = Transfer Time (วินาที)
# คำนวณ Transfer Rate ด้วย Python3
python3 -c "
size_bytes = 1_433_600
time_sec = 0.23
rate_bps = size_bytes / time_sec
rate_kbps = rate_bps / 1024
rate_mbps = rate_bps * 8 / 1_000_000
print(f'Transfer Rate: {rate_bps:,.0f} B/s')
print(f'Transfer Rate: {rate_kbps:,.2f} KB/s')
print(f'Transfer Rate: {rate_mbps:.2f} Mbps')
"
# Transfer Rate: 6,233,043 B/s
# Transfer Rate: 6,086.96 KB/s
# Transfer Rate: 49.86 Mbps
mindmap
root((FTP จุดอ่อน - Vulnerabilities))
ไม่มีการเข้ารหัส - No Encryption
Credentials เป็น Plaintext
Data เป็น Plaintext
Sniffing ได้ง่ายด้วย tcpdump
การพิสูจน์ตัวตนอ่อนแอ - Weak Authentication
รองรับ Anonymous Login
ไม่มี Brute-force Protection
ไม่รองรับ MFA
ปัญหา Active Mode
NAT Traversal ยาก
Firewall ต้องเปิด Port เพิ่ม
FTP Bounce Attack
MITM Attack
PORT Command IP Spoofing
Man-in-the-Middle ได้ง่าย
ไม่มี Server Authentication
Anonymous FTP
เข้าถึงไฟล์โดยไม่ต้อง Login
เสี่ยงต่อ Data Leakage
เสี่ยงต่อ Malware Distribution
| ช่องโหว่ | ความรุนแรง | คำอธิบาย |
|---|---|---|
| Plaintext Credentials | 🔴 วิกฤต | Username/Password ส่งในรูปแบบที่อ่านได้ทุกคน |
| Plaintext Data | 🔴 วิกฤต | ข้อมูลไฟล์ไม่มีการเข้ารหัสใดๆ |
| FTP Bounce Attack | 🟠 สูง | ใช้ Server เป็น Proxy โจมตีเครื่องอื่น |
| Anonymous Login | 🟠 สูง | เข้าถึงไฟล์โดยไม่ต้อง Authenticate |
| No Integrity Check | 🟡 กลาง | ไม่ตรวจสอบว่าข้อมูลถูกแก้ไขระหว่างทางหรือไม่ |
| PORT Command Spoofing | 🟡 กลาง | แอบอ้าง IP ในคำสั่ง PORT เพื่อ Redirect Data |
SFTP (SSH File Transfer Protocol) ไม่ใช่ FTP ที่เข้ารหัส แต่เป็นโปรโตคอลใหม่ที่ทำงานเป็น Subsystem ของ SSH ทั้งหมดผ่าน Port 22 เพียง Port เดียว
💡 ความต่างสำคัญ: SFTP ≠ FTPS — SFTP ทำงานบน SSH ทั้งหมด ส่วน FTPS คือ FTP ที่ใช้ TLS/SSL เพิ่มเข้าไป
graph TB
subgraph client["SFTP Client (ฝั่งผู้ใช้งาน)"]
App["Application\nไฟล์แมเนเจอร์ / CLI sftp / WinSCP"]
SFTPLib["SFTP Library\nโปรโตคอล SFTP v3–v6"]
SSHClient["SSH Transport Layer\nการเข้ารหัส + Authentication"]
end
subgraph network["Network (เครือข่าย)"]
TCP["TCP Port 22\nช่องเดียว One Channel\n(เข้ารหัสทั้งหมด Fully Encrypted)"]
end
subgraph server["SSH Server (ฝั่งเซิร์ฟเวอร์)"]
SSHDaemon["sshd Daemon\nตรวจสอบ Authentication"]
Subsystem["SFTP Subsystem\n/usr/lib/openssh/sftp-server\nหรือ internal-sftp"]
FS["Filesystem\nระบบไฟล์ (อาจมี Chroot)"]
end
App --> SFTPLib --> SSHClient --> TCP --> SSHDaemon --> Subsystem --> FS
style client fill:#4A2518,color:#FFF5DC
style network fill:#2C1A0E,color:#FFF5DC
style server fill:#3D1F10,color:#FFF5DC
คุณสมบัติที่โดดเด่นของ SFTP:
ข้อมูลสภาพแวดล้อมทดสอบ:
192.168.1.10sftpuser01/srv/sftp/sftpuser01ขั้นตอนที่ 1: ตรวจสอบ SFTP Subsystem
# ตรวจสอบว่า SFTP Subsystem มีอยู่
grep -i sftp /etc/ssh/sshd_config
# Subsystem sftp /usr/lib/openssh/sftp-server
# ตรวจสอบว่าไฟล์มีอยู่จริง
ls -la /usr/lib/openssh/sftp-server
# -rwxr-xr-x 1 root root 121616 ... /usr/lib/openssh/sftp-server
ขั้นตอนที่ 2: สร้างโครงสร้าง Directory สำหรับ SFTP
# สร้าง Directory โครงสร้าง
sudo mkdir -p /srv/sftp/sftpuser01/uploads
sudo mkdir -p /srv/sftp/sftpuser01/downloads
# สร้าง SFTP Group
sudo groupadd sftpusers
# สร้าง SFTP User (ไม่มี Shell Login)
sudo useradd -M -d /srv/sftp/sftpuser01 -G sftpusers -s /sbin/nologin sftpuser01
echo "sftpuser01:SftpP@ss2024!" | sudo chpasswd
# กำหนดความเป็นเจ้าของ — สำคัญมากสำหรับ Chroot!
# Chroot Directory ต้องเป็น owner โดย root เท่านั้น ห้ามให้ user เป็นเจ้าของ
sudo chown root:root /srv/sftp/sftpuser01
sudo chmod 755 /srv/sftp/sftpuser01
# Subdirectory ให้ user เป็นเจ้าของได้
sudo chown sftpuser01:sftpusers /srv/sftp/sftpuser01/uploads
sudo chown sftpuser01:sftpusers /srv/sftp/sftpuser01/downloads
sudo chmod 755 /srv/sftp/sftpuser01/uploads /srv/sftp/sftpuser01/downloads
# ตรวจสอบ
ls -la /srv/sftp/sftpuser01/
# drwxr-xr-x 4 root root 4096 ... .
# drwxr-xr-x 2 sftpuser01 sftpusers 4096 ... downloads
# drwxr-xr-x 2 sftpuser01 sftpusers 4096 ... uploads
ขั้นตอนที่ 3: กำหนดค่า sshd_config สำหรับ SFTP Chroot
# แก้ไข /etc/ssh/sshd_config
sudo nano /etc/ssh/sshd_config
เพิ่มการตั้งค่าต่อไปนี้ (ที่ส่วนท้ายของไฟล์):
# ปิด Subsystem เดิม
# Subsystem sftp /usr/lib/openssh/sftp-server
# ใช้ internal-sftp แทน (รองรับ Chroot ได้ดีกว่า)
Subsystem sftp internal-sftp -l INFO -f AUTH
# กำหนดค่าเฉพาะสำหรับ sftpusers group
Match Group sftpusers
ForceCommand internal-sftp -l INFO
ChrootDirectory /srv/sftp/%u
AllowTcpForwarding no
X11Forwarding no
AllowAgentForwarding no
PermitTunnel no
# ตรวจสอบ Config ก่อน Restart
sudo sshd -t && echo "Config OK"
# Restart SSH Service
sudo systemctl restart sshd
# เชื่อมต่อ SFTP Server
sftp sftpuser01@192.168.1.10
# Connected to 192.168.1.10.
# sftp>
# คำสั่งสำคัญใน SFTP
sftp> pwd # ดู Remote Directory ปัจจุบัน
sftp> lpwd # ดู Local Directory ปัจจุบัน
sftp> ls -la # แสดงไฟล์บน Remote
sftp> lls /tmp # แสดงไฟล์บน Local
sftp> cd uploads # เปลี่ยน Remote Directory
sftp> lcd /tmp # เปลี่ยน Local Directory
# อัปโหลดไฟล์เดียว
sftp> put /tmp/report.pdf uploads/
# Uploading /tmp/report.pdf to /uploads/report.pdf
# report.pdf 100% 256KB 1.2MB/s 00:00
# ดาวน์โหลดไฟล์
sftp> get downloads/data.csv /tmp/
# อัปโหลดหลายไฟล์ด้วย wildcard
sftp> mput /tmp/*.log uploads/
# ดาวน์โหลดทั้ง Directory (Recursive)
sftp> get -r downloads/ /tmp/backup/
ใช้ sftp แบบ Non-interactive สำหรับสคริปต์อัตโนมัติ:
# สร้างไฟล์ batch commands
cat > /tmp/sftp_batch.txt << 'EOF'
cd uploads
put /tmp/report_2024.pdf
put /tmp/data_export.csv
ls -la
bye
EOF
# รันแบบ batch (ไม่ต้องกด Enter)
sftp -b /tmp/sftp_batch.txt sftpuser01@192.168.1.10
# ทดสอบว่า Chroot ทำงาน
sftp sftpuser01@192.168.1.10
sftp> cd /etc
# Permission denied. ← Chroot ป้องกันแล้ว!
sftp> ls /
# downloads uploads ← เห็นแค่ directory ที่กำหนด
# ทดสอบว่าเข้า Shell ไม่ได้
ssh sftpuser01@192.168.1.10
# This service allows sftp connections only.
# Connection to 192.168.1.10 closed. ← ForceCommand ทำงาน!
# ตรวจสอบ Log การเข้าถึง
sudo tail -f /var/log/auth.log | grep sftp
# Jun 10 10:15 server sshd[1234]: Accepted password for sftpuser01 from 192.168.1.100
# Jun 10 10:15 server sshd[1234]: subsystem request for sftp by user sftpuser01
FTPS (FTP Secure) คือ FTP ที่เพิ่มชั้นการเข้ารหัส TLS/SSL ต่างจาก SFTP ตรงที่ยังใช้โครงสร้าง Dual-Channel และ FTP Command Set เดิม มี 2 แบบ:
| คุณสมบัติ | Implicit FTPS | Explicit FTPS (FTPES) |
|---|---|---|
| Port | 990 (Control), 989 (Data) | 21 (ทั้ง Control และ Data) |
| การเข้ารหัส | บังคับตั้งแต่เริ่มต้น Mandatory | เริ่มจาก Plaintext แล้ว Upgrade ด้วย AUTH TLS |
| คำสั่ง Upgrade | ไม่มี — เข้ารหัสทันที | AUTH TLS หรือ AUTH SSL |
| Backward Compat | ❌ ไม่รองรับ FTP ธรรมดา | ✅ รองรับ (แต่ควรบังคับ TLS) |
| RFC | ไม่มี RFC อย่างเป็นทางการ | RFC 4217 |
| การใช้งาน | ลดลง Legacy | แพร่หลายกว่า Preferred |
sequenceDiagram participant C as FTPS Client participant S as FTPS Server Note over C,S: Explicit FTPS (FTPES) — เริ่มจาก Plaintext แล้ว Upgrade C->>S: TCP Connect Port 21 S-->>C: 220 FTP Server Ready (Plaintext) C->>S: AUTH TLS (ขอ Upgrade เป็น TLS) S-->>C: 234 AUTH TLS OK (ยอมรับ Upgrade) Note over C,S: TLS Handshake เริ่มต้น C->>S: ClientHello (TLS Version + Supported Ciphers) S-->>C: ServerHello + Certificate (ใบรับรอง) C->>S: Certificate Verification (ตรวจสอบ CA) C->>S: Key Exchange (แลกเปลี่ยน Key) S-->>C: Finished (TLS Established) Note over C,S: ตั้งแต่นี้ทุกอย่างเข้ารหัส Encrypted from here C->>S: USER student01 ENCRYPTED S-->>C: 331 Password Required ENCRYPTED C->>S: PASS P@ssw0rd2024 ENCRYPTED S-->>C: 230 Login Successful ENCRYPTED
TLS Record Overhead Calculation:
เมื่อส่งข้อมูลผ่าน TLS จะมี Overhead เพิ่มขึ้นต่อ Record:
ตัวอย่าง TLS 1.3 with AES-128-GCM: H=5, IV=0 (ฝังใน Nonce), MAC(GCM Auth Tag)=16, P=0:
เปอร์เซ็นต์ Overhead ต่อ TLS Record ขนาดสูงสุด 16,384 bytes:
Overhead ของ TLS น้อยมาก (< 0.2%) ไม่มีผลกระทบด้านประสิทธิภาพในการใช้งานจริง
python3 -c "
header, auth_tag = 5, 16
record_size = 16384
overhead = header + auth_tag
pct = (overhead / record_size) * 100
print(f'TLS Record Size: {record_size:,} bytes')
print(f'TLS Overhead: {overhead} bytes/record')
print(f'Overhead %: {pct:.3f}%')
"
# TLS Record Size: 16,384 bytes
# TLS Overhead: 21 bytes/record
# Overhead %: 0.128%
ขั้นตอนที่ 1: สร้าง Self-signed TLS Certificate
# สร้าง Certificate อายุ 365 วัน
sudo openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 \
-keyout /etc/ssl/private/vsftpd.key \
-out /etc/ssl/certs/vsftpd.crt \
-subj "/C=TH/ST=Songkhla/L=Hat_Yai/O=RMUTSV/OU=NetworkSec/CN=192.168.1.10"
# กำหนด Permission ที่ปลอดภัย
sudo chmod 600 /etc/ssl/private/vsftpd.key
# ตรวจสอบ Certificate
sudo openssl x509 -in /etc/ssl/certs/vsftpd.crt -text -noout | grep -E "Subject:|Not After"
# Subject: C=TH, ST=Songkhla, O=RMUTSV, CN=192.168.1.10
# Not After : Jun 10 10:00:00 2025 GMT
ขั้นตอนที่ 2: กำหนดค่า vsftpd.conf สำหรับ FTPS
sudo tee /etc/vsftpd.conf << 'EOF'
# vsftpd — Explicit FTPS Configuration
listen=YES
listen_ipv6=NO
local_enable=YES
anonymous_enable=NO
write_enable=YES
local_umask=022
chroot_local_user=YES
allow_writeable_chroot=NO
# TLS Configuration
ssl_enable=YES
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1_2=YES
ssl_sslv2=NO
ssl_sslv3=NO
rsa_cert_file=/etc/ssl/certs/vsftpd.crt
rsa_private_key_file=/etc/ssl/private/vsftpd.key
# Passive Mode
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=50000
# Logging
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log
log_ftp_protocol=YES
EOF
sudo systemctl restart vsftpd
ขั้นตอนที่ 3: ทดสอบ FTPS ด้วย lftp
# ติดตั้ง lftp
sudo apt install lftp -y
# เชื่อมต่อ FTPS
lftp << 'EOF'
set ftp:ssl-force true
set ftp:ssl-protect-data true
set ssl:verify-certificate no
open -u student01,P@ssw0rd2024 ftp://192.168.1.10
ls
bye
EOF
# ตรวจสอบว่า Credentials ไม่โชว์ใน Packet
sudo tcpdump -i eth0 -A 'port 21' -w /tmp/ftps.pcap &
lftp -u student01,P@ssw0rd2024 ftps://192.168.1.10 -e "ls; bye"
sudo kill %1
sudo tcpdump -r /tmp/ftps.pcap -A | grep -i "pass\|user"
# ไม่ควรเห็น Credentials — เข้ารหัสแล้ว!
SCP (Secure Copy Protocol) คือโปรโตคอลสำหรับคัดลอกไฟล์ระหว่างเครื่องอย่างปลอดภัยผ่าน SSH ทำงานโดยส่ง SSH Command พิเศษไปยัง Remote Host ใช้ Port 22 เพียง Port เดียว
⚠️ หมายเหตุสำคัญ: OpenSSH 9.0+ ได้ Deprecate SCP Protocol เดิม และใช้ SFTP Protocol ทำงานหลังเบื้องหลังแทน คำสั่ง
scpยังคงใช้ได้ตามปกติ
sequenceDiagram participant L as Local Machine (เครื่องต้นทาง) participant R as Remote Server (192.168.1.10) Note over L,R: SCP ทำงานบน SSH Channel — Port 22 เท่านั้น L->>R: SSH Connection + Authentication (Key หรือ Password) R-->>L: SSH Session Established (ช่องทางเข้ารหัส) L->>R: SSH Command: scp -t /destination/ (โหมด Receive) R-->>L: Ready to receive (0x00 = OK) L->>R: File Metadata Header (ชื่อ, ขนาด, Permissions) L->>R: File Data Stream (ข้อมูลไฟล์ — เข้ารหัสทั้งหมด) R-->>L: Acknowledgment 0x00 Note over L,R: ทำซ้ำสำหรับไฟล์ถัดไปถ้ามี
SCP Command Syntax และตัวอย่าง:
# รูปแบบพื้นฐาน
scp [OPTIONS] SOURCE DESTINATION
# ตัวอย่างที่ 1: คัดลอกไฟล์จาก Local ไป Remote
scp /tmp/report.pdf student01@192.168.1.10:/home/student01/
# ตัวอย่างที่ 2: คัดลอกไฟล์จาก Remote มา Local
scp student01@192.168.1.10:/home/student01/data.csv /tmp/
# ตัวอย่างที่ 3: คัดลอก Directory ทั้งหมด (Recursive)
scp -r /tmp/project/ student01@192.168.1.10:/home/student01/
# ตัวอย่างที่ 4: ระบุ SSH Key
scp -i ~/.ssh/id_ed25519 /tmp/report.pdf student01@192.168.1.10:/home/student01/
# ตัวอย่างที่ 5: ระบุ Port ที่ไม่ใช่ 22
scp -P 2222 /tmp/file.txt student01@192.168.1.10:/home/student01/
# ตัวอย่างที่ 6: จำกัด Bandwidth ที่ 1024 KB/s
scp -l 1024 /tmp/large_file.tar.gz student01@192.168.1.10:/home/student01/
# ตัวอย่างที่ 7: คัดลอกระหว่าง 2 Remote Hosts
scp student01@192.168.1.10:/data/file.txt student02@192.168.1.20:/backup/
การทดลองและตรวจสอบ Integrity:
# สร้างไฟล์ทดสอบ 10MB
dd if=/dev/urandom bs=1M count=10 of=/tmp/test_10mb.bin
ls -lh /tmp/test_10mb.bin
# คัดลอกและจับเวลา
time scp /tmp/test_10mb.bin student01@192.168.1.10:/home/student01/
# test_10mb.bin 100% 10MB 45.2MB/s 00:00
# real 0m0.234s
# ตรวจสอบ Integrity ด้วย MD5 Checksum
LOCAL_MD5=$(md5sum /tmp/test_10mb.bin | cut -d' ' -f1)
REMOTE_MD5=$(ssh student01@192.168.1.10 "md5sum /home/student01/test_10mb.bin" | cut -d' ' -f1)
echo "Local: $LOCAL_MD5"
echo "Remote: $REMOTE_MD5"
[ "$LOCAL_MD5" = "$REMOTE_MD5" ] && echo "✅ Files Match!" || echo "❌ Files Differ!"
SSHFS (SSH Filesystem) ทำให้ Mount Remote Directory ผ่าน SSH เป็นเหมือน Local Drive โดยใช้ FUSE (Filesystem in Userspace)
graph TB
subgraph local["Local Machine (เครื่องผู้ใช้)"]
App["Application\nอ่าน/เขียนไฟล์ปกติ"]
Mount["Mount Point\n/mnt/remote_server\n(เสมือน Local Drive)"]
FUSE["FUSE Driver\nส่งต่อ File Operations ผ่าน Kernel"]
SSHFS_C["SSHFS Client\nแปลง VFS Calls เป็น SFTP Commands"]
end
subgraph tunnel["SSH Encrypted Tunnel (Port 22)"]
SSH_T["AES-256 / ChaCha20\nทุก Byte เข้ารหัส"]
end
subgraph remote["Remote Server (192.168.1.10)"]
SSHD2["sshd + internal-sftp"]
FS2["Remote Filesystem\n/home/student01/"]
end
App --> Mount --> FUSE --> SSHFS_C --> SSH_T --> SSHD2 --> FS2
style local fill:#4A2518,color:#FFF5DC
style tunnel fill:#2C1A0E,color:#FFF5DC
style remote fill:#3D1F10,color:#FFF5DC
การติดตั้งและใช้งาน SSHFS:
# ติดตั้ง SSHFS
sudo apt install sshfs -y
# สร้าง Mount Point
mkdir -p /mnt/server_home
# Mount Remote Directory
sshfs student01@192.168.1.10:/home/student01/ /mnt/server_home \
-o reconnect \
-o ServerAliveInterval=15 \
-o ServerAliveCountMax=3 \
-o IdentityFile=~/.ssh/id_ed25519
# ตรวจสอบว่า Mount สำเร็จ
df -h /mnt/server_home
# student01@192.168.1.10:/home/student01 50G 5G 45G 10% /mnt/server_home
# ใช้งานเหมือน Local Drive!
ls -la /mnt/server_home/
cp /tmp/new_file.txt /mnt/server_home/
cat /mnt/server_home/readme.txt
# Unmount เมื่อเสร็จ
fusermount -u /mnt/server_home
Auto-mount ผ่าน /etc/fstab:
# เพิ่มใน /etc/fstab
echo "student01@192.168.1.10:/home/student01 /mnt/server_home fuse.sshfs \
defaults,_netdev,reconnect,IdentityFile=/home/localuser/.ssh/id_ed25519,\
ServerAliveInterval=15,uid=1000,gid=1000 0 0" | sudo tee -a /etc/fstab
sudo mount -a # ทดสอบ fstab
| คุณสมบัติ | SCP | rsync over SSH | SSHFS |
|---|---|---|---|
| วัตถุประสงค์ | Copy ไฟล์ครั้งเดียว | Sync/Backup | Mount เป็น Drive |
| Incremental Transfer | ❌ ส่งทั้งหมดทุกครั้ง | ✅ ส่งเฉพาะส่วนที่เปลี่ยน | ✅ On-demand |
| Resume ต่อได้ | ❌ | ✅ | ✅ |
| ใช้งานเหมือน Local | ❌ | ❌ | ✅ |
| Compression | ✅ -C flag |
✅ -z flag |
✅ รองรับ |
| Bandwidth Efficient | ต่ำ | สูงมาก | กลาง |
| ความง่ายใช้งาน | ง่ายมาก | ปานกลาง | ปานกลาง |
| Use Case | Copy ไฟล์เดี่ยว | Backup/Sync | Edit Remote Files |
# rsync over SSH — Incremental Backup
rsync -avz --progress \
-e "ssh -i ~/.ssh/id_ed25519" \
/local/project/ \
student01@192.168.1.10:/home/student01/project/
# -a = archive (รักษา permissions, timestamps, symlinks)
# -v = verbose
# -z = compress ระหว่างส่ง
# --progress = แสดงความคืบหน้า
# Dry Run ดูก่อนว่าจะ sync อะไรบ้าง
rsync -avz --dry-run -e "ssh -i ~/.ssh/id_ed25519" \
/local/project/ student01@192.168.1.10:/home/student01/project/
SSH (Secure Shell) เป็นโปรโตคอลสำหรับการสื่อสารที่ปลอดภัยผ่านเครือข่ายที่ไม่น่าเชื่อถือ พัฒนาโดย Tatu Ylönen ในปี 1995 เพื่อแทน Telnet และ rsh ที่ส่งข้อมูลแบบ Plaintext
graph TB
subgraph layers["SSH Protocol Layers ชั้นโปรโตคอล (RFC 4251-4254)"]
L4["SSH Connection Protocol (RFC 4254)\nจัดการ Channels: Shell, SFTP, Port Forward, X11"]
L3["SSH Authentication Protocol (RFC 4252)\nPassword, Public Key, GSSAPI, Host-based"]
L2["SSH Transport Layer Protocol (RFC 4253)\nKey Exchange ECDH/DH, Encryption AES/ChaCha20, Integrity HMAC"]
L1["TCP/IP Network Layer\nPort 22 — ช่องทางเครือข่าย"]
L4 --> L3 --> L2 --> L1
end
style L4 fill:#6B3A2A,color:#FFF5DC
style L3 fill:#5A2E1A,color:#FFF5DC
style L2 fill:#4A2518,color:#FFF5DC
style L1 fill:#3D1F10,color:#FFF5DC
sequenceDiagram
participant C as SSH Client
participant S as SSH Server (sshd)
Note over C,S: Phase 1: TCP Connection & Version Exchange
C->>S: TCP SYN Port 22
S-->>C: TCP SYN-ACK
C->>S: SSH-2.0-OpenSSH_9.0
S-->>C: SSH-2.0-OpenSSH_9.0p1 Ubuntu-3
Note over C,S: Phase 2: Key Exchange — ECDH Curve25519
C->>S: SSH_MSG_KEXINIT (รายการ Algorithm ที่รองรับ)
S-->>C: SSH_MSG_KEXINIT (เลือก Algorithm ที่ดีที่สุด)
C->>S: SSH_MSG_KEX_ECDH_INIT (Client Ephemeral Public Key)
S-->>C: SSH_MSG_KEX_ECDH_REPLY (Server Public Key + Signature)
Note over C,S: ทั้งสองฝ่ายคำนวณ Shared Secret ⟶ Session Keys (ไม่ผ่านเครือข่าย)
Note over C,S: Phase 3: User Authentication
C->>S: SSH_MSG_USERAUTH_REQUEST (username + auth method)
alt Public Key Authentication (แนะนำ)
C->>S: ส่ง Public Key + Signature (ลายเซ็นด้วย Private Key)
S->>S: ตรวจสอบ Public Key ใน ~/.ssh/authorized_keys
S-->>C: SSH_MSG_USERAUTH_SUCCESS
else Password Authentication
S-->>C: ขอ Password
C->>S: Password (Encrypted ด้วย Session Key)
S-->>C: SSH_MSG_USERAUTH_SUCCESS
end
Note over C,S: Phase 4: Encrypted Session
C->>S: Open Channel (shell / sftp / port-forward)
S-->>C: Channel Confirmed — สื่อสาร Encrypted ทั้งหมด
ประเภท SSH Key Algorithm:
| Algorithm | Key Size | Security Level | ความเร็ว | แนะนำ |
|---|---|---|---|---|
| RSA | 2048 / 4096 บิต | 112 / 140 บิต equiv | ช้า | ✅ ถ้า Legacy จำเป็น |
| DSA | 1024 บิต (fixed) | 80 บิต equiv | ปานกลาง | ❌ เลิกใช้แล้ว |
| ECDSA | 256 / 384 / 521 บิต | 128 / 192 / 260 บิต equiv | เร็ว | ✅ |
| Ed25519 | 255 บิต (fixed) | ~128 บิต equiv | เร็วมาก | ✅✅ แนะนำสูงสุด |
การคำนวณ Security Level ของ RSA Key:
ตัวแปร: S = Security bits equivalent, n = จำนวนบิตของ RSA Key
# คำนวณ Security Level ของ RSA Keys
python3 -c "
import math
def rsa_security_bits(n_bits):
log2_n = n_bits
log2_log2_n = math.log2(n_bits)
return 1.923 * (log2_n ** (1/3)) * (log2_log2_n ** (2/3)) - 4.69
for bits in [1024, 2048, 3072, 4096]:
sec = rsa_security_bits(bits)
status = 'INSECURE' if sec < 100 else 'OK' if sec < 128 else 'GOOD'
print(f'RSA-{bits}: ~{sec:.1f}-bit security [{status}]')
"
# RSA-1024: ~80.0-bit security [INSECURE] — Deprecated!
# RSA-2048: ~111.5-bit security [OK] — Acceptable until 2030
# RSA-3072: ~128.6-bit security [GOOD] — Recommended
# RSA-4096: ~140.0-bit security [GOOD] — Strong
การสร้าง SSH Key Pair:
# ========================================
# สร้าง Ed25519 Key (แนะนำที่สุด)
# ========================================
ssh-keygen -t ed25519 \
-C "student01@rmutsv.ac.th" \
-f ~/.ssh/id_ed25519
# กด Enter สองครั้ง (ไม่ใส่ Passphrase สำหรับ Lab)
# หรือใส่ Passphrase เพื่อความปลอดภัยสูงสุด
# ตรวจสอบไฟล์ที่สร้าง
ls -la ~/.ssh/
# -rw------- 1 user user 411 ... id_ed25519 ← Private Key (เก็บลับ!)
# -rw-r--r-- 1 user user 97 ... id_ed25519.pub ← Public Key (แชร์ได้)
# ดูเนื้อหา Public Key
cat ~/.ssh/id_ed25519.pub
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... student01@rmutsv.ac.th
# ตรวจสอบ Key Fingerprint
ssh-keygen -lf ~/.ssh/id_ed25519.pub
# 256 SHA256:xxxxxxxxxxxxxxxxxxxx student01@rmutsv.ac.th (ED25519)
# ========================================
# สร้าง RSA-4096 Key (สำหรับ Legacy System)
# ========================================
ssh-keygen -t rsa -b 4096 -C "student01@rmutsv.ac.th" -f ~/.ssh/id_rsa_4096
sequenceDiagram participant C as SSH Client (มี Private Key) participant S as SSH Server (มี authorized_keys) Note over C,S: ขั้นตอนเตรียมการ — ทำเพียงครั้งเดียว C->>S: ssh-copy-id — ส่ง Public Key ไปเก็บใน ~/.ssh/authorized_keys Note over C,S: การ Login ด้วย Key — ทุกครั้งที่เชื่อมต่อ C->>S: SSH Connection + ระบุ Public Key ที่ต้องการใช้ S->>S: ตรวจสอบ Public Key อยู่ใน authorized_keys? S-->>C: Challenge: Random Data เข้ารหัสด้วย Public Key C->>C: ถอดรหัส Challenge ด้วย Private Key (บน Local เท่านั้น) C->>S: ส่ง Response = Hash(Decrypted Challenge + Session ID) S->>S: ตรวจสอบ Response ถูกต้องไหม? S-->>C: Authentication Successful Note over C,S: Private Key ไม่เคยออกจากเครื่อง Client เลย!
ขั้นตอนการตั้งค่า Key-based Authentication:
# ========================================
# คัดลอก Public Key ไป Server
# ========================================
# วิธีที่ 1: ใช้ ssh-copy-id (ง่ายที่สุด)
ssh-copy-id -i ~/.ssh/id_ed25519.pub student01@192.168.1.10
# Number of key(s) added: 1
# Now try logging into the machine, with: "ssh 'student01@192.168.1.10'"
# วิธีที่ 2: Manual (ถ้า ssh-copy-id ไม่มี)
cat ~/.ssh/id_ed25519.pub | ssh student01@192.168.1.10 \
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
# ทดสอบ — Login โดยไม่ถาม Password
ssh student01@192.168.1.10
# student01@server:~$ ← เข้าได้ทันที!
# ========================================
# SSH Agent — จัดการ Key และ Passphrase
# ========================================
eval $(ssh-agent -s) # Start Agent
ssh-add ~/.ssh/id_ed25519 # เพิ่ม Key
ssh-add -l # ดู Key ที่อยู่ใน Agent
ssh student01@192.168.1.10 # Login โดยไม่ถาม Passphrase
# สำรองไฟล์ Config ก่อนแก้ไข
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
กำหนดค่า /etc/ssh/sshd_config แบบ Hardened:
# ==========================================
# /etc/ssh/sshd_config — Hardened Configuration
# RMUTSV Network Security Lab
# ==========================================
# --- Port & Binding ---
Port 2222
AddressFamily inet
ListenAddress 0.0.0.0
# --- Cryptographic Settings ---
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,diffie-hellman-group14-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256
# --- Authentication ---
PasswordAuthentication no # บังคับใช้ Key เท่านั้น
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PermitRootLogin no # ห้าม Login ด้วย Root
PermitEmptyPasswords no
ChallengeResponseAuthentication no
MaxAuthTries 3 # ล้มเหลวได้สูงสุด 3 ครั้ง
MaxSessions 5
# --- Access Control ---
AllowUsers student01 admin backup_user # อนุญาตเฉพาะ User เหล่านี้
# AllowGroups sshusers # หรือระบุเป็น Group
# --- Timeout ---
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
# --- Feature Restrictions ---
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
PermitTunnel no
PrintMotd no
Banner /etc/ssh/banner.txt
# --- Logging ---
LogLevel VERBOSE
SyslogFacility AUTH
# --- SFTP Subsystem ---
Subsystem sftp internal-sftp -l INFO
# --- SFTP Chroot สำหรับ sftpusers ---
Match Group sftpusers
ForceCommand internal-sftp -l INFO
ChrootDirectory /srv/sftp/%u
AllowTcpForwarding no
X11Forwarding no
AllowAgentForwarding no
# สร้าง Banner เตือนผู้ใช้
sudo tee /etc/ssh/banner.txt << 'EOF'
*******************************************************************************
* WARNING: Authorized Access Only — ห้ามเข้าถึงโดยไม่ได้รับอนุญาต *
* All connections are logged — ทุกการเชื่อมต่อถูกบันทึกและตรวจสอบ *
* RMUTSV Network Security Lab — ห้องปฏิบัติการความมั่นคงเครือข่าย *
*******************************************************************************
EOF
# ตรวจสอบและ Apply
sudo sshd -t && echo "Config OK"
sudo systemctl reload sshd
# ทดสอบด้วย Port ใหม่
ssh -p 2222 student01@192.168.1.10
fail2ban Monitor Log และ Ban IP ที่พยายาม Login ผิดพลาดหลายครั้ง:
# ติดตั้ง fail2ban
sudo apt install fail2ban -y
# กำหนดค่า
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600 # Ban 1 ชั่วโมง (วินาที)
findtime = 600 # ดูย้อนหลัง 10 นาที
maxretry = 5 # Ban เมื่อผิดเกิน 5 ครั้ง
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200 # Ban SSH เป็นพิเศษ 2 ชั่วโมง
EOF
sudo systemctl enable fail2ban
sudo systemctl restart fail2ban
# ตรวจสอบสถานะ
sudo fail2ban-client status sshd
# |- Filter: Currently failed: 0, Total failed: 0
# `- Actions: Currently banned: 0, Total banned: 0
# Unban IP ที่ถูก Ban โดยไม่ตั้งใจ
sudo fail2ban-client set sshd unbanip 192.168.1.100
การคำนวณ Entropy ของ SSH Passphrase:
ตัวอย่าง: Passphrase MyS3cur3P@ss! ยาว 13 ตัวอักษร จาก 95 ตัวอักษร ASCII Printable:
ตัวแปร: H = Entropy (บิต), L = ความยาว Passphrase, N = จำนวนตัวอักษรที่เป็นไปได้
python3 -c "
import math
tests = [
('MyS3cur3P@ss!', 13, 95), # ASCII Printable
('correcthorsebatterystaple', 25, 26), # Lowercase only
('Ab1!Cd2@Ef3#', 12, 94), # Mixed complex
]
for phrase, L, N in tests:
H = L * math.log2(N)
level = 'WEAK' if H < 60 else 'OK' if H < 80 else 'STRONG'
print(f'Passphrase: {phrase!r:<30} L={L}, N={N}, H={H:.1f} bits [{level}]')
"
# Passphrase: 'MyS3cur3P@ss!' L=13, N=95, H=85.4 bits [STRONG]
# Passphrase: 'correcthorsebatterystaple' L=25, N=26, H=117.7 bits [STRONG]
# Passphrase: 'Ab1!Cd2@Ef3#' L=12, N=94, H=78.8 bits [OK]
| คุณสมบัติ | FTP | SFTP | FTPS (Explicit) | SCP |
|---|---|---|---|---|
| Port หลัก | 21+20 (Dual) | 22 (Single) | 21+Data Port | 22 (Single) |
| การเข้ารหัส | ❌ ไม่มี | ✅ SSH (AES-256, ChaCha20) | ✅ TLS 1.2/1.3 | ✅ SSH |
| Credential Encryption | ❌ Plaintext | ✅ เข้ารหัส | ✅ เข้ารหัส | ✅ เข้ารหัส |
| SSH Key Support | ❌ | ✅ | ❌ (ใช้ Certificate) | ✅ |
| Firewall Friendly | 🟡 ปัญหา NAT | ✅ ดีมาก | 🟡 ต้องเปิด Data Port | ✅ ดีมาก |
| Resume Transfer | ❌ | ✅ | 🟡 บางไคลเอนต์ | ❌ |
| Full File Ops | ✅ | ✅ | ✅ | ❌ (แค่ Copy) |
| Anonymous Access | ✅ รองรับ | ❌ | ❌ | ❌ |
| Chroot Jail | 🟡 ซับซ้อน | ✅ Built-in | 🟡 vsftpd | N/A |
| RFC Standard | RFC 959 | IETF Draft | RFC 4217 | ไม่มี RFC |
| สถานะ | 🔴 Legacy/Insecure | ✅ แนะนำ | ✅ ยอมรับได้ | ✅ ใช้ได้ |
flowchart TD
Start["เริ่มต้น: ต้องการถ่ายโอนไฟล์\nStart: Need to Transfer Files"]
Start --> Q1{"ต้องการ Security?\nSecurity Required?"}
Q1 -->|"ไม่ (Lab เท่านั้น)"| FTP["FTP\n⚠️ Lab Only — ไม่ใช้ Production"]
Q1 -->|"ใช่ (เสมอใน Production)"| Q2
Q2{"ใช้ SSH อยู่แล้วไหม?\nAlready using SSH?"}
Q2 -->|"ใช่ — มี SSH"| Q3
Q2 -->|"ไม่ — มีแค่ FTP Server"| Q4
Q3{"ต้องการทำอะไร?"}
Q3 -->|"Copy ไฟล์เดี่ยว/ไม่กี่ไฟล์"| SCP["SCP\n✅ ง่าย รวดเร็ว คำสั่งเดียว"]
Q3 -->|"จัดการไฟล์ Interactive"| SFTP["SFTP\n✅ แนะนำ — Full File Operations"]
Q3 -->|"Backup / Sync อัตโนมัติ"| RSYNC["rsync over SSH\n✅ Incremental — ประหยัด Bandwidth"]
Q3 -->|"ทำงานกับไฟล์บ่อยๆ"| SSHFS["SSHFS\n✅ Mount เป็น Local Drive"]
Q4{"Client รองรับ FTPS?"}
Q4 -->|"ใช่ — Legacy Client"| FTPS["FTPS Explicit\n✅ FTP + TLS (RFC 4217)"]
Q4 -->|"ไม่ — ย้ายได้เลย"| SFTP
style FTP fill:#8B0000,color:#FFF
style SCP fill:#1A4A1A,color:#FFF
style SFTP fill:#1A3A4A,color:#FFF
style RSYNC fill:#2A1A4A,color:#FFF
style SSHFS fill:#1A2A4A,color:#FFF
style FTPS fill:#3A2E10,color:#FFF
| สถานการณ์ | โปรโตคอลที่เหมาะสม | เหตุผล |
|---|---|---|
| ส่ง Report ไปยัง Server | SCP | ง่าย รวดเร็ว คำสั่งเดียวจบ |
| อัปโหลดเว็บไซต์ | SFTP (GUI) | จัดการ Permission ได้ รองรับ Resume |
| Backup ประจำวัน | rsync over SSH | Incremental ลดเวลาและ Bandwidth |
| Windows User | SFTP (WinSCP) | GUI ใช้งานง่าย ลาก-วางได้ |
| Legacy FTP Server | FTPS | Upgrade Security โดยไม่เปลี่ยน Protocol |
| ทำงาน Edit ไฟล์บน Server | SSHFS | เหมือน Local Drive ทำงานกับ IDE ได้ |
| Public Download Server | HTTPS | ดีกว่า FTP ทุกด้าน |
| IoT / Embedded System | SCP หรือ SFTP | Lightweight ใช้ทรัพยากรน้อย |
| CI/CD Pipeline | SCP หรือ rsync | Scriptable ทำงานอัตโนมัติได้ |
mindmap
root((File Transfer - Server Security))
การพิสูจน์ตัวตน - Authentication
SSH Key เท่านั้น No Password
MFA สำหรับ Admin Accounts
ล็อค Account หลัง Login ผิด
Passphrase บน Private Key
การควบคุมการเข้าถึง - Access Control
Chroot Jail — จำกัด Directory
Principle of Least Privilege
Per-User Permission Rules
IP Whitelisting ถ้าเป็นไปได้
การเข้ารหัส - Encryption
TLS 1.2 ขึ้นไปสำหรับ FTPS
AES-256-GCM / ChaCha20 สำหรับ SSH
Perfect Forward Secrecy PFS
Certificate Validation
การ Monitor - Monitoring
Log ทุก Connection
Log ทุก File Transfer Operation
Real-time Alert เมื่อผิดปกติ
ตรวจสอบ Log เป็นประจำ
Network Security
Firewall Rules เฉพาะเจาะจง
Rate Limiting ต่อ Connection
fail2ban Block Brute-force
IDS Integration Snort/Suricata
# ขั้นตอนที่ 1: โครงสร้าง Directory
sudo mkdir -p /srv/ftps/{uploads,downloads,shared}
sudo groupadd ftpsusers
# สร้าง User สำหรับ FTPS (ไม่มี Shell)
sudo useradd -M -d /srv/ftps -G ftpsusers -s /sbin/nologin ftpsuser01
echo "ftpsuser01:FtpsS3cur3!" | sudo chpasswd
# กำหนด Permission (สำคัญ!)
sudo chown root:root /srv/ftps
sudo chmod 755 /srv/ftps
sudo chown ftpsuser01:ftpsusers /srv/ftps/uploads /srv/ftps/downloads
sudo chmod 750 /srv/ftps/uploads /srv/ftps/downloads
sudo chown root:ftpsusers /srv/ftps/shared
sudo chmod 750 /srv/ftps/shared
# ขั้นตอนที่ 2: Config ที่ปลอดภัยสมบูรณ์
sudo tee /etc/vsftpd.conf << 'EOF'
# vsftpd — Secure FTPS + Chroot Configuration
listen=YES
listen_ipv6=NO
local_enable=YES
anonymous_enable=NO
write_enable=YES
local_umask=022
# Chroot
chroot_local_user=YES
allow_writeable_chroot=NO
secure_chroot_dir=/var/run/vsftpd/empty
# TLS/SSL (Explicit FTPS)
ssl_enable=YES
require_ssl_reuse=NO
ssl_ciphers=HIGH:!aNULL:!MD5:!RC4:!SSLv2:!SSLv3
force_local_data_ssl=YES
force_local_logins_ssl=YES
allow_anon_ssl=NO
ssl_tlsv1_2=YES
ssl_sslv2=NO
ssl_sslv3=NO
rsa_cert_file=/etc/ssl/certs/vsftpd.crt
rsa_private_key_file=/etc/ssl/private/vsftpd.key
# Passive Mode
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=50000
pasv_address=192.168.1.10
# Limits
local_max_rate=1048576 # 1 MB/s per connection
max_clients=20
max_per_ip=3
idle_session_timeout=300
data_connection_timeout=120
# Logging
xferlog_enable=YES
xferlog_file=/var/log/vsftpd.log
log_ftp_protocol=YES
ftpd_banner=Authorized Access Only — RMUTSV
EOF
sudo systemctl restart vsftpd && sudo systemctl status vsftpd
#!/bin/bash
# ssh_security_check.sh — ตรวจสอบความปลอดภัย SSH Server
echo "=== SSH Security Check — $(date) ==="
echo ""
# ตรวจสอบ SSH Version
echo "SSH Version: $(ssh -V 2>&1)"
# ตรวจสอบ Port
SSH_PORT=$(grep "^Port" /etc/ssh/sshd_config | awk '{print $2}')
echo "SSH Port: ${SSH_PORT:-22}"
# ฟังก์ชันตรวจสอบ
check_config() {
local key="$1" expected="$2" desc="$3"
val=$(grep "^${key}" /etc/ssh/sshd_config | awk '{print $2}')
if [ "$val" = "$expected" ]; then
echo " ✅ $desc: $val"
else
echo " ❌ $desc: ${val:-not set} (ควรเป็น: $expected)"
fi
}
echo ""
echo "--- Authentication Settings ---"
check_config "PasswordAuthentication" "no" "Password Auth Disabled"
check_config "PermitRootLogin" "no" "Root Login Disabled"
check_config "PermitEmptyPasswords" "no" "Empty Password Disabled"
check_config "PubkeyAuthentication" "yes" "PubKey Auth Enabled"
echo ""
echo "--- Feature Restrictions ---"
check_config "X11Forwarding" "no" "X11 Forwarding Disabled"
check_config "AllowTcpForwarding" "no" "TCP Forwarding Disabled"
check_config "AllowAgentForwarding" "no" "Agent Forwarding Disabled"
echo ""
echo "--- fail2ban Status ---"
if systemctl is-active fail2ban &>/dev/null; then
echo " ✅ fail2ban: active"
sudo fail2ban-client status sshd 2>/dev/null | grep -E "failed|banned"
else
echo " ❌ fail2ban: not running"
fi
echo ""
echo "--- Recent Failed Login Attempts (last 10) ---"
sudo grep "Failed password\|Invalid user" /var/log/auth.log 2>/dev/null | tail -10
echo ""
echo "--- Active SSH Sessions ---"
who | grep pts || echo " (no active sessions)"
# Monitor SFTP Activity แบบ Real-time
sudo tail -f /var/log/auth.log | grep -E "sftp|Accepted|Failed"
# วิเคราะห์ vsftpd Transfer Log
# Format: Date Duration ClientIP Size FilePath Mode Compress Direction AuthType User ...
# ตัวอย่าง:
# Mon Jun 10 11:00:00 2024 1 192.168.1.100 1048576 /srv/ftps/uploads/data.csv b _ i r ftpsuser01 ftp 0 * c
# คำนวณ Total Transfer ต่อ User
awk '{
direction=$12; size=$8; user=$14
if(direction=="i") upload[user] += size
else if(direction=="o") download[user] += size
count[user]++
}
END {
printf "%-20s %12s %12s %8s\n", "User", "Upload(B)", "Download(B)", "Files"
for(u in count)
printf "%-20s %12d %12d %8d\n", u, upload[u], download[u], count[u]
}' /var/log/vsftpd.log | sort -k2 -rn
#!/bin/bash
# file_transfer_security_checklist.sh
PASS=0; FAIL=0; WARN=0
chk() {
local desc="$1" result="$2"
case "$result" in
PASS) echo " ✅ PASS: $desc"; ((PASS++)) ;;
FAIL) echo " ❌ FAIL: $desc"; ((FAIL++)) ;;
*) echo " ⚠️ WARN: $desc"; ((WARN++)) ;;
esac
}
echo "=== File Transfer Server Security Checklist ==="
echo "Date: $(date)"
echo ""
echo "--- SSH Server ---"
PASS_AUTH=$(grep "^PasswordAuthentication" /etc/ssh/sshd_config 2>/dev/null | awk '{print $2}')
chk "Password Authentication Disabled" "$([ "$PASS_AUTH" = "no" ] && echo PASS || echo FAIL)"
ROOT=$(grep "^PermitRootLogin" /etc/ssh/sshd_config 2>/dev/null | awk '{print $2}')
chk "Root Login Disabled" "$([ "$ROOT" = "no" ] && echo PASS || echo FAIL)"
PORT=$(grep "^Port" /etc/ssh/sshd_config 2>/dev/null | awk '{print $2}')
chk "Non-default SSH Port (${PORT:-22})" "$([ "${PORT:-22}" != "22" ] && echo PASS || echo WARN)"
chk "fail2ban Running" "$(systemctl is-active fail2ban &>/dev/null && echo PASS || echo FAIL)"
echo ""
echo "--- vsftpd (FTPS) ---"
if [ -f /etc/vsftpd.conf ]; then
ANON=$(grep "^anonymous_enable" /etc/vsftpd.conf | cut -d= -f2)
chk "Anonymous Login Disabled" "$([ "$ANON" = "NO" ] && echo PASS || echo FAIL)"
SSL=$(grep "^ssl_enable" /etc/vsftpd.conf | cut -d= -f2)
chk "TLS/SSL Enabled" "$([ "$SSL" = "YES" ] && echo PASS || echo FAIL)"
CHROOT=$(grep "^chroot_local_user" /etc/vsftpd.conf | cut -d= -f2)
chk "Chroot Jail Enabled" "$([ "$CHROOT" = "YES" ] && echo PASS || echo FAIL)"
else
chk "vsftpd Config Found" "WARN"
fi
echo ""
echo "=== Summary ==="
TOTAL=$((PASS + FAIL + WARN))
SCORE=$(( TOTAL > 0 ? PASS * 100 / TOTAL : 0 ))
echo " PASS: $PASS | FAIL: $FAIL | WARN: $WARN"
echo " Security Score: $SCORE%"
[ $SCORE -ge 80 ] && echo " Status: ACCEPTABLE" || echo " Status: NEEDS IMPROVEMENT"
บทที่ 3 นำเสนอโปรโตคอลการถ่ายโอนไฟล์และการเข้าถึงระยะไกลตั้งแต่ต้นกำเนิดจนถึงปัจจุบัน โดยแบ่งเป็น 2 กลุ่มหลัก:
โปรโตคอล Legacy ที่ไม่ปลอดภัย:
โปรโตคอลที่ปลอดภัย (Secure Alternatives):
หลักการสำคัญที่ต้องจำ:
graph LR
subgraph unsafe["ไม่ปลอดภัย — อย่าใช้ใน Production"]
FTP["FTP\nPort 21/20\nPlaintext Everything"]
TELNET["Telnet\nPort 23\nPlaintext Shell"]
end
subgraph secure["ปลอดภัย — ใช้แทน Secure Alternatives"]
SFTP2["SFTP\nPort 22\nSSH Subsystem — แนะนำสูงสุด"]
FTPS2["FTPS\nPort 21+TLS\nRFC 4217"]
SCP2["SCP\nPort 22\nSSH-based Copy"]
SSH3["SSH\nPort 22\nEncrypted Shell"]
RSYNC2["rsync/SSH\nPort 22\nIncremental Sync"]
end
FTP -->|"แทนที่ด้วย"| SFTP2
FTP -->|"หรือ"| FTPS2
FTP -->|"สำหรับ Copy"| SCP2
TELNET -->|"แทนที่ด้วย"| SSH3
style unsafe fill:#6B0000,color:#FFF
style secure fill:#0D3B0D,color:#FFF
RFC 959 — Postel, J., & Reynolds, J. (1985). File Transfer Protocol (FTP). IETF. https://datatracker.ietf.org/doc/html/rfc959
RFC 4217 — Ford-Hutchinson, P. (2005). Securing FTP with TLS. IETF. https://datatracker.ietf.org/doc/html/rfc4217
RFC 4251 — Ylonen, T., & Lonvick, C. (2006). The Secure Shell (SSH) Protocol Architecture. IETF. https://datatracker.ietf.org/doc/html/rfc4251
RFC 4252 — Ylonen, T., & Lonvick, C. (2006). The Secure Shell (SSH) Authentication Protocol. IETF. https://datatracker.ietf.org/doc/html/rfc4252
RFC 4253 — Ylonen, T., & Lonvick, C. (2006). The Secure Shell (SSH) Transport Layer Protocol. IETF. https://datatracker.ietf.org/doc/html/rfc4253
RFC 4254 — Ylonen, T., & Lonvick, C. (2006). The Secure Shell (SSH) Connection Protocol. IETF. https://datatracker.ietf.org/doc/html/rfc4254
OpenSSH Project — OpenBSD Foundation. (2024). OpenSSH Manual Pages. https://www.openssh.com/manual.html
NIST SP 800-52 Rev. 2 — McKay, K., & Cooper, D. (2019). Guidelines for the Selection, Configuration, and Use of TLS Implementations. NIST. https://csrc.nist.gov/publications/detail/sp/800-52/rev-2/final
NIST SP 800-57 Part 1 Rev. 5 — Barker, E. (2020). Recommendation for Key Management. NIST. https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final
vsftpd Documentation — Gilbert, C. (2023). vsftpd — Very Secure FTP Daemon. https://security.appspot.com/vsftpd.html
SSHFS / libfuse — Szeredi, M. (2023). SSHFS — SSH Filesystem. https://github.com/libfuse/sshfs
fail2ban — Fail2ban Project. (2024). Ban hosts that cause multiple authentication errors. https://www.fail2ban.org/
Barrett, D. J., Silverman, R. E., & Byrnes, R. G. (2005). SSH, The Secure Shell: The Definitive Guide (2nd ed.). O'Reilly Media.
CIS Benchmark for Ubuntu Linux — Center for Internet Security. (2024). CIS Ubuntu Linux 22.04 LTS Benchmark v1.0.0. https://www.cisecurity.org/benchmark/ubuntu_linux
OWASP — OWASP Foundation. (2023). Transport Layer Security Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html
Ylönen, T. (1996). SSH — Secure Login Connections over the Internet. Proceedings of the 6th USENIX Security Symposium, San Jose, CA.