โปรโตคอลระดับ Application (Application Layer Protocols) เป็นชั้นบนสุดในโมเดล OSI และ TCP/IP ทำหน้าที่เป็นส่วนติดต่อระหว่างผู้ใช้กับระบบเครือข่าย โดยโปรโตคอลเหล่านี้กำหนดวิธีการสื่อสารระหว่างแอปพลิเคชันต่างๆ ผ่านเครือข่าย
ในบริบทของความปลอดภัยเครือข่าย การเข้าใจโปรโตคอลเหล่านี้มีความสำคัญเนื่องจาก:
graph TB
subgraph APP["Application Layer Protocols"]
direction TB
subgraph FT["File Transfer โปรโตคอลถ่ายโอนไฟล์"]
FTP["FTP
Port 21/20"]
TFTP["TFTP
Port 69"]
SFTP["SFTP
Port 22"]
FTPS["FTPS
Port 990"]
end
subgraph RA["Remote Access การเข้าถึงระยะไกล"]
SSH["SSH
Port 22"]
SCP["SCP
Port 22"]
end
end
style APP fill:#282828,stroke:#ebdbb2,color:#ebdbb2
style FT fill:#3c3836,stroke:#b8bb26,color:#ebdbb2
style RA fill:#3c3836,stroke:#83a598,color:#ebdbb2
style FTP fill:#504945,stroke:#fb4934,color:#ebdbb2
style TFTP fill:#504945,stroke:#fe8019,color:#ebdbb2
style SFTP fill:#504945,stroke:#b8bb26,color:#ebdbb2
style FTPS fill:#504945,stroke:#fabd2f,color:#ebdbb2
style SSH fill:#504945,stroke:#83a598,color:#ebdbb2
style SCP fill:#504945,stroke:#d3869b,color:#ebdbb2
flowchart LR
subgraph ERA1["ยุคเริ่มต้น (1970s-1980s)"]
A1["1971: FTP
RFC 114"]
A2["1980: FTP Standard
RFC 765"]
A3["1981: TFTP
RFC 783"]
end
subgraph ERA2["ยุคพัฒนา (1990s)"]
B1["1995: SSH-1
Tatu Ylönen"]
B2["1997: FTPS
RFC 2228"]
B3["1999: SSH-2
IETF Draft"]
end
subgraph ERA3["ยุคปัจจุบัน (2000s-ปัจจุบัน)"]
C1["2006: SSH-2
RFC 4251-4256"]
C2["2006: SFTP
Draft-ietf"]
C3["2012: ED25519
Modern Crypto"]
end
ERA1 --> ERA2 --> ERA3
style ERA1 fill:#3c3836,stroke:#fb4934,color:#ebdbb2
style ERA2 fill:#3c3836,stroke:#fabd2f,color:#ebdbb2
style ERA3 fill:#3c3836,stroke:#b8bb26,color:#ebdbb2
style A1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style A2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style A3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style B1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style B2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style B3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style C1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style C2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style C3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
FTP (File Transfer Protocol) เป็นโปรโตคอลมาตรฐานสำหรับการถ่ายโอนไฟล์ระหว่างคอมพิวเตอร์ผ่านเครือข่าย TCP/IP ถูกกำหนดครั้งแรกใน RFC 959 และใช้งานมาตั้งแต่ปี 1971
คุณสมบัติหลักของ FTP:
FTP ใช้ สองการเชื่อมต่อแยกกัน (Dual Connection Architecture):
| ประเภทการเชื่อมต่อ | Port | หน้าที่ |
|---|---|---|
| Control Connection | 21 | ส่งคำสั่งและรับการตอบกลับ |
| Data Connection | 20 (Active) หรือ Dynamic (Passive) | ส่งข้อมูลไฟล์จริง |
sequenceDiagram
participant C as Client
ไคลเอนต์
participant S as Server
เซิร์ฟเวอร์
Note over C,S: Control Connection (Port 21)
C->>S: เชื่อมต่อ TCP Port 21
S-->>C: 220 Service Ready
C->>S: USER username
S-->>C: 331 Password Required
C->>S: PASS password
S-->>C: 230 User Logged In
Note over C,S: Data Connection (Active Mode)
C->>S: PORT h1,h2,h3,h4,p1,p2
S-->>C: 200 PORT OK
C->>S: RETR filename
S->>C: เชื่อมต่อ TCP จาก Port 20 ไปยัง Client Port
S-->>C: ส่งข้อมูลไฟล์
S-->>C: 226 Transfer Complete
Active Mode (โหมดแอคทีฟ):
Passive Mode (โหมดพาสซีฟ):
flowchart TB
subgraph ACTIVE["Active Mode โหมดแอคทีฟ"]
direction LR
A1["Client
Random Port"] -->|"1. PORT command"| A2["Server
Port 21"]
A2 -->|"2. Data Connection"| A1
A3["Server Port 20"] -->|"เริ่มเชื่อมต่อ"| A4["Client Port N"]
end
subgraph PASSIVE["Passive Mode โหมดพาสซีฟ"]
direction LR
B1["Client"] -->|"1. PASV command"| B2["Server
Port 21"]
B2 -->|"2. 227 (IP,Port)"| B1
B1 -->|"3. Data Connection"| B3["Server
Port N"]
end
style ACTIVE fill:#3c3836,stroke:#fb4934,color:#ebdbb2
style PASSIVE fill:#3c3836,stroke:#b8bb26,color:#ebdbb2
style A1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style A2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style A3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style A4 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style B1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style B2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style B3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
FTP มีจุดอ่อนด้านความปลอดภัยที่สำคัญ:
"""
ตัวอย่างการดักจับ FTP credentials ด้วย Python
(สำหรับการศึกษาเท่านั้น - ห้ามใช้โดยไม่ได้รับอนุญาต)
โค้ดนี้แสดงให้เห็นว่า FTP ส่งข้อมูลแบบ cleartext
ซึ่งสามารถถูกดักจับได้ง่าย
"""
from scapy.all import sniff, TCP, Raw
def analyze_ftp_packet(packet):
"""
วิเคราะห์แพ็กเก็ต FTP เพื่อหา credentials
Parameters:
packet: แพ็กเก็ตที่จับได้จากเครือข่าย
Returns:
None - แสดงผลลัพธ์ทางหน้าจอ
"""
# ตรวจสอบว่าเป็น TCP และมีข้อมูล payload
if packet.haslayer(TCP) and packet.haslayer(Raw):
# ตรวจสอบว่าเป็น FTP (port 21)
if packet[TCP].dport == 21 or packet[TCP].sport == 21:
payload = packet[Raw].load.decode('utf-8', errors='ignore')
# ตรวจหา USER command
if payload.startswith('USER'):
username = payload.split()[1].strip()
print(f"[!] พบ Username: {username}")
# ตรวจหา PASS command
elif payload.startswith('PASS'):
password = payload.split()[1].strip()
print(f"[!] พบ Password: {password}")
# ตัวอย่างการใช้งาน (ต้องรันด้วยสิทธิ์ root)
# sniff(filter="tcp port 21", prn=analyze_ftp_packet, store=0)
# ผลลัพธ์ตัวอย่าง:
# [!] พบ Username: admin
# [!] พบ Password: secret123
TFTP (Trivial File Transfer Protocol) เป็นโปรโตคอลถ่ายโอนไฟล์แบบเรียบง่ายที่ออกแบบมาสำหรับการใช้งานที่ไม่ต้องการความซับซ้อน ถูกกำหนดใน RFC 1350
คุณสมบัติหลักของ TFTP:
กรณีที่ควรใช้ TFTP:
sequenceDiagram
participant C as Client
ไคลเอนต์
participant S as Server
เซิร์ฟเวอร์ Port 69
Note over C,S: TFTP Read Request (RRQ)
C->>S: RRQ "filename" octet
S-->>C: DATA Block 1 (512 bytes)
C->>S: ACK Block 1
S-->>C: DATA Block 2 (512 bytes)
C->>S: ACK Block 2
S-->>C: DATA Block 3 (<512 bytes = สิ้นสุด)
C->>S: ACK Block 3
Note over C,S: ไฟล์ถูกถ่ายโอนสำเร็จ
TFTP มีความเสี่ยงสูงมาก:
| ความเสี่ยง | คำอธิบาย | ระดับความรุนแรง |
|---|---|---|
| ไม่มี Authentication | ใครก็สามารถดาวน์โหลด/อัปโหลดไฟล์ได้ | สูงมาก |
| ไม่มี Encryption | ข้อมูลถูกส่งแบบ plaintext | สูง |
| Directory Traversal | อาจเข้าถึงไฟล์นอก root directory ได้ | สูง |
| UDP Spoofing | ง่ายต่อการปลอมแปลง source IP | ปานกลาง |
แนวทางการป้องกัน:
SFTP (SSH File Transfer Protocol) เป็นโปรโตคอลถ่ายโอนไฟล์ที่ปลอดภัย ทำงานเป็น subsystem ของ SSH ไม่เกี่ยวข้องกับ FTP แบบดั้งเดิมแต่อย่างใด
คุณสมบัติหลักของ SFTP:
flowchart TB
subgraph CLIENT["SFTP Client"]
C1["User Interface
ส่วนติดต่อผู้ใช้"]
C2["SFTP Protocol Handler
ตัวจัดการโปรโตคอล"]
C3["SSH Client
ไคลเอนต์ SSH"]
end
subgraph SERVER["SFTP Server"]
S1["SSH Server
เซิร์ฟเวอร์ SSH"]
S2["SFTP Subsystem
ระบบย่อย SFTP"]
S3["File System
ระบบไฟล์"]
end
C1 --> C2
C2 --> C3
C3 <-->|"SSH Encrypted Channel
ช่องทางเข้ารหัส Port 22"| S1
S1 --> S2
S2 --> S3
style CLIENT fill:#3c3836,stroke:#83a598,color:#ebdbb2
style SERVER fill:#3c3836,stroke:#b8bb26,color:#ebdbb2
style C1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style C2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style C3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style S1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style S2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style S3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
การเข้ารหัสของ SFTP มี overhead ที่ส่งผลต่อประสิทธิภาพ สามารถคำนวณ throughput โดยประมาณได้ดังนี้:
คำอธิบายตัวแปร:
"""
โปรแกรมคำนวณ Throughput ของ SFTP
โปรแกรมนี้ช่วยประมาณ throughput ที่จะได้รับจริง
เมื่อใช้ SFTP เทียบกับ bandwidth ดิบของเครือข่าย
"""
def calculate_sftp_throughput(raw_bandwidth_mbps: float,
encryption_overhead: float = 0.10,
protocol_overhead: float = 0.03) -> dict:
"""
คำนวณ throughput ที่ใช้งานได้จริงของ SFTP
Parameters:
raw_bandwidth_mbps: แบนด์วิดท์ดิบเป็น Mbps
encryption_overhead: overhead จากการเข้ารหัส (ค่าเริ่มต้น 10%)
protocol_overhead: overhead จากโปรโตคอล (ค่าเริ่มต้น 3%)
Returns:
dict: ผลลัพธ์การคำนวณ
"""
# คำนวณ throughput ที่ใช้งานได้จริง
total_overhead = 1 + encryption_overhead + protocol_overhead
effective_throughput = raw_bandwidth_mbps / total_overhead
# คำนวณเวลาในการถ่ายโอนไฟล์ 1 GB
file_size_mb = 1024 * 8 # 1 GB = 1024 MB = 8192 Mb
transfer_time_seconds = file_size_mb / effective_throughput
return {
'raw_bandwidth_mbps': raw_bandwidth_mbps,
'encryption_overhead': f"{encryption_overhead * 100:.1f}%",
'protocol_overhead': f"{protocol_overhead * 100:.1f}%",
'effective_throughput_mbps': round(effective_throughput, 2),
'efficiency': f"{(effective_throughput/raw_bandwidth_mbps) * 100:.1f}%",
'time_for_1gb_seconds': round(transfer_time_seconds, 1),
'time_for_1gb_minutes': round(transfer_time_seconds / 60, 2)
}
# ตัวอย่างการใช้งาน
if __name__ == "__main__":
# ทดสอบกับ bandwidth ต่างๆ
bandwidths = [100, 1000, 10000] # 100 Mbps, 1 Gbps, 10 Gbps
print("=" * 60)
print("การคำนวณ SFTP Throughput")
print("=" * 60)
for bw in bandwidths:
result = calculate_sftp_throughput(bw)
print(f"\nBandwidth ดิบ: {bw} Mbps")
print(f" Throughput จริง: {result['effective_throughput_mbps']} Mbps")
print(f" ประสิทธิภาพ: {result['efficiency']}")
print(f" เวลาถ่ายโอน 1 GB: {result['time_for_1gb_minutes']} นาที")
# ผลลัพธ์ตัวอย่าง:
# ============================================================
# การคำนวณ SFTP Throughput
# ============================================================
#
# Bandwidth ดิบ: 100 Mbps
# Throughput จริง: 88.5 Mbps
# ประสิทธิภาพ: 88.5%
# เวลาถ่ายโอน 1 GB: 1.54 นาที
#
# Bandwidth ดิบ: 1000 Mbps
# Throughput จริง: 884.96 Mbps
# ประสิทธิภาพ: 88.5%
# เวลาถ่ายโอน 1 GB: 0.15 นาที
FTPS (FTP Secure) คือ FTP ที่เพิ่มชั้นความปลอดภัยด้วย SSL/TLS ถูกกำหนดใน RFC 4217 โดยยังคงใช้โครงสร้าง dual-connection เหมือน FTP แต่เพิ่มการเข้ารหัส
รูปแบบของ FTPS:
| รูปแบบ | คำอธิบาย | Port |
|---|---|---|
| Implicit FTPS | เข้ารหัสทันทีที่เชื่อมต่อ | 990 (Control), 989 (Data) |
| Explicit FTPS | เริ่มด้วย FTP ธรรมดา แล้วอัปเกรดด้วย AUTH TLS | 21 |
sequenceDiagram
participant C as Client
ไคลเอนต์
participant S as Server
เซิร์ฟเวอร์
Note over C,S: Explicit FTPS Handshake
C->>S: เชื่อมต่อ TCP Port 21
S-->>C: 220 FTP Server Ready
C->>S: AUTH TLS
S-->>C: 234 Using TLS
Note over C,S: TLS Handshake
C->>S: ClientHello
S-->>C: ServerHello + Certificate
C->>S: Key Exchange
S-->>C: Finished
Note over C,S: Encrypted Session
C->>S: USER username (encrypted)
S-->>C: 331 Password Required
C->>S: PASS password (encrypted)
S-->>C: 230 Login Successful
| คุณสมบัติ | FTPS | SFTP |
|---|---|---|
| พื้นฐาน | FTP + SSL/TLS | SSH Subsystem |
| Port | 21, 990 + Data Port | 22 เท่านั้น |
| การเชื่อมต่อ | Multiple | Single |
| Firewall | ซับซ้อน (หลาย port) | ง่าย (port เดียว) |
| Certificate | ต้องใช้ X.509 | ใช้ SSH Keys |
| ความเข้ากันได้ | Legacy FTP clients | ต้องการ SFTP client |
| มาตรฐาน | RFC 4217 | IETF Draft |
"""
ตัวอย่างการเชื่อมต่อ FTPS ด้วย Python
โค้ดนี้แสดงวิธีการเชื่อมต่อและถ่ายโอนไฟล์ผ่าน FTPS
โดยใช้ทั้ง Implicit และ Explicit mode
"""
from ftplib import FTP_TLS
import ssl
def connect_ftps_explicit(host: str, username: str, password: str,
port: int = 21) -> FTP_TLS:
"""
เชื่อมต่อ FTPS แบบ Explicit (AUTH TLS)
Parameters:
host: ชื่อโฮสต์หรือ IP address
username: ชื่อผู้ใช้
password: รหัสผ่าน
port: พอร์ต (ค่าเริ่มต้น 21)
Returns:
FTP_TLS: อ็อบเจกต์การเชื่อมต่อ FTPS
"""
# สร้างการเชื่อมต่อ FTP_TLS
ftps = FTP_TLS()
# กำหนด SSL context สำหรับความปลอดภัยที่ดีขึ้น
context = ssl.create_default_context()
context.check_hostname = True
context.verify_mode = ssl.CERT_REQUIRED
# เชื่อมต่อและล็อกอิน
ftps.connect(host, port)
ftps.auth() # อัปเกรดเป็น TLS
ftps.login(username, password)
ftps.prot_p() # เปิด Protected data connection
print(f"[+] เชื่อมต่อ FTPS สำเร็จ: {host}:{port}")
return ftps
def upload_file_ftps(ftps: FTP_TLS, local_path: str, remote_path: str):
"""
อัปโหลดไฟล์ผ่าน FTPS
Parameters:
ftps: อ็อบเจกต์การเชื่อมต่อ FTPS
local_path: path ของไฟล์ในเครื่อง
remote_path: path ปลายทางบนเซิร์ฟเวอร์
"""
with open(local_path, 'rb') as file:
ftps.storbinary(f'STOR {remote_path}', file)
print(f"[+] อัปโหลดสำเร็จ: {local_path} -> {remote_path}")
def download_file_ftps(ftps: FTP_TLS, remote_path: str, local_path: str):
"""
ดาวน์โหลดไฟล์ผ่าน FTPS
Parameters:
ftps: อ็อบเจกต์การเชื่อมต่อ FTPS
remote_path: path ของไฟล์บนเซิร์ฟเวอร์
local_path: path ปลายทางในเครื่อง
"""
with open(local_path, 'wb') as file:
ftps.retrbinary(f'RETR {remote_path}', file.write)
print(f"[+] ดาวน์โหลดสำเร็จ: {remote_path} -> {local_path}")
# ตัวอย่างการใช้งาน
if __name__ == "__main__":
# การใช้งานจริง (ต้องเปลี่ยนค่าตามเซิร์ฟเวอร์จริง)
"""
ftps = connect_ftps_explicit(
host="ftp.example.com",
username="user",
password="password"
)
# แสดงรายการไฟล์
ftps.dir()
# อัปโหลด/ดาวน์โหลด
upload_file_ftps(ftps, "local_file.txt", "remote_file.txt")
download_file_ftps(ftps, "remote_file.txt", "downloaded.txt")
# ปิดการเชื่อมต่อ
ftps.quit()
"""
print("ตัวอย่างการใช้งาน FTPS - ดูโค้ดในไฟล์")
SSH (Secure Shell) เป็นโปรโตคอลเครือข่ายที่ออกแบบมาเพื่อการสื่อสารที่ปลอดภัยระหว่างคอมพิวเตอร์สองเครื่อง ถูกพัฒนาโดย Tatu Ylönen ในปี 1995 เพื่อทดแทน Telnet, rlogin และ rsh ที่ไม่ปลอดภัย
คุณสมบัติหลักของ SSH:
SSH ประกอบด้วย 3 ส่วนหลัก:
flowchart TB
subgraph SSH["SSH Protocol Stack"]
direction TB
subgraph CONN["SSH Connection Layer
ชั้นการเชื่อมต่อ"]
C1["Session Channel"]
C2["X11 Forwarding"]
C3["Port Forwarding"]
C4["SFTP Subsystem"]
end
subgraph AUTH["SSH User Authentication Layer
ชั้นการยืนยันตัวตน"]
A1["Password"]
A2["Public Key"]
A3["Keyboard-Interactive"]
A4["GSSAPI"]
end
subgraph TRANS["SSH Transport Layer
ชั้นการขนส่ง"]
T1["Key Exchange
การแลกเปลี่ยนกุญแจ"]
T2["Server Authentication
การยืนยันเซิร์ฟเวอร์"]
T3["Encryption
การเข้ารหัส"]
T4["Integrity
การตรวจสอบความถูกต้อง"]
end
TCP["TCP Port 22"]
end
CONN --> AUTH --> TRANS --> TCP
style SSH fill:#282828,stroke:#ebdbb2,color:#ebdbb2
style CONN fill:#3c3836,stroke:#b8bb26,color:#ebdbb2
style AUTH fill:#3c3836,stroke:#83a598,color:#ebdbb2
style TRANS fill:#3c3836,stroke:#fabd2f,color:#ebdbb2
style C1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style C2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style C3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style C4 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style A1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style A2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style A3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style A4 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style T1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style T2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style T3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style T4 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style TCP fill:#504945,stroke:#fb4934,color:#ebdbb2
การยืนยันตัวตนด้วย Public Key:
sequenceDiagram
participant C as Client
ไคลเอนต์
participant S as Server
เซิร์ฟเวอร์
Note over C,S: Transport Layer Setup
C->>S: TCP Connection (Port 22)
C->>S: SSH_MSG_KEXINIT
S-->>C: SSH_MSG_KEXINIT
Note over C,S: Key Exchange (e.g., ECDH)
C->>S: SSH_MSG_KEX_ECDH_INIT
S-->>C: SSH_MSG_KEX_ECDH_REPLY + Server's Public Key
C->>S: SSH_MSG_NEWKEYS
S-->>C: SSH_MSG_NEWKEYS
Note over C,S: User Authentication with Public Key
C->>S: SSH_MSG_USERAUTH_REQUEST (publickey)
Note right of C: ส่ง username + algorithm + public key
S-->>C: SSH_MSG_USERAUTH_PK_OK
Note left of S: Server ยืนยันว่า key อยู่ใน authorized_keys
C->>S: SSH_MSG_USERAUTH_REQUEST + Signature
Note right of C: เซ็น session ID ด้วย private key
S-->>C: SSH_MSG_USERAUTH_SUCCESS
Note left of S: ตรวจสอบ signature สำเร็จ
| ประเภท | อัลกอริทึมที่แนะนำ | อัลกอริทึมที่ควรหลีกเลี่ยง |
|---|---|---|
| Key Exchange | curve25519-sha256, ecdh-sha2-nistp256 | diffie-hellman-group1-sha1 |
| Host Key | ssh-ed25519, rsa-sha2-512 | ssh-dss, ssh-rsa (SHA-1) |
| Cipher | chacha20-poly1305, aes256-gcm | 3des-cbc, arcfour |
| MAC | hmac-sha2-512-etm, umac-128-etm | hmac-md5, hmac-sha1 |
"""
โปรแกรมจัดการ SSH Keys
โปรแกรมนี้ช่วยในการสร้าง จัดการ และตรวจสอบ SSH keys
รวมถึงการตั้งค่าการยืนยันตัวตนแบบ Public Key
"""
import subprocess
import os
from pathlib import Path
from typing import Optional, Tuple
class SSHKeyManager:
"""
คลาสสำหรับจัดการ SSH Keys
รองรับการสร้าง key ใหม่, การตรวจสอบ key ที่มีอยู่
และการจัดการ authorized_keys
"""
def __init__(self, ssh_dir: Optional[str] = None):
"""
สร้าง SSHKeyManager
Parameters:
ssh_dir: path ของ .ssh directory (ค่าเริ่มต้น ~/.ssh)
"""
if ssh_dir is None:
self.ssh_dir = Path.home() / ".ssh"
else:
self.ssh_dir = Path(ssh_dir)
# สร้าง directory ถ้ายังไม่มี
self.ssh_dir.mkdir(mode=0o700, exist_ok=True)
def generate_key(self, key_type: str = "ed25519",
key_name: str = "id_ed25519",
comment: str = "",
passphrase: str = "") -> Tuple[Path, Path]:
"""
สร้าง SSH key pair ใหม่
Parameters:
key_type: ประเภทของ key (ed25519, rsa, ecdsa)
key_name: ชื่อไฟล์ของ key
comment: คอมเมนต์ที่แนบไปกับ key
passphrase: รหัสผ่านสำหรับป้องกัน private key
Returns:
Tuple[Path, Path]: (private_key_path, public_key_path)
"""
private_key_path = self.ssh_dir / key_name
public_key_path = self.ssh_dir / f"{key_name}.pub"
# สร้างคำสั่ง ssh-keygen
cmd = [
"ssh-keygen",
"-t", key_type,
"-f", str(private_key_path),
"-N", passphrase, # passphrase (ว่างถ้าไม่ต้องการ)
]
if comment:
cmd.extend(["-C", comment])
# เพิ่ม options ตามประเภท key
if key_type == "rsa":
cmd.extend(["-b", "4096"]) # RSA ควรใช้อย่างน้อย 4096 bits
# รันคำสั่ง
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"[+] สร้าง SSH key สำเร็จ:")
print(f" Private key: {private_key_path}")
print(f" Public key: {public_key_path}")
return (private_key_path, public_key_path)
else:
raise Exception(f"สร้าง key ไม่สำเร็จ: {result.stderr}")
def get_key_fingerprint(self, key_path: Path) -> str:
"""
ดึง fingerprint ของ SSH key
Parameters:
key_path: path ของ key file
Returns:
str: fingerprint ของ key
"""
cmd = ["ssh-keygen", "-l", "-f", str(key_path)]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
return result.stdout.strip()
else:
raise Exception(f"อ่าน fingerprint ไม่สำเร็จ: {result.stderr}")
def add_to_authorized_keys(self, public_key_path: Path,
target_user: str = "",
target_host: str = "") -> bool:
"""
เพิ่ม public key ไปยัง authorized_keys ของ remote server
Parameters:
public_key_path: path ของ public key
target_user: username บน remote server
target_host: hostname หรือ IP ของ remote server
Returns:
bool: สำเร็จหรือไม่
"""
if not target_host:
# เพิ่มในเครื่องตัวเอง
auth_keys_path = self.ssh_dir / "authorized_keys"
with open(public_key_path, 'r') as pub_key:
key_content = pub_key.read().strip()
# ตรวจสอบว่า key มีอยู่แล้วหรือไม่
if auth_keys_path.exists():
with open(auth_keys_path, 'r') as auth_keys:
if key_content in auth_keys.read():
print("[!] Key นี้มีอยู่แล้วใน authorized_keys")
return True
# เพิ่ม key
with open(auth_keys_path, 'a') as auth_keys:
auth_keys.write(f"{key_content}\n")
# ตั้งค่า permission
auth_keys_path.chmod(0o600)
print(f"[+] เพิ่ม key ไปยัง {auth_keys_path} สำเร็จ")
return True
else:
# ใช้ ssh-copy-id สำหรับ remote server
target = f"{target_user}@{target_host}" if target_user else target_host
cmd = ["ssh-copy-id", "-i", str(public_key_path), target]
print(f"[*] กำลังคัดลอก key ไปยัง {target}...")
result = subprocess.run(cmd)
return result.returncode == 0
def list_keys(self) -> list:
"""
แสดงรายการ SSH keys ทั้งหมดใน .ssh directory
Returns:
list: รายการของ key files
"""
keys = []
for file in self.ssh_dir.iterdir():
if file.suffix == '.pub':
private_key = file.with_suffix('')
if private_key.exists():
fingerprint = self.get_key_fingerprint(file)
keys.append({
'name': private_key.name,
'private': private_key,
'public': file,
'fingerprint': fingerprint
})
return keys
# ตัวอย่างการใช้งาน
if __name__ == "__main__":
manager = SSHKeyManager()
print("=" * 60)
print("SSH Key Manager - ตัวอย่างการใช้งาน")
print("=" * 60)
# แสดงรายการ keys ที่มีอยู่
print("\n[*] รายการ SSH Keys ที่มีอยู่:")
existing_keys = manager.list_keys()
for key in existing_keys:
print(f" - {key['name']}: {key['fingerprint']}")
# ตัวอย่างการสร้าง key ใหม่ (comment out เพื่อไม่ให้รันจริง)
"""
# สร้าง ED25519 key (แนะนำ)
priv, pub = manager.generate_key(
key_type="ed25519",
key_name="id_ed25519_new",
comment="user@hostname"
)
# สร้าง RSA key (สำหรับระบบเก่า)
priv, pub = manager.generate_key(
key_type="rsa",
key_name="id_rsa_4096",
comment="legacy-system"
)
"""
print("\n[*] เสร็จสิ้น")
"""
สคริปต์สร้างการตั้งค่า SSH Server ที่ปลอดภัย
สคริปต์นี้สร้างไฟล์ sshd_config ที่มีการตั้งค่าความปลอดภัยที่แนะนำ
สำหรับ OpenSSH Server
"""
def generate_secure_sshd_config(
port: int = 22,
permit_root_login: str = "no",
password_auth: bool = False,
pubkey_auth: bool = True,
allowed_users: list = None,
max_auth_tries: int = 3,
client_alive_interval: int = 300,
client_alive_count_max: int = 2
) -> str:
"""
สร้างการตั้งค่า sshd_config ที่ปลอดภัย
Parameters:
port: พอร์ตที่ใช้งาน
permit_root_login: อนุญาตให้ root login หรือไม่
password_auth: อนุญาตการยืนยันตัวตนด้วยรหัสผ่าน
pubkey_auth: อนุญาตการยืนยันตัวตนด้วย public key
allowed_users: รายชื่อผู้ใช้ที่อนุญาต
max_auth_tries: จำนวนครั้งสูงสุดที่พยายาม login
client_alive_interval: ช่วงเวลาตรวจสอบการเชื่อมต่อ (วินาที)
client_alive_count_max: จำนวนครั้งสูงสุดที่ไม่มีการตอบกลับ
Returns:
str: เนื้อหาของ sshd_config
"""
config = f"""# OpenSSH Server Configuration - Secure Settings
# สร้างโดยอัตโนมัติ - กรุณาตรวจสอบก่อนใช้งาน
# ========================================
# พื้นฐานการเชื่อมต่อ
# ========================================
Port {port}
Protocol 2
AddressFamily any
ListenAddress 0.0.0.0
ListenAddress ::
# ========================================
# การยืนยันตัวตน
# ========================================
PermitRootLogin {permit_root_login}
PubkeyAuthentication {"yes" if pubkey_auth else "no"}
PasswordAuthentication {"yes" if password_auth else "no"}
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes
# จำกัดจำนวนครั้งในการ login
MaxAuthTries {max_auth_tries}
MaxSessions 10
LoginGraceTime 60
# ========================================
# อัลกอริทึมการเข้ารหัส (เฉพาะที่แนะนำ)
# ========================================
# Key Exchange
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256
# Host Key
HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256
# Ciphers
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
# MACs
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
# ========================================
# การตั้งค่าความปลอดภัยเพิ่มเติม
# ========================================
# ปิด features ที่ไม่จำเป็น
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
PermitTunnel no
GatewayPorts no
# ตรวจสอบ permissions
StrictModes yes
# Logging
SyslogFacility AUTH
LogLevel VERBOSE
# ตรวจสอบการเชื่อมต่อ
ClientAliveInterval {client_alive_interval}
ClientAliveCountMax {client_alive_count_max}
TCPKeepAlive yes
# Banner
Banner /etc/ssh/banner
# ========================================
# SFTP
# ========================================
Subsystem sftp /usr/lib/openssh/sftp-server -f AUTH -l INFO
# ========================================
# จำกัดผู้ใช้ (ถ้ากำหนด)
# ========================================
"""
if allowed_users:
config += f"AllowUsers {' '.join(allowed_users)}\n"
config += """
# ========================================
# Match Rules (ตัวอย่าง)
# ========================================
# จำกัด SFTP สำหรับกลุ่ม sftpusers
#Match Group sftpusers
# ChrootDirectory /home/%u
# ForceCommand internal-sftp
# AllowTcpForwarding no
# X11Forwarding no
"""
return config
# ตัวอย่างการใช้งาน
if __name__ == "__main__":
# สร้าง config ที่ปลอดภัย
config = generate_secure_sshd_config(
port=22,
permit_root_login="no",
password_auth=False,
pubkey_auth=True,
allowed_users=["admin", "developer"],
max_auth_tries=3
)
print("=" * 60)
print("Secure SSH Server Configuration")
print("=" * 60)
print(config)
# บันทึกไฟล์ (comment out เพื่อไม่ให้รันจริง)
# with open("/etc/ssh/sshd_config.secure", "w") as f:
# f.write(config)
# print("\n[+] บันทึกไฟล์สำเร็จ")
SCP (Secure Copy Protocol) เป็นโปรโตคอลสำหรับคัดลอกไฟล์ระหว่างเครื่องผ่าน SSH โดยใช้การเข้ารหัสและการยืนยันตัวตนของ SSH
คุณสมบัติหลักของ SCP:
# รูปแบบพื้นฐาน
# scp [options] source destination
# คัดลอกไฟล์จากเครื่องไปยัง remote
scp local_file.txt user@remote:/path/to/destination/
# คัดลอกไฟล์จาก remote มายังเครื่อง
scp user@remote:/path/to/file.txt ./local_directory/
# คัดลอกไดเรกทอรีทั้งหมด (recursive)
scp -r local_directory/ user@remote:/path/to/destination/
# ใช้ port อื่น
scp -P 2222 file.txt user@remote:/path/
# ใช้ identity file (private key)
scp -i ~/.ssh/id_ed25519 file.txt user@remote:/path/
# คัดลอกระหว่าง remote servers
scp user1@host1:/file.txt user2@host2:/destination/
| คุณสมบัติ | SCP | SFTP |
|---|---|---|
| การใช้งาน | Non-interactive, command-line | Interactive หรือ automated |
| การทำงาน | คัดลอกไฟล์เท่านั้น | จัดการไฟล์ครบวงจร |
| Resume transfer | ไม่รองรับ | รองรับ |
| Progress | แสดงความคืบหน้า | รองรับ verbose mode |
| Protocol | RCP over SSH | SSH Subsystem |
| ความเร็ว | เร็วกว่าเล็กน้อย | ช้ากว่าเล็กน้อย (overhead) |
"""
โปรแกรมจัดการการถ่ายโอนไฟล์ด้วย SCP/SFTP
โปรแกรมนี้แสดงวิธีการใช้ Python ในการถ่ายโอนไฟล์
ผ่าน SCP และ SFTP โดยใช้ paramiko library
"""
import paramiko
from scp import SCPClient
from pathlib import Path
from typing import Optional, Callable
import os
class SecureFileTransfer:
"""
คลาสสำหรับถ่ายโอนไฟล์อย่างปลอดภัยผ่าน SSH
รองรับทั้ง SCP และ SFTP
"""
def __init__(self, hostname: str, username: str,
port: int = 22,
private_key_path: Optional[str] = None,
password: Optional[str] = None):
"""
สร้างการเชื่อมต่อ SSH
Parameters:
hostname: ชื่อโฮสต์หรือ IP address
username: ชื่อผู้ใช้
port: พอร์ต SSH (ค่าเริ่มต้น 22)
private_key_path: path ของ private key
password: รหัสผ่าน (ถ้าไม่ใช้ key)
"""
self.hostname = hostname
self.username = username
self.port = port
# สร้าง SSH client
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# เชื่อมต่อ
connect_kwargs = {
'hostname': hostname,
'port': port,
'username': username
}
if private_key_path:
# ใช้ private key
key = paramiko.Ed25519Key.from_private_key_file(private_key_path)
connect_kwargs['pkey'] = key
elif password:
# ใช้รหัสผ่าน
connect_kwargs['password'] = password
self.ssh.connect(**connect_kwargs)
print(f"[+] เชื่อมต่อ SSH สำเร็จ: {username}@{hostname}:{port}")
def scp_upload(self, local_path: str, remote_path: str,
progress_callback: Optional[Callable] = None):
"""
อัปโหลดไฟล์ด้วย SCP
Parameters:
local_path: path ของไฟล์ในเครื่อง
remote_path: path ปลายทางบน remote server
progress_callback: callback function สำหรับแสดงความคืบหน้า
"""
def default_progress(filename, size, sent):
percent = (sent / size) * 100
print(f"\r[SCP] {filename}: {percent:.1f}%", end='', flush=True)
callback = progress_callback or default_progress
with SCPClient(self.ssh.get_transport(), progress=callback) as scp:
scp.put(local_path, remote_path)
print(f"\n[+] SCP อัปโหลดสำเร็จ: {local_path} -> {remote_path}")
def scp_download(self, remote_path: str, local_path: str,
progress_callback: Optional[Callable] = None):
"""
ดาวน์โหลดไฟล์ด้วย SCP
Parameters:
remote_path: path ของไฟล์บน remote server
local_path: path ปลายทางในเครื่อง
progress_callback: callback function สำหรับแสดงความคืบหน้า
"""
def default_progress(filename, size, received):
percent = (received / size) * 100
print(f"\r[SCP] {filename}: {percent:.1f}%", end='', flush=True)
callback = progress_callback or default_progress
with SCPClient(self.ssh.get_transport(), progress=callback) as scp:
scp.get(remote_path, local_path)
print(f"\n[+] SCP ดาวน์โหลดสำเร็จ: {remote_path} -> {local_path}")
def sftp_upload(self, local_path: str, remote_path: str):
"""
อัปโหลดไฟล์ด้วย SFTP
Parameters:
local_path: path ของไฟล์ในเครื่อง
remote_path: path ปลายทางบน remote server
"""
sftp = self.ssh.open_sftp()
try:
# ตรวจสอบว่า local_path เป็นไดเรกทอรีหรือไม่
if os.path.isdir(local_path):
self._sftp_upload_directory(sftp, local_path, remote_path)
else:
sftp.put(local_path, remote_path)
print(f"[+] SFTP อัปโหลดสำเร็จ: {local_path} -> {remote_path}")
finally:
sftp.close()
def _sftp_upload_directory(self, sftp, local_dir: str, remote_dir: str):
"""
อัปโหลดไดเรกทอรีทั้งหมดด้วย SFTP (recursive)
Parameters:
sftp: SFTP client object
local_dir: path ของไดเรกทอรีในเครื่อง
remote_dir: path ปลายทางบน remote server
"""
# สร้างไดเรกทอรี remote ถ้ายังไม่มี
try:
sftp.mkdir(remote_dir)
except IOError:
pass # มีอยู่แล้ว
for item in os.listdir(local_dir):
local_path = os.path.join(local_dir, item)
remote_path = f"{remote_dir}/{item}"
if os.path.isdir(local_path):
self._sftp_upload_directory(sftp, local_path, remote_path)
else:
sftp.put(local_path, remote_path)
print(f" [+] {local_path} -> {remote_path}")
def sftp_download(self, remote_path: str, local_path: str):
"""
ดาวน์โหลดไฟล์ด้วย SFTP
Parameters:
remote_path: path ของไฟล์บน remote server
local_path: path ปลายทางในเครื่อง
"""
sftp = self.ssh.open_sftp()
try:
sftp.get(remote_path, local_path)
print(f"[+] SFTP ดาวน์โหลดสำเร็จ: {remote_path} -> {local_path}")
finally:
sftp.close()
def sftp_list_directory(self, remote_path: str = '.') -> list:
"""
แสดงรายการไฟล์ใน remote directory
Parameters:
remote_path: path ของไดเรกทอรีที่ต้องการดู
Returns:
list: รายการของไฟล์และไดเรกทอรี
"""
sftp = self.ssh.open_sftp()
try:
items = []
for entry in sftp.listdir_attr(remote_path):
items.append({
'name': entry.filename,
'size': entry.st_size,
'mode': oct(entry.st_mode)[-3:],
'is_dir': entry.st_mode & 0o40000 != 0
})
return items
finally:
sftp.close()
def close(self):
"""ปิดการเชื่อมต่อ SSH"""
self.ssh.close()
print(f"[-] ปิดการเชื่อมต่อ SSH: {self.hostname}")
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
# ตัวอย่างการใช้งาน
if __name__ == "__main__":
print("=" * 60)
print("Secure File Transfer - ตัวอย่างการใช้งาน")
print("=" * 60)
# ตัวอย่างการใช้งาน (ต้องเปลี่ยนค่าตามเซิร์ฟเวอร์จริง)
"""
with SecureFileTransfer(
hostname="192.168.1.100",
username="admin",
private_key_path="~/.ssh/id_ed25519"
) as transfer:
# SCP Upload
transfer.scp_upload("local_file.txt", "/home/admin/file.txt")
# SCP Download
transfer.scp_download("/home/admin/file.txt", "downloaded.txt")
# SFTP Upload directory
transfer.sftp_upload("./local_dir", "/home/admin/remote_dir")
# List remote directory
files = transfer.sftp_list_directory("/home/admin")
for f in files:
print(f" {'[D]' if f['is_dir'] else '[F]'} {f['name']} ({f['size']} bytes)")
"""
print("\nดูตัวอย่างโค้ดในไฟล์สำหรับการใช้งานจริง")
# ========================================
# การเชื่อมต่อพื้นฐาน
# ========================================
# เชื่อมต่อ SSH ปกติ
ssh user@hostname
# ระบุ port
ssh -p 2222 user@hostname
# ใช้ private key ที่ระบุ
ssh -i ~/.ssh/id_ed25519 user@hostname
# เปิด verbose mode เพื่อ debug
ssh -v user@hostname # -v, -vv, -vvv
# ========================================
# การจัดการ SSH Keys
# ========================================
# สร้าง ED25519 key (แนะนำ)
ssh-keygen -t ed25519 -C "comment"
# สร้าง RSA 4096-bit key
ssh-keygen -t rsa -b 4096 -C "comment"
# ดู fingerprint ของ key
ssh-keygen -l -f ~/.ssh/id_ed25519.pub
# คัดลอก public key ไป remote server
ssh-copy-id user@hostname
# ========================================
# SSH Agent
# ========================================
# เริ่ม ssh-agent
eval $(ssh-agent -s)
# เพิ่ม key เข้า agent
ssh-add ~/.ssh/id_ed25519
# แสดง keys ใน agent
ssh-add -l
# ลบ keys ออกจาก agent
ssh-add -D
# ========================================
# Port Forwarding
# ========================================
# Local port forwarding
# เข้าถึง remote:3306 ผ่าน localhost:13306
ssh -L 13306:localhost:3306 user@hostname
# Remote port forwarding
# เปิด port 8080 บน remote ให้เข้าถึง localhost:80
ssh -R 8080:localhost:80 user@hostname
# Dynamic port forwarding (SOCKS proxy)
ssh -D 1080 user@hostname
# ========================================
# การใช้งานขั้นสูง
# ========================================
# ProxyJump (เข้าผ่าน bastion host)
ssh -J jump@bastion user@internal
# Agent forwarding (ใช้ key บน remote)
ssh -A user@hostname
# รันคำสั่งบน remote
ssh user@hostname "ls -la /var/log"
# รันหลายคำสั่ง
ssh user@hostname "cd /var/log && tail -n 100 syslog"
# ========================================
# SCP Commands
# ========================================
# อัปโหลดไฟล์
scp local.txt user@host:/path/
# ดาวน์โหลดไฟล์
scp user@host:/path/remote.txt ./
# คัดลอก directory (recursive)
scp -r local_dir/ user@host:/path/
# ใช้ compression
scp -C large_file.tar user@host:/path/
# จำกัด bandwidth (KB/s)
scp -l 1024 file.txt user@host:/path/
# ========================================
# SFTP Commands
# ========================================
# เชื่อมต่อ SFTP
sftp user@hostname
# คำสั่งใน SFTP session
sftp> pwd # แสดง remote directory
sftp> lpwd # แสดง local directory
sftp> ls # list remote
sftp> lls # list local
sftp> cd /path # change remote dir
sftp> lcd /path # change local dir
sftp> get file.txt # download
sftp> put file.txt # upload
sftp> mkdir dir # create directory
sftp> rm file.txt # delete file
sftp> bye # disconnect
# Batch mode
sftp -b commands.txt user@hostname
SSHFS (SSH Filesystem) เป็นระบบไฟล์แบบ client-based ที่ช่วยให้สามารถ mount ไดเรกทอรีจาก remote server มาใช้งานบนเครื่อง local เสมือนเป็นไดเรกทอรีในเครื่องตัวเอง โดยใช้ SSH เป็น transport layer
คุณสมบัติหลักของ SSHFS:
flowchart TB
subgraph CLIENT["Local Machine เครื่อง Local"]
APP["Application
แอปพลิเคชัน"]
VFS["VFS (Virtual File System)
ระบบไฟล์เสมือน"]
FUSE["FUSE Module
โมดูล FUSE"]
SSHFS["SSHFS Client
ไคลเอนต์ SSHFS"]
SSHC["SSH Client
ไคลเอนต์ SSH"]
end
subgraph SERVER["Remote Server เซิร์ฟเวอร์"]
SSHS["SSH Server
เซิร์ฟเวอร์ SSH"]
SFTP["SFTP Subsystem
ระบบย่อย SFTP"]
FS["File System
ระบบไฟล์จริง"]
end
APP -->|"read/write"| VFS
VFS -->|"FUSE calls"| FUSE
FUSE -->|"SFTP requests"| SSHFS
SSHFS --> SSHC
SSHC <-->|"SSH Encrypted
Port 22"| SSHS
SSHS --> SFTP
SFTP --> FS
style CLIENT fill:#3c3836,stroke:#83a598,color:#ebdbb2
style SERVER fill:#3c3836,stroke:#b8bb26,color:#ebdbb2
style APP fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style VFS fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style FUSE fill:#504945,stroke:#fabd2f,color:#ebdbb2
style SSHFS fill:#504945,stroke:#83a598,color:#ebdbb2
style SSHC fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style SSHS fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style SFTP fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style FS fill:#504945,stroke:#b8bb26,color:#ebdbb2
ขั้นตอนการทำงาน:
# ========================================
# การติดตั้ง SSHFS
# ========================================
# Ubuntu/Debian
sudo apt update
sudo apt install sshfs
# Fedora/RHEL/CentOS
sudo dnf install fuse-sshfs
# Arch Linux
sudo pacman -S sshfs
# macOS (ต้องติดตั้ง macFUSE ก่อน)
brew install macfuse
brew install sshfs
# ตรวจสอบการติดตั้ง
sshfs --version
# ========================================
# การเตรียม Mount Point
# ========================================
# สร้าง directory สำหรับ mount
mkdir -p ~/mnt/remote_server
# ตรวจสอบว่า user อยู่ใน group fuse (บาง distro)
groups $USER
# ถ้าไม่มี ให้เพิ่ม
sudo usermod -aG fuse $USER
# แล้ว logout/login ใหม่
# ========================================
# การ Mount พื้นฐาน
# ========================================
# รูปแบบพื้นฐาน
sshfs [user@]host:[remote_path] mountpoint [options]
# Mount home directory ของ remote user
sshfs user@192.168.1.100: ~/mnt/remote
# Mount directory ที่ระบุ
sshfs user@server:/var/www ~/mnt/webserver
# Mount ด้วย port ที่กำหนด
sshfs -p 2222 user@server:/data ~/mnt/data
# ========================================
# Options ที่สำคัญ
# ========================================
# -o IdentityFile: ระบุ private key
sshfs -o IdentityFile=~/.ssh/id_ed25519 user@server:/path ~/mnt/remote
# -o reconnect: เชื่อมต่อใหม่อัตโนมัติเมื่อขาดการเชื่อมต่อ
sshfs -o reconnect user@server:/path ~/mnt/remote
# -o ServerAliveInterval: ส่ง keepalive ทุก N วินาที
sshfs -o ServerAliveInterval=15 user@server:/path ~/mnt/remote
# -o ServerAliveCountMax: จำนวนครั้งที่ไม่มีการตอบกลับก่อนตัดการเชื่อมต่อ
sshfs -o ServerAliveCountMax=3 user@server:/path ~/mnt/remote
# -o Compression=yes: เปิดการบีบอัดข้อมูล (ดีสำหรับ slow connection)
sshfs -o Compression=yes user@server:/path ~/mnt/remote
# -o Ciphers: ระบุ cipher (เลือก cipher ที่เร็วกว่า)
sshfs -o Ciphers=aes128-gcm@openssh.com user@server:/path ~/mnt/remote
# -o cache=yes: เปิด caching เพื่อเพิ่มประสิทธิภาพ
sshfs -o cache=yes user@server:/path ~/mnt/remote
# -o kernel_cache: ใช้ kernel caching
sshfs -o kernel_cache user@server:/path ~/mnt/remote
# -o auto_cache: automatic cache invalidation
sshfs -o auto_cache user@server:/path ~/mnt/remote
# ========================================
# Options สำหรับ Permission และ Ownership
# ========================================
# -o allow_other: อนุญาตให้ users อื่นเข้าถึง (ต้องตั้งค่าใน /etc/fuse.conf)
sshfs -o allow_other user@server:/path ~/mnt/remote
# -o default_permissions: ใช้ permission checking ของ kernel
sshfs -o default_permissions user@server:/path ~/mnt/remote
# -o uid, gid: กำหนด owner ของไฟล์ที่ mount
sshfs -o uid=$(id -u),gid=$(id -g) user@server:/path ~/mnt/remote
# -o umask: กำหนด umask สำหรับไฟล์
sshfs -o umask=0022 user@server:/path ~/mnt/remote
# ========================================
# การ Unmount
# ========================================
# วิธีที่ 1: fusermount (แนะนำ)
fusermount -u ~/mnt/remote
# วิธีที่ 2: umount
umount ~/mnt/remote
# Force unmount (กรณี busy)
fusermount -uz ~/mnt/remote
# หรือ
sudo umount -l ~/mnt/remote
# ========================================
# การ Mount แบบ Production-Ready
# ========================================
# Full options สำหรับการใช้งานจริง
sshfs user@server:/data ~/mnt/data \
-o IdentityFile=~/.ssh/id_ed25519 \
-o reconnect \
-o ServerAliveInterval=15 \
-o ServerAliveCountMax=3 \
-o Compression=no \
-o Ciphers=chacha20-poly1305@openssh.com \
-o cache=yes \
-o kernel_cache \
-o auto_cache \
-o uid=$(id -u) \
-o gid=$(id -g) \
-o idmap=user \
-o follow_symlinks \
-o transform_symlinks
# ========================================
# การตั้งค่า Auto-Mount ด้วย /etc/fstab
# ========================================
# เพิ่มบรรทัดนี้ใน /etc/fstab
# user@server:/remote/path /local/mountpoint fuse.sshfs options 0 0
# ตัวอย่าง:
# admin@192.168.1.100:/var/www /mnt/webserver fuse.sshfs \
# IdentityFile=/home/user/.ssh/id_ed25519,\
# allow_other,\
# reconnect,\
# ServerAliveInterval=15,\
# _netdev,\
# users,\
# idmap=user 0 0
# _netdev: รอ network ก่อน mount
# users: อนุญาตให้ user ทั่วไป mount/unmount
# Mount ทุก entry ใน fstab
sudo mount -a
# แก้ไข /etc/fuse.conf เพื่อเปิดใช้งาน allow_other
sudo nano /etc/fuse.conf
# เพิ่มหรือ uncomment บรรทัดนี้:
user_allow_other
# บันทึกและออก
"""
โปรแกรมจัดการ SSHFS Mount Points
โปรแกรมนี้ช่วยในการ mount, unmount และจัดการ
SSHFS connections อย่างมีประสิทธิภาพ
"""
import subprocess
import os
from pathlib import Path
from typing import Optional, List, Dict
from dataclasses import dataclass
import json
@dataclass
class SSHFSMount:
"""
คลาสเก็บข้อมูลการ mount SSHFS
Attributes:
name: ชื่อเรียกสำหรับ mount point นี้
user: ชื่อผู้ใช้บน remote server
host: hostname หรือ IP address
remote_path: path บน remote server
local_path: path สำหรับ mount บนเครื่อง local
port: SSH port (ค่าเริ่มต้น 22)
identity_file: path ของ private key
options: options เพิ่มเติม
"""
name: str
user: str
host: str
remote_path: str
local_path: str
port: int = 22
identity_file: Optional[str] = None
options: Optional[List[str]] = None
class SSHFSManager:
"""
คลาสจัดการ SSHFS Mount Points
รองรับการ mount, unmount, ตรวจสอบสถานะ
และบันทึกการตั้งค่า
"""
def __init__(self, config_file: Optional[str] = None):
"""
สร้าง SSHFSManager
Parameters:
config_file: path ของไฟล์ config (JSON)
"""
self.config_file = config_file or os.path.expanduser("~/.sshfs_mounts.json")
self.mounts: Dict[str, SSHFSMount] = {}
self._load_config()
def _load_config(self):
"""โหลดการตั้งค่าจากไฟล์"""
if os.path.exists(self.config_file):
try:
with open(self.config_file, 'r') as f:
data = json.load(f)
for name, mount_data in data.items():
self.mounts[name] = SSHFSMount(**mount_data)
print(f"[+] โหลดการตั้งค่าจาก {self.config_file}")
except Exception as e:
print(f"[!] ไม่สามารถโหลดการตั้งค่า: {e}")
def _save_config(self):
"""บันทึกการตั้งค่าลงไฟล์"""
try:
data = {}
for name, mount in self.mounts.items():
data[name] = {
'name': mount.name,
'user': mount.user,
'host': mount.host,
'remote_path': mount.remote_path,
'local_path': mount.local_path,
'port': mount.port,
'identity_file': mount.identity_file,
'options': mount.options
}
with open(self.config_file, 'w') as f:
json.dump(data, f, indent=2)
print(f"[+] บันทึกการตั้งค่าไปยัง {self.config_file}")
except Exception as e:
print(f"[!] ไม่สามารถบันทึกการตั้งค่า: {e}")
def add_mount(self, mount: SSHFSMount) -> bool:
"""
เพิ่มการตั้งค่า mount point ใหม่
Parameters:
mount: ข้อมูลการ mount
Returns:
bool: สำเร็จหรือไม่
"""
if mount.name in self.mounts:
print(f"[!] Mount '{mount.name}' มีอยู่แล้ว")
return False
self.mounts[mount.name] = mount
self._save_config()
print(f"[+] เพิ่ม mount '{mount.name}' สำเร็จ")
return True
def remove_mount(self, name: str) -> bool:
"""
ลบการตั้งค่า mount point
Parameters:
name: ชื่อของ mount point
Returns:
bool: สำเร็จหรือไม่
"""
if name not in self.mounts:
print(f"[!] ไม่พบ mount '{name}'")
return False
# Unmount ก่อนถ้ายัง mount อยู่
if self.is_mounted(name):
self.unmount(name)
del self.mounts[name]
self._save_config()
print(f"[+] ลบ mount '{name}' สำเร็จ")
return True
def mount(self, name: str) -> bool:
"""
Mount filesystem
Parameters:
name: ชื่อของ mount point
Returns:
bool: สำเร็จหรือไม่
"""
if name not in self.mounts:
print(f"[!] ไม่พบ mount '{name}'")
return False
mount = self.mounts[name]
# ตรวจสอบว่า mount อยู่แล้วหรือไม่
if self.is_mounted(name):
print(f"[!] '{name}' ถูก mount อยู่แล้ว")
return True
# สร้าง mount point directory ถ้ายังไม่มี
local_path = Path(mount.local_path).expanduser()
local_path.mkdir(parents=True, exist_ok=True)
# สร้างคำสั่ง sshfs
cmd = ["sshfs"]
# เพิ่ม port ถ้าไม่ใช่ 22
if mount.port != 22:
cmd.extend(["-p", str(mount.port)])
# สร้าง remote path
remote = f"{mount.user}@{mount.host}:{mount.remote_path}"
cmd.append(remote)
cmd.append(str(local_path))
# เพิ่ม options
default_options = [
"reconnect",
"ServerAliveInterval=15",
"ServerAliveCountMax=3"
]
if mount.identity_file:
identity_path = os.path.expanduser(mount.identity_file)
default_options.append(f"IdentityFile={identity_path}")
all_options = default_options + (mount.options or [])
for opt in all_options:
cmd.extend(["-o", opt])
# รันคำสั่ง
print(f"[*] กำลัง mount '{name}'...")
print(f" Command: {' '.join(cmd)}")
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode == 0:
print(f"[+] Mount '{name}' สำเร็จ")
print(f" Remote: {remote}")
print(f" Local: {local_path}")
return True
else:
print(f"[!] Mount ไม่สำเร็จ: {result.stderr}")
return False
except subprocess.TimeoutExpired:
print(f"[!] Timeout: ไม่สามารถเชื่อมต่อได้")
return False
except Exception as e:
print(f"[!] Error: {e}")
return False
def unmount(self, name: str) -> bool:
"""
Unmount filesystem
Parameters:
name: ชื่อของ mount point
Returns:
bool: สำเร็จหรือไม่
"""
if name not in self.mounts:
print(f"[!] ไม่พบ mount '{name}'")
return False
mount = self.mounts[name]
local_path = Path(mount.local_path).expanduser()
if not self.is_mounted(name):
print(f"[!] '{name}' ไม่ได้ถูก mount อยู่")
return True
print(f"[*] กำลัง unmount '{name}'...")
try:
# ลอง fusermount ก่อน
result = subprocess.run(
["fusermount", "-u", str(local_path)],
capture_output=True, text=True
)
if result.returncode == 0:
print(f"[+] Unmount '{name}' สำเร็จ")
return True
# ถ้าไม่สำเร็จ ลอง lazy unmount
print(f"[!] fusermount ไม่สำเร็จ กำลังลอง lazy unmount...")
result = subprocess.run(
["fusermount", "-uz", str(local_path)],
capture_output=True, text=True
)
if result.returncode == 0:
print(f"[+] Lazy unmount '{name}' สำเร็จ")
return True
else:
print(f"[!] Unmount ไม่สำเร็จ: {result.stderr}")
return False
except Exception as e:
print(f"[!] Error: {e}")
return False
def is_mounted(self, name: str) -> bool:
"""
ตรวจสอบว่า mount point ถูก mount อยู่หรือไม่
Parameters:
name: ชื่อของ mount point
Returns:
bool: mounted หรือไม่
"""
if name not in self.mounts:
return False
mount = self.mounts[name]
local_path = str(Path(mount.local_path).expanduser())
# ตรวจสอบจาก /proc/mounts
try:
with open('/proc/mounts', 'r') as f:
for line in f:
parts = line.split()
if len(parts) >= 2:
mount_point = parts[1]
mount_type = parts[2] if len(parts) > 2 else ""
if mount_point == local_path and "fuse" in mount_type:
return True
except:
pass
return False
def status(self) -> List[Dict]:
"""
แสดงสถานะของทุก mount points
Returns:
List[Dict]: รายการสถานะ
"""
status_list = []
for name, mount in self.mounts.items():
mounted = self.is_mounted(name)
status_list.append({
'name': name,
'user': mount.user,
'host': mount.host,
'remote_path': mount.remote_path,
'local_path': mount.local_path,
'mounted': mounted,
'status': '🟢 Mounted' if mounted else '🔴 Not Mounted'
})
return status_list
def mount_all(self):
"""Mount ทุก mount points"""
print("[*] กำลัง mount ทุก mount points...")
for name in self.mounts:
self.mount(name)
def unmount_all(self):
"""Unmount ทุก mount points"""
print("[*] กำลัง unmount ทุก mount points...")
for name in self.mounts:
self.unmount(name)
def print_status_table(status_list: List[Dict]):
"""
แสดงตารางสถานะ
Parameters:
status_list: รายการสถานะจาก SSHFSManager.status()
"""
if not status_list:
print("ไม่มี mount points ที่บันทึกไว้")
return
# หา column widths
name_width = max(len(s['name']) for s in status_list)
host_width = max(len(f"{s['user']}@{s['host']}") for s in status_list)
remote_width = max(len(s['remote_path']) for s in status_list)
local_width = max(len(s['local_path']) for s in status_list)
# Header
print("\n" + "=" * 80)
print(f"{'Name':<{name_width}} | {'Host':<{host_width}} | {'Remote':<{remote_width}} | Status")
print("-" * 80)
# Rows
for s in status_list:
host = f"{s['user']}@{s['host']}"
print(f"{s['name']:<{name_width}} | {host:<{host_width}} | {s['remote_path']:<{remote_width}} | {s['status']}")
print("=" * 80 + "\n")
# ตัวอย่างการใช้งาน
if __name__ == "__main__":
print("=" * 60)
print("SSHFS Manager - ตัวอย่างการใช้งาน")
print("=" * 60)
# สร้าง manager
manager = SSHFSManager()
# ตัวอย่างการเพิ่ม mount point
"""
# เพิ่ม mount point ใหม่
web_server = SSHFSMount(
name="webserver",
user="admin",
host="192.168.1.100",
remote_path="/var/www/html",
local_path="~/mnt/webserver",
port=22,
identity_file="~/.ssh/id_ed25519",
options=["cache=yes", "kernel_cache"]
)
manager.add_mount(web_server)
# เพิ่ม mount point อีกตัว
backup_server = SSHFSMount(
name="backup",
user="backup",
host="192.168.1.200",
remote_path="/backup/daily",
local_path="~/mnt/backup",
identity_file="~/.ssh/id_ed25519"
)
manager.add_mount(backup_server)
# Mount
manager.mount("webserver")
# ตรวจสอบสถานะ
status = manager.status()
print_status_table(status)
# Unmount
manager.unmount("webserver")
"""
# แสดงสถานะปัจจุบัน
status = manager.status()
print_status_table(status)
print("\nดูตัวอย่างโค้ดในไฟล์สำหรับการใช้งานจริง")
ปัจจัยที่ส่งผลต่อประสิทธิภาพ:
| ปัจจัย | ผลกระทบ | แนวทางแก้ไข |
|---|---|---|
| Latency | ช้าลงมากสำหรับ small files | ใช้ caching, batch operations |
| Encryption overhead | CPU usage สูงขึ้น | เลือก cipher ที่เร็ว |
| No local caching (default) | อ่านซ้ำไฟล์เดิมช้า | เปิด cache options |
| Small read-ahead | Sequential read ช้า | เพิ่ม read-ahead buffer |
Options สำหรับเพิ่มประสิทธิภาพ:
# ========================================
# Performance Optimization Options
# ========================================
# การตั้งค่าสำหรับประสิทธิภาพสูงสุด
sshfs user@server:/path ~/mnt/remote \
-o Ciphers=aes128-gcm@openssh.com \
-o Compression=no \
-o cache=yes \
-o kernel_cache \
-o auto_cache \
-o large_read \
-o big_writes \
-o max_conns=10 \
-o no_readahead
# คำอธิบาย:
# Ciphers=aes128-gcm : cipher ที่เร็ว (มี hardware acceleration)
# Compression=no : ไม่บีบอัด (ดีสำหรับ LAN เร็ว)
# cache=yes : เปิด caching
# kernel_cache : ใช้ kernel page cache
# auto_cache : invalidate cache อัตโนมัติเมื่อไฟล์เปลี่ยน
# large_read : ใช้ read buffer ขนาดใหญ่
# big_writes : อนุญาต write ขนาดใหญ่กว่า 4KB
# max_conns : จำนวน SSH connections (parallel transfers)
# ========================================
# การตั้งค่าสำหรับ WAN / High Latency
# ========================================
# สำหรับการเชื่อมต่อผ่าน Internet
sshfs user@server:/path ~/mnt/remote \
-o Compression=yes \
-o Ciphers=chacha20-poly1305@openssh.com \
-o cache=yes \
-o kernel_cache \
-o auto_cache \
-o reconnect \
-o ServerAliveInterval=15 \
-o ServerAliveCountMax=3 \
-o TCPKeepAlive=yes
# คำอธิบาย:
# Compression=yes : บีบอัดข้อมูล (ดีสำหรับ slow connection)
# chacha20-poly1305 : cipher ที่เร็วบน CPU ที่ไม่มี AES-NI
# reconnect : เชื่อมต่อใหม่อัตโนมัติ
# ServerAliveInterval: ส่ง keepalive ทุก 15 วินาที
คำอธิบายตัวแปร:
"""
โปรแกรมคำนวณและทดสอบประสิทธิภาพ SSHFS
โปรแกรมนี้ช่วยประมาณและทดสอบประสิทธิภาพของ SSHFS
ในสภาพแวดล้อมต่างๆ
"""
import time
import os
import tempfile
from typing import Dict, Tuple
import subprocess
def calculate_transfer_time(file_size_mb: float,
bandwidth_mbps: float,
latency_ms: float,
overhead_percent: float = 15) -> Dict:
"""
คำนวณเวลาในการถ่ายโอนไฟล์ผ่าน SSHFS
Parameters:
file_size_mb: ขนาดไฟล์เป็น MB
bandwidth_mbps: แบนด์วิดท์เป็น Mbps
latency_ms: latency เป็น milliseconds (one-way)
overhead_percent: overhead จาก encryption และ protocol
Returns:
Dict: ผลการคำนวณ
"""
# แปลงหน่วย
file_size_bytes = file_size_mb * 1024 * 1024
bandwidth_bps = (bandwidth_mbps * 1_000_000) / 8 # bytes per second
rtt_seconds = (latency_ms * 2) / 1000 # round-trip time
# คำนวณ effective bandwidth
effective_bandwidth = bandwidth_bps * (1 - overhead_percent/100)
# ประมาณจำนวน round-trips (SFTP ต้องการ acknowledgment)
# สมมติว่าใช้ block size 64KB
block_size = 64 * 1024
num_blocks = file_size_bytes / block_size
# เวลาในการถ่ายโอน
transfer_time = file_size_bytes / effective_bandwidth
# เวลาจาก latency (ประมาณ 1 RTT ต่อ 10 blocks)
latency_time = (num_blocks / 10) * rtt_seconds
total_time = transfer_time + latency_time
# คำนวณ throughput จริง
actual_throughput_mbps = (file_size_mb * 8) / total_time
return {
'file_size_mb': file_size_mb,
'bandwidth_mbps': bandwidth_mbps,
'latency_ms': latency_ms,
'overhead_percent': overhead_percent,
'effective_bandwidth_mbps': (effective_bandwidth * 8) / 1_000_000,
'transfer_time_sec': round(transfer_time, 2),
'latency_overhead_sec': round(latency_time, 2),
'total_time_sec': round(total_time, 2),
'actual_throughput_mbps': round(actual_throughput_mbps, 2),
'efficiency_percent': round((actual_throughput_mbps / bandwidth_mbps) * 100, 1)
}
def benchmark_sshfs(mount_path: str, file_sizes_mb: list = [1, 10, 100]) -> list:
"""
ทดสอบประสิทธิภาพ SSHFS ด้วยการเขียนและอ่านไฟล์จริง
Parameters:
mount_path: path ของ SSHFS mount point
file_sizes_mb: ขนาดไฟล์ที่จะทดสอบ
Returns:
list: ผลการทดสอบ
"""
results = []
if not os.path.ismount(mount_path):
print(f"[!] {mount_path} ไม่ใช่ mount point")
return results
for size_mb in file_sizes_mb:
print(f"\n[*] ทดสอบไฟล์ขนาด {size_mb} MB...")
# สร้างข้อมูลทดสอบ
data = os.urandom(size_mb * 1024 * 1024)
test_file = os.path.join(mount_path, f"benchmark_{size_mb}mb.tmp")
# ทดสอบเขียน
start_time = time.time()
with open(test_file, 'wb') as f:
f.write(data)
f.flush()
os.fsync(f.fileno())
write_time = time.time() - start_time
write_speed = size_mb / write_time
# ทดสอบอ่าน
start_time = time.time()
with open(test_file, 'rb') as f:
read_data = f.read()
read_time = time.time() - start_time
read_speed = size_mb / read_time
# ลบไฟล์ทดสอบ
os.remove(test_file)
result = {
'size_mb': size_mb,
'write_time_sec': round(write_time, 2),
'write_speed_mbps': round(write_speed * 8, 2),
'read_time_sec': round(read_time, 2),
'read_speed_mbps': round(read_speed * 8, 2)
}
results.append(result)
print(f" Write: {result['write_speed_mbps']} Mbps ({write_time:.2f}s)")
print(f" Read: {result['read_speed_mbps']} Mbps ({read_time:.2f}s)")
return results
# ตัวอย่างการใช้งาน
if __name__ == "__main__":
print("=" * 60)
print("SSHFS Performance Calculator")
print("=" * 60)
# ทดสอบการคำนวณสำหรับสถานการณ์ต่างๆ
scenarios = [
{"name": "LAN (Gigabit)", "bw": 1000, "latency": 0.5},
{"name": "WAN (100Mbps)", "bw": 100, "latency": 20},
{"name": "VPN (50Mbps)", "bw": 50, "latency": 50},
{"name": "International (25Mbps)", "bw": 25, "latency": 150},
]
file_size = 100 # MB
print(f"\nการถ่ายโอนไฟล์ขนาด {file_size} MB:")
print("-" * 60)
for scenario in scenarios:
result = calculate_transfer_time(
file_size_mb=file_size,
bandwidth_mbps=scenario['bw'],
latency_ms=scenario['latency']
)
print(f"\n{scenario['name']}:")
print(f" Bandwidth: {scenario['bw']} Mbps, Latency: {scenario['latency']} ms")
print(f" เวลาถ่ายโอน: {result['total_time_sec']} วินาที")
print(f" Throughput จริง: {result['actual_throughput_mbps']} Mbps")
print(f" ประสิทธิภาพ: {result['efficiency_percent']}%")
# Benchmark จริง (uncomment เพื่อใช้งาน)
"""
print("\n" + "=" * 60)
print("Benchmark ด้วยการถ่ายโอนจริง")
print("=" * 60)
mount_point = os.path.expanduser("~/mnt/remote")
if os.path.ismount(mount_point):
results = benchmark_sshfs(mount_point, [1, 10, 50])
else:
print(f"[!] กรุณา mount SSHFS ที่ {mount_point} ก่อน")
"""
| ปัญหา | สาเหตุ | วิธีแก้ไข |
|---|---|---|
| "Transport endpoint is not connected" | การเชื่อมต่อขาดหาย | fusermount -uz แล้ว mount ใหม่ |
| "Permission denied" | SSH key ไม่ถูกต้อง | ตรวจสอบ key และ authorized_keys |
| "Host key verification failed" | Host key เปลี่ยน | ลบ entry ใน known_hosts |
| Mount ช้ามาก | Latency สูง หรือ no caching | เพิ่ม cache options |
| "fuse: device not found" | FUSE module ไม่ถูก load | sudo modprobe fuse |
| Cannot access as another user | ไม่ได้ตั้งค่า allow_other | แก้ไข /etc/fuse.conf |
# ========================================
# การแก้ไขปัญหาที่พบบ่อย
# ========================================
# ปัญหา: Transport endpoint is not connected
fusermount -uz ~/mnt/remote
# แล้ว mount ใหม่
# ปัญหา: Host key verification failed
ssh-keygen -R hostname
# แล้วเชื่อมต่อใหม่เพื่อยอมรับ key ใหม่
# ปัญหา: FUSE device not found
sudo modprobe fuse
# เพิ่มใน /etc/modules เพื่อ load อัตโนมัติ
echo "fuse" | sudo tee -a /etc/modules
# ปัญหา: Permission denied บน mount point
# ตรวจสอบ permissions
ls -la ~/.ssh/
# ควรเป็น 700 สำหรับ .ssh และ 600 สำหรับ keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
# ปัญหา: ช้ามากเมื่อ list directory ใหญ่
# เพิ่ม options
sshfs -o cache=yes,cache_timeout=115200 \
-o attr_timeout=115200 \
user@server:/path ~/mnt/remote
# Debug mode
sshfs -o debug,sshfs_debug user@server:/path ~/mnt/remote
| คุณสมบัติ | SSHFS | NFS | SMB/CIFS | SyncThing |
|---|---|---|---|---|
| การเข้ารหัส | ✅ (SSH) | ❌ (ต้องใช้ Kerberos) | ✅ (SMB3) | ✅ |
| ติดตั้งง่าย | ✅ | ปานกลาง | ปานกลาง | ✅ |
| ไม่ต้อง root | ✅ (FUSE) | ❌ | ❌ | ✅ |
| ทำงานผ่าน Internet | ✅ | ❌ (ไม่แนะนำ) | ⚠️ (VPN) | ✅ |
| ประสิทธิภาพ | ปานกลาง | สูงมาก | สูง | - (sync) |
| Real-time access | ✅ | ✅ | ✅ | ❌ |
| Offline access | ❌ | ❌ | ❌ | ✅ |
# ========================================
# การเชื่อมต่อพื้นฐาน
# ========================================
# เชื่อมต่อ SSH ปกติ
ssh user@hostname
# ระบุ port
ssh -p 2222 user@hostname
# ใช้ private key ที่ระบุ
ssh -i ~/.ssh/id_ed25519 user@hostname
# เปิด verbose mode เพื่อ debug
ssh -v user@hostname # -v, -vv, -vvv
# ========================================
# การจัดการ SSH Keys
# ========================================
# สร้าง ED25519 key (แนะนำ)
ssh-keygen -t ed25519 -C "comment"
# สร้าง RSA 4096-bit key
ssh-keygen -t rsa -b 4096 -C "comment"
# ดู fingerprint ของ key
ssh-keygen -l -f ~/.ssh/id_ed25519.pub
# คัดลอก public key ไป remote server
ssh-copy-id user@hostname
# ========================================
# SSH Agent
# ========================================
# เริ่ม ssh-agent
eval $(ssh-agent -s)
# เพิ่ม key เข้า agent
ssh-add ~/.ssh/id_ed25519
# แสดง keys ใน agent
ssh-add -l
# ลบ keys ออกจาก agent
ssh-add -D
# ========================================
# Port Forwarding
# ========================================
# Local port forwarding
# เข้าถึง remote:3306 ผ่าน localhost:13306
ssh -L 13306:localhost:3306 user@hostname
# Remote port forwarding
# เปิด port 8080 บน remote ให้เข้าถึง localhost:80
ssh -R 8080:localhost:80 user@hostname
# Dynamic port forwarding (SOCKS proxy)
ssh -D 1080 user@hostname
# ========================================
# การใช้งานขั้นสูง
# ========================================
# ProxyJump (เข้าผ่าน bastion host)
ssh -J jump@bastion user@internal
# Agent forwarding (ใช้ key บน remote)
ssh -A user@hostname
# รันคำสั่งบน remote
ssh user@hostname "ls -la /var/log"
# รันหลายคำสั่ง
ssh user@hostname "cd /var/log && tail -n 100 syslog"
# ========================================
# SCP Commands
# ========================================
# อัปโหลดไฟล์
scp local.txt user@host:/path/
# ดาวน์โหลดไฟล์
scp user@host:/path/remote.txt ./
# คัดลอก directory (recursive)
scp -r local_dir/ user@host:/path/
# ใช้ compression
scp -C large_file.tar user@host:/path/
# จำกัด bandwidth (KB/s)
scp -l 1024 file.txt user@host:/path/
# ========================================
# SFTP Commands
# ========================================
# เชื่อมต่อ SFTP
sftp user@hostname
# คำสั่งใน SFTP session
sftp> pwd # แสดง remote directory
sftp> lpwd # แสดง local directory
sftp> ls # list remote
sftp> lls # list local
sftp> cd /path # change remote dir
sftp> lcd /path # change local dir
sftp> get file.txt # download
sftp> put file.txt # upload
sftp> mkdir dir # create directory
sftp> rm file.txt # delete file
sftp> bye # disconnect
# Batch mode
sftp -b commands.txt user@hostname
# ========================================
# SSHFS Commands - Quick Reference
# ========================================
# ติดตั้ง sshfs
sudo apt install sshfs
# Mount remote filesystem
sshfs user@hostname:/remote/path /local/mountpoint
# Mount พร้อม options ที่แนะนำ
sshfs -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3 \
-o cache=yes,kernel_cache,auto_cache \
user@hostname:/remote/path /local/mountpoint
# ใช้ identity file
sshfs -o IdentityFile=~/.ssh/id_ed25519 \
user@hostname:/path /mountpoint
# Mount ผ่าน port อื่น
sshfs -p 2222 user@hostname:/path /mountpoint
# Unmount
fusermount -u /local/mountpoint
# Force unmount
fusermount -uz /local/mountpoint
# ตรวจสอบ mounts
mount | grep sshfs
flowchart TB
subgraph DEFENSE["การป้องกัน Brute Force"]
D1["Fail2ban
บล็อก IP ที่พยายามหลายครั้ง"]
D2["Rate Limiting
MaxAuthTries = 3"]
D3["Key-only Auth
ปิด Password Auth"]
D4["Port Knocking
ซ่อน Port"]
D5["2FA/MFA
การยืนยันตัวตนหลายขั้น"]
end
A["Attacker
ผู้โจมตี"] -->|"Brute Force"| B["SSH Server"]
B --> D1
B --> D2
B --> D3
B --> D4
B --> D5
style DEFENSE fill:#3c3836,stroke:#b8bb26,color:#ebdbb2
style A fill:#504945,stroke:#fb4934,color:#ebdbb2
style B fill:#504945,stroke:#83a598,color:#ebdbb2
style D1 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style D2 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style D3 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style D4 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
style D5 fill:#504945,stroke:#ebdbb2,color:#ebdbb2
สำหรับ SSH Server:
สำหรับ SSH Client:
สำหรับ File Transfer:
ในบทนี้ได้ศึกษาโปรโตคอลระดับ Application ที่เกี่ยวข้องกับการถ่ายโอนไฟล์และการเข้าถึงระยะไกล โดยมีประเด็นสำคัญดังนี้:
โปรโตคอลการถ่ายโอนไฟล์:
การเข้าถึงระยะไกล:
| โปรโตคอล | Port | เข้ารหัส | Authentication | การใช้งานที่แนะนำ |
|---|---|---|---|---|
| FTP | 21/20 | ไม่ | Username/Password | ไม่แนะนำ |
| TFTP | 69 | ไม่ | ไม่มี | Network boot เท่านั้น |
| SFTP | 22 | ใช่ | SSH Keys/Password | ถ่ายโอนไฟล์ทั่วไป |
| FTPS | 990/21 | ใช่ | Certificate/Password | Legacy systems |
| SSH | 22 | ใช่ | Keys/Password/MFA | Remote access |
| SCP | 22 | ใช่ | SSH Keys/Password | Quick file copy |
| SSHFS | 22 | ใช่ | SSH Keys/Password | Mount remote filesystem |
flowchart TB
START["ต้องการถ่ายโอนไฟล์/เข้าถึงระยะไกล"] --> Q1{"ต้องการ
ความปลอดภัย?"}
Q1 -->|"ใช่"| Q2{"ลักษณะการใช้งาน?"}
Q1 -->|"ไม่ (เครือข่ายปิด)"| Q3{"ใช้สำหรับ
Network Boot?"}
Q2 -->|"จัดการไฟล์ Interactive"| SFTP["ใช้ SFTP"]
Q2 -->|"คัดลอกไฟล์ครั้งเดียว"| SCP["ใช้ SCP"]
Q2 -->|"เข้าถึงไฟล์ต่อเนื่อง
เหมือน local"| SSHFS["ใช้ SSHFS"]
Q2 -->|"Remote shell access"| SSH["ใช้ SSH"]
Q3 -->|"ใช่"| TFTP["ใช้ TFTP
(จำกัดเครือข่าย)"]
Q3 -->|"ไม่"| LEGACY{"ต้องรองรับ
Legacy Systems?"}
LEGACY -->|"ใช่"| FTPS["ใช้ FTPS"]
LEGACY -->|"ไม่"| SFTP
style START fill:#282828,stroke:#ebdbb2,color:#ebdbb2
style Q1 fill:#3c3836,stroke:#fabd2f,color:#ebdbb2
style Q2 fill:#3c3836,stroke:#fabd2f,color:#ebdbb2
style Q3 fill:#3c3836,stroke:#fabd2f,color:#ebdbb2
style LEGACY fill:#3c3836,stroke:#fabd2f,color:#ebdbb2
style SFTP fill:#504945,stroke:#b8bb26,color:#ebdbb2
style SCP fill:#504945,stroke:#83a598,color:#ebdbb2
style SSHFS fill:#504945,stroke:#d3869b,color:#ebdbb2
style SSH fill:#504945,stroke:#8ec07c,color:#ebdbb2
style TFTP fill:#504945,stroke:#fe8019,color:#ebdbb2
style FTPS fill:#504945,stroke:#fb4934,color:#ebdbb2
RFC 959 - File Transfer Protocol (FTP)
RFC 1350 - The TFTP Protocol (Revision 2)
RFC 4217 - Securing FTP with TLS
RFC 4251 - The Secure Shell (SSH) Protocol Architecture
RFC 4252 - The Secure Shell (SSH) Authentication Protocol
RFC 4253 - The Secure Shell (SSH) Transport Layer Protocol
RFC 4254 - The Secure Shell (SSH) Connection Protocol
draft-ietf-secsh-filexfer - SSH File Transfer Protocol
OpenSSH Manual Pages
Mozilla SSH Guidelines
NIST Special Publication 800-52 - Guidelines for TLS Implementations
CIS Benchmark for OpenSSH