BẢO MẬTCĂN BẢNTUẦN 01–04
BÀI 06

Hành trình một lần mở trang: từ HTTP chữ rõ đến HTTPS

Câu hỏi xuyên suốt: một thành viên mở trang đóng lệ phí của câu lạc bộ. Trên đường từ trình duyệt đến máy chủ, ai nhìn thấy được gì, ai có thể sửa gì, và ta chặn bằng cách nào?

Thời lượng: khoảng 2 giờ 20 phút (giảng và thực hành xen kẽ; nên chia hai buổi: phần A–B rồi phần C–D; 11 bài tập, bài cuối làm ở nhà)

Bốn phần của bài: nội dung gửi đi, đường đi, bảo vệ bằng TLS, rồi chẩn đoán lỗi. Mỗi phần có bài tập.
Bốn phần của bài: nội dung gửi đi, đường đi, bảo vệ bằng TLS, rồi chẩn đoán lỗi. Mỗi phần có bài tập.
01

Mạch bài: một câu hỏi, bốn phần

5 phút

Bài 5 cho biết mỗi kết nối có IP và port ở hai đầu. Bài này đi tiếp với một tình huống cụ thể:

Tình huốngThành viên Lan mở trang đóng lệ phí của câu lạc bộ, nhập tên và số tiền, rồi bấm gửi. Dữ liệu đó đi qua router nhà Lan, qua nhà mạng, qua nhiều thiết bị trung gian, rồi mới đến máy chủ. Ai trên đường đi đọc được tên, số tiền và mã phiên đăng nhập của Lan? Ai sửa được số tài khoản trong trang trả về?

Để trả lời, bài đi theo thứ tự "nhìn vấn đề trước, tìm cách chặn sau":

PhầnViệc làmTrả lời câu hỏi nàoThời gian
A. Nội dungĐọc HTTP, tự dựng server và bắt gói trong máyDữ liệu gửi đi trông thế nào? (kết quả: chữ rõ, ai thấy cũng đọc được)40 phút
B. Đường điDNS, router và NAT, firewall, TCP, quét mạng nhàDữ liệu đi qua những điểm nào, mỗi điểm thấy gì và có thể làm gì?45 phút
C. Bảo vệTLS và HTTPS, chứng chỉ, tự chạy server HTTPSLàm sao biến chữ rõ thành chữ mã và chắc rằng đang nói đúng máy chủ?35 phút
D. Chẩn đoánTìm lớp bị lỗi, rà soát websiteKhi hỏng, lỗi ở lớp nào? Website của mình đã đủ các lớp chưa?15 phút

Cần chuẩn bị

  • Python 3.8 trở lên (chạy web server thử), trình duyệt, terminal.
  • Wireshark đã cài và cấp quyền bắt gói. Nếu chưa có, vẫn làm được phần lớn bài tập bằng cách đọc dữ liệu mẫu.
  • curl (có sẵn trên macOS, Linux; Windows dùng curl.exe).
  • openssl (Lab 2, tạo chứng chỉ thử; có sẵn trên macOS, Linux; Windows dùng bản đi kèm Git for Windows).
Quy tắc an toàn khi thực hànhChỉ dùng dữ liệu giả. Không nhập tài khoản, mật khẩu hay số điện thoại thật khi đang bắt gói. Chỉ bắt gói trên máy và mạng của chính bạn hoặc nơi được cho phép. Chỉ kết nối tới máy của mình và tới example.com.
02

A1. HTTP: nội dung mà trình duyệt gửi đi

8 phút
Trình duyệtGửi request
MạngMang các gói tin
Web serverTrả response

là ngôn ngữ giữa trình duyệt và website. Trình duyệt gửi một , server trả một . Khi Lan bấm "Đóng phí", trình duyệt gửi khoảng như sau (đã trình bày lại cho dễ đọc):

REQUEST MINH HỌA
POST /dong-phi HTTP/1.1
Host: clb.example
Cookie: phien=a1b2c3d4
Content-Type: application/x-www-form-urlencoded
Content-Length: 29

ten=Lan&so_tien=200000&ghi=ok
  • Dòng đầu: (POST = gửi dữ liệu lên; GET = lấy tài nguyên; còn PUT, DELETE), đường dẫn /dong-phi trên server, và phiên bản giao thức.
  • Các dòng Tên: giá trị là . Host là tên đích. Cookie mang mã phiên đăng nhập (bài 3). Content-Length là số byte của body.
  • Dòng trống kết thúc header. Phần sau đó là body: dữ liệu Lan nhập.

Server trả lời bằng một response:

RESPONSE MINH HỌA
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 14

<h1>Hello</h1>

Dòng đầu có . Bảng mã thường gặp:

MãNghĩaKhông được suy ra
200Thành côngDữ liệu chắc chắn đúng
301 / 302Chuyển hướng sang URL khácURL mới là đáng tin
403Từ chối vì không đủ quyềnMật khẩu sai
404Không tìm thấy tài nguyênMạng hỏng
500Lỗi bên trong serverBị tấn công

Một response chứa số tài khoản sai vẫn là 200: HTTP chỉ nói giao thức chạy ổn, tính đúng của dữ liệu là chuyện toàn vẹn (bài 1).

Điểm mấu chốt của phần AToàn bộ request ở trên là văn bản thường. Tên, số tiền và mã phiên nằm ở dạng chữ rõ trong từng gói tin. Phần A2 sẽ chứng minh điều đó bằng cách tự bắt gói.

BÀI TẬP 1 · 5 PHÚT

Đọc một request

Dùng request POST ở trên và trả lời:

  1. Method và đường dẫn là gì?
  2. Phần nào là dữ liệu Lan nhập, phần nào là bằng chứng "đã đăng nhập"?
  3. Content-Length: 29 đếm cái gì? Hãy đếm thử chuỗi ten=Lan&so_tien=200000&ghi=ok.
  4. Nếu request này đi qua HTTP, người ở router nhà Lan đọc được những gì và làm gì được với cookie?
Xem đáp án
  1. Method POST, đường dẫn /dong-phi.
  2. Dữ liệu nhập là body (ten, so_tien, ghi). Bằng chứng đăng nhập là header Cookie: phien=a1b2c3d4.
  3. Số byte của body. Chuỗi có đúng 29 ký tự ASCII (7 + 1 + 14 + 1 + 6) nên 29 byte.
  4. Đọc được toàn bộ: tên, số tiền, cookie. Với cookie còn hiệu lực, người đó gửi request giả danh Lan mà không cần mật khẩu hay MFA. Đây là đánh cắp phiên (session hijacking) đã học ở bài 3.
03

A2. Lab 1: tự bắt gói HTTP trong máy mình

30 phút
Trình duyệt127.0.0.1:51514
Python server127.0.0.1:8000

Bài giảng đến đây đã nói HTTP là chữ rõ. Lab này để bạn tự chứng minh điều đó trên máy mình: tự tạo một trang web, tự chạy web server, tự gửi request, rồi tự bắt gói bằng Wireshark để đọc nguyên văn nội dung. Mọi thứ chạy trong máy bạn, không đụng đến mạng ngoài. Địa chỉ 127.0.0.1 luôn trỏ về chính máy, nên gói không rời khỏi máy; dùng của Wireshark để xem các gói đó.

Kết quả cuối labBạn sẽ có: (1) thư mục network-lab với file index.html; (2) một web server chạy ở port 8000; (3) một lần mở trang bằng trình duyệt và bằng curl; (4) một bản bắt gói trong đó đọc được cookie và dữ liệu form dưới dạng chữ rõ.

Bước 0. Kiểm tra máy đã có đủ công cụ chưa

Bạn cần ba thứ: terminal (cửa sổ gõ lệnh), Python 3 (để chạy web server) và curl (để gửi request từ dòng lệnh). Mở terminal như sau:

Hệ điều hànhMở terminal
macOSNhấn ⌘ + Space, gõ Terminal, nhấn Enter
WindowsBấm Start, gõ PowerShell, chọn Windows PowerShell
LinuxNhấn Ctrl + Alt + T (hoặc tìm Terminal trong menu ứng dụng)

Gõ lệnh kiểm tra rồi nhấn Enter:

MACOS
python3 --version
curl --version
WINDOWS POWERSHELL
py --version
curl.exe --version
LINUX
python3 --version
curl --version
PhầnÝ nghĩa
python3 --versionHỏi máy xem Python 3 có không và phiên bản nào. macOS và Linux dùng tên python3.
py --versionTrên Windows, py là trình khởi chạy Python do bộ cài python.org cung cấp. Dùng py thay cho python3.
curl.exe --versionTrên Windows luôn gõ cả .exe. PowerShell có sẵn tên curl nhưng trỏ tới lệnh khác nên cho kết quả không như mong đợi.
KẾT QUẢ MONG ĐỢI (SỐ PHIÊN BẢN CÓ THỂ KHÁC)
Python 3.9.6
curl 8.7.1 (x86_64-apple-darwin26.0) ...

Python từ 3.8 trở lên là đủ. Nếu báo "command not found" hoặc "not recognized": macOS chạy xcode-select --install hoặc tải Python tại python.org; Windows tải bộ cài tại python.org và tick ô Add python.exe to PATH trước khi cài; Linux chạy sudo apt install python3 curl. Cài xong, đóng và mở lại terminal rồi kiểm tra lại.

Wireshark tải tại wireshark.org. Lúc cài: macOS cài xong thường còn phải cài thêm ChmodBPF để được phép bắt gói (hướng dẫn ở bước 3, mục 3a); Windows giữ tùy chọn cài Npcap và tick hỗ trợ loopback; Linux cho phép người dùng thường bắt gói khi được hỏi, hoặc chạy Wireshark bằng sudo.

Bước 1. Tạo thư mục làm việc và file index.html

Web server phục vụ file ở thư mục mà bạn chạy lệnh, và cho phép đọc mọi file trong đó. Vì vậy hãy tạo một thư mục trống riêng, đừng chạy server ở thư mục Home hay Documents (nơi có dữ liệu cá nhân). Trong terminal:

MACOS
mkdir ~/network-lab
cd ~/network-lab
pwd
WINDOWS POWERSHELL
mkdir $HOME\network-lab
cd $HOME\network-lab
pwd
LINUX
mkdir ~/network-lab
cd ~/network-lab
pwd
PhầnÝ nghĩa
mkdirTạo thư mục mới (make directory). Tên thư mục là network-lab.
~ hoặc $HOMEThư mục cá nhân của bạn. Vậy thư mục mới nằm ngay trong thư mục cá nhân.
cdĐi vào một thư mục (change directory). Từ lúc này mọi lệnh chạy "tại" network-lab.
pwdIn ra đường dẫn thư mục hiện tại. Kết quả phải kết thúc bằng network-lab, ví dụ /Users/ten-ban/network-lab.

Tiếp theo tạo file index.html, một trang web chỉ có một dòng tiêu đề (không dấu để tránh lỗi font khi xem gói):

MACOS
echo '<h1>Cau lac bo - Lich sinh hoat</h1>' > index.html
ls -l
cat index.html
WINDOWS POWERSHELL
Set-Content -Path index.html -Value '<h1>Cau lac bo - Lich sinh hoat</h1>' -Encoding ascii
dir
type index.html
LINUX
echo '<h1>Cau lac bo - Lich sinh hoat</h1>' > index.html
ls -l
cat index.html
PhầnÝ nghĩa
echo '...' > index.htmlecho in chuỗi ra; dấu > chuyển phần in ra đó vào file index.html thay vì màn hình. File chưa có thì được tạo.
Set-Content -Path ... -Value ...Lệnh PowerShell ghi giá trị vào file. -Encoding ascii giữ file là chữ thường, không có ký tự lạ ở đầu file.
ls -l / dirLiệt kê file trong thư mục. Phải thấy index.html, cỡ 37 byte.
cat / typeIn nội dung file ra màn hình, để chắc rằng file đúng như ý.
KẾT QUẢ MONG ĐỢI
<h1>Cau lac bo - Lich sinh hoat</h1>
Muốn tạo file bằng trình soạn thảo thay vì lệnh?Dùng VS Code, Notepad++ hoặc Notepad đều được. Ba bẫy hay gặp: (1) Windows Notepad: ở ô Save as type chọn All files, nếu không file thành index.html.txt và server báo 404; bật File name extensions trong Explorer (View → Show) để nhìn thấy đuôi thật. (2) macOS TextEdit mặc định lưu dạng RTF; vào Format → Make Plain Text (⇧⌘T) trước khi lưu. (3) Lưu file vào đúng thư mục network-lab.

Bước 2. Chạy web server và mở trang

Python có sẵn một web server nhỏ. Gõ lệnh sau trong thư mục network-lab (vẫn cửa sổ terminal vừa dùng; gọi nó là Terminal A):

MACOS
python3 -m http.server 8000 --bind 127.0.0.1
WINDOWS POWERSHELL
py -m http.server 8000 --bind 127.0.0.1
LINUX
python3 -m http.server 8000 --bind 127.0.0.1
PhầnÝ nghĩa
python3 -m http.server-m nghĩa là chạy một module có sẵn của Python. http.server là module web server tĩnh: nó trả file trong thư mục hiện hành cho ai hỏi.
8000Port mà server lắng nghe (bài 5). Chọn 8000 vì port dưới 1024 cần quyền quản trị.
--bind 127.0.0.1Chỉ nghe trên địa chỉ loopback, nghĩa là chỉ máy này truy cập được. Không có tham số này server nghe ở mọi địa chỉ và máy khác cùng Wi-Fi cũng vào được. Thói quen tốt cho dịch vụ thử nghiệm.
KẾT QUẢ MONG ĐỢI TRONG TERMINAL A
Serving HTTP on 127.0.0.1 port 8000 (http://127.0.0.1:8000/) ...

Terminal A đứng yên, không trả về dấu nhắc lệnh. Đó là bình thường: server đang chạy và chờ kết nối. Đừng đóng cửa sổ này; muốn dừng thì nhấn Ctrl + C. Từ giờ, mọi lệnh khác gõ ở một cửa sổ mới (Terminal B): macOS nhấn ⌘ + T để mở tab mới, Windows mở thêm một PowerShell, Linux nhấn Ctrl + Shift + T. Nhớ cd vào network-lab (với macOS/Linux là cd ~/network-lab) ở cửa sổ mới.

Mở trình duyệt, vào http://127.0.0.1:8000/. Bạn thấy dòng tiêu đề "Cau lac bo - Lich sinh hoat". Quay lại Terminal A, server đã in nhật ký của lần truy cập:

NHẬT KÝ SERVER (NGÀY GIỜ CỦA BẠN SẼ KHÁC)
127.0.0.1 - - [19/Oct/2026 20:05:38] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [19/Oct/2026 20:05:38] code 404, message File not found
127.0.0.1 - - [19/Oct/2026 20:05:38] "GET /favicon.ico HTTP/1.1" 404 -
PhầnÝ nghĩa
127.0.0.1Địa chỉ của client (ở đây là chính máy bạn).
[19/Oct/2026 ...]Thời điểm server nhận request.
"GET / HTTP/1.1"Dòng đầu của request (phần A1): method GET, đường dẫn / và phiên bản giao thức.
200Mã trạng thái: server trả trang thành công.
/favicon.ico ... 404Trình duyệt tự xin thêm icon của tab; thư mục không có file đó nên server trả 404. Không phải lỗi của bạn.

Bây giờ gửi cùng request đó bằng curl ở Terminal B, thêm -i để in cả phần header của response:

TERMINAL B
curl -i http://127.0.0.1:8000/
KẾT QUẢ MONG ĐỢI (RÚT GỌN)
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.9.6
Content-type: text/html
Content-Length: 37

<h1>Cau lac bo - Lich sinh hoat</h1>

Đây chính là response ở phần A1: dòng trạng thái, các header, dòng trống, rồi body. Server Python này trả HTTP/1.0 dù curl gửi HTTP/1.1; hai bên chỉ cần tương thích.

Gặp lỗi?

Dấu hiệuNguyên nhân thường gặpCách sửa
command not found hoặc not recognizedChưa cài Python hoặc gõ sai tên lệnhLàm lại bước 0. Windows dùng py, macOS/Linux dùng python3
Address already in usePort 8000 đang bị chương trình khác (hoặc server cũ) giữTắt server cũ bằng Ctrl+C, hoặc đổi sang port khác, ví dụ 8001, và sửa URL cho khớp
Trình duyệt báo "Can't connect" / "refused"Server chưa chạy, đã bị tắt, hoặc sai portNhìn Terminal A xem còn dòng "Serving HTTP" không; kiểm tra URL có đúng :8000
Trang hiện "Directory listing" thay vì tiêu đềChạy server sai thư mục, hoặc file tên khác index.htmlCtrl+C, cd đúng vào network-lab, kiểm tra tên file bằng ls/dir
Trang báo 404 Not FoundThư mục có file nhưng sai tên, thường là index.html.txtĐổi tên file, xem lại ghi chú về Notepad ở bước 1

Bước 3. Làm quen với Wireshark (làm một lần, dùng cho cả hai lab)

Wireshark là chương trình nghe lén có phép trên máy của chính bạn: nó chép lại mọi gói tin đi qua một giao diện mạng và trình bày chúng thành bảng để đọc. Phần này chỉ để bạn biết bấm cái gì, gõ vào đâu, nút nào làm gì; các thao tác bắt gói thật nằm ở bước 4. Nội dung theo Wireshark 4.x trên macOS; Windows và Linux gần như giống (phím Ctrl thay cho ⌘).

3a. Cấp quyền bắt gói (lỗi "You don't have permission to capture")

Lần đầu mở Wireshark trên macOS, bạn có thể thấy khung vàng nâu ở màn hình chào: "You don't have permission to capture on local interfaces. You can fix this by installing ChmodBPF." Lý do: macOS chỉ cho người quản trị đọc thiết bị bắt gói (/dev/bpf*). ChmodBPF là một thành phần nhỏ đi kèm Wireshark, cho phép tài khoản của bạn đọc thiết bị đó mà không phải chạy Wireshark bằng quyền root (chạy cả chương trình bằng root là thói quen không an toàn). Cách làm:

  1. Bấm vào liên kết installing ChmodBPF trong khung vàng. Nếu không thấy liên kết, mở Finder, vào /Applications/Wireshark.app/Contents/Resources/Extras/ (chuột phải Wireshark → Show Package Contents để đi vào) và nhấp đúp Install ChmodBPF.pkg.
  2. Trong bộ cài bấm Continue → Install, nhập mật khẩu máy khi macOS hỏi, đợi báo "The installation was successful".
  3. Thoát hẳn Wireshark (⌘ + Q, không chỉ đóng cửa sổ) rồi mở lại. Khung vàng biến mất, mỗi giao diện trong danh sách có thêm đường sóng nhỏ. Nếu vẫn báo lỗi: đăng xuất rồi đăng nhập lại, hoặc khởi động lại máy, vì quyền nhóm mới chỉ có hiệu lực cho phiên đăng nhập mới.
Hệ điều hànhCách cấp quyền
macOSChmodBPF như trên
WindowsBộ cài Npcap đã lo việc này. Gặp lỗi thì cài lại Npcap, tick tùy chọn hỗ trợ loopback, rồi chạy Wireshark lần đầu bằng "Run as administrator" để kiểm tra
Linux (Ubuntu/Debian)sudo dpkg-reconfigure wireshark-common chọn Yes, rồi sudo usermod -aG wireshark $USER, sau đó đăng xuất và đăng nhập lại
3b. Màn hình chào: chọn giao diện để bắt

Khi mở Wireshark bạn thấy ba thứ chính ở giữa màn hình:

PhầnÝ nghĩa
Ô "Enter a capture filter …"Bộ lọc bắt gói (capture filter): lọc ngay lúc thu, gói không khớp bị bỏ luôn, không lấy lại được. Cú pháp riêng, ví dụ port 8000. Trong bài này để trống cho an toàn: thu hết rồi lọc sau.
Nút "All interfaces shown"Chọn nhóm giao diện hiển thị (tất cả, hoặc chỉ giao diện có dữ liệu). Cứ để mặc định.
Danh sách giao diệnMỗi dòng là một "cửa" mạng. Đường sóng nhỏ bên phải tên cho biết đang có lưu lượng. Nhấp đúp vào dòng để bắt đầu bắt gói ngay trên giao diện đó. Hoặc nhấp một lần để chọn rồi bấm nút vây cá mập xanh ở thanh công cụ.

Danh sách trên Mac có rất nhiều tên lạ vì macOS tạo sẵn nhiều giao diện cho tính năng hệ thống. Bảng dưới giải thích từng nhóm (tên và số có thể khác theo máy bạn). Với lab chỉ cần hai dòng in đậm; còn lại bạn có thể bỏ qua.

Tên giao diệnLà gìCó cần cho lab?
Loopback: lo0 (Linux: lo)Giao diện nội bộ 127.0.0.1: gói từ máy gửi thẳng cho chính máy, không ra khỏi máyCó: Lab 1 và Lab 2, vì server và client cùng nằm trong máy bạn
Wi-Fi: en0Card Wi-Fi thật. Mọi gói đi ra router, Internet đều qua đây. Đường sóng nhỏ bên phải là lưu lượng đang chạyChỉ ở bước tùy chọn của Lab 2 (truy cập example.com). Không dùng để bắt gói tới 127.0.0.1
utun0 … utun4Đường hầm phần mềm (user tunnel): VPN, iCloud Private Relay và một số dịch vụ hệ thốngKhông. Chỉ bắt khi bạn đang tìm hiểu lưu lượng VPN
awdl0Apple Wireless Direct Link: kết nối trực tiếp giữa thiết bị Apple (AirDrop, AirPlay, Handoff, Sidecar)Không
llw0Low Latency WLAN: giao diện đi cặp với awdl0 cho các tính năng trênKhông
anpi0 … anpi2Giao diện nội bộ do Mac chip Apple tạo, gắn với cổng và phụ kiện của hệ thống; thường không có lưu lượngKhông
Ethernet Adapter (en4/en5/en6)Card Ethernet. Có thể là dây mạng qua bộ chuyển USB hoặc Thunderbolt, hoặc giao diện ảo do phần mềm máy ảo, chia sẻ mạng USB từ điện thoại tạo raKhông, trừ khi bạn cắm dây mạng thật và muốn bắt trên đó
Thunderbolt 1 … 3 (en1/en2/en3)Ba cổng Thunderbolt có thể dùng để nối mạng giữa hai máy qua cáp ThunderboltKhông
Thunderbolt Bridge: bridge0Cầu nối gộp các cổng Thunderbolt thành một mạngKhông
gif0, stf0Giao diện đường hầm của hệ điều hành: gif là đường hầm IP chung, stf là cầu nối IPv6 qua IPv4 (6to4). Hầu như không dùngKhông
ap1Giao diện điểm phát Wi-Fi: xuất hiện khi bạn bật chia sẻ Internet (Internet Sharing) cho thiết bị khácKhông
nan0Neighbor Awareness Networking (Wi-Fi Aware): kết nối Wi-Fi trực tiếp giữa các thiết bị lân cậnKhông

Các dòng có biểu tượng bánh răng ở cuối danh sách (Cisco remote capture: ciscodump, Random packet generator: randpkt, SSH remote capture: sshdump, và các dòng tương tự như UDP Listener, Wi-Fi remote capture) không phải card mạng. Đó là công cụ bổ trợ (extcap) của Wireshark: ciscodump và sshdump bắt gói từ một thiết bị khác (router Cisco, máy chủ SSH) qua mạng; randpkt sinh gói giả để thử nghiệm. Bấm đúp vào chúng sẽ mở hộp cấu hình kết nối tới máy khác, nằm ngoài phạm vi bài này. Chỉ cấu hình khi bạn được phép bắt gói trên thiết bị đó.

Cách chọn giao diện nhanhHỏi "client và server của mình đang nằm ở đâu?". Cùng một máy và dùng địa chỉ 127.0.0.1 hoặc localhost thì chọn Loopback. Một đầu ở xa (website thật, máy khác trong nhà) thì chọn card đang dùng để ra mạng, thường là Wi-Fi: en0. Chọn sai là lý do số một khiến bảng gói trống.
3c. Cửa sổ chính khi đang bắt gói: sáu vùng cần biết
Bố cục cửa sổ WiresharkSáu vùng: thanh công cụ, ô lọc hiển thị, danh sách gói, chi tiết gói, byte của gói và thanh trạng thái. Capturing from Loopback: lo0 Start · Stop · Restart · Options · Open · Save · Find … 1 tcp.port == 8000 2 No.TimeSourceDestinationProtocolLengthInfo 10.000127.0.0.1127.0.0.1TCP6851514 → 8000 [SYN] 20.000127.0.0.1127.0.0.1TCP688000 → 51514 [SYN, ACK] 30.000127.0.0.1127.0.0.1TCP5651514 → 8000 [ACK] 40.001127.0.0.1127.0.0.1HTTP175GET / HTTP/1.1 5 … (dòng đang chọn có nền xanh) 3 ▸ Frame 4: 175 bytes on wire▸ Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1▸ Transmission Control Protocol, Src Port: 51514, Dst Port: 8000▾ Hypertext Transfer ProtocolGET / HTTP/1.1\r\n Cookie: phien=demo123\r\n 4 0030 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1..0040 43 6f 6f 6b 69 65 3a 20 70 68 69 65 6e 3d 64 65 Cookie: phien=de0050 6d 6f 31 32 33 0d 0a 0d 0a mo123.... 5 Loopback: lo0Packets: 12 · Displayed: 8 (66.7%) 6
Sơ đồ minh họa cửa sổ Wireshark sau khi bắt gói (vẽ lại, nội dung giản lược). Số ① đến ⑥ khớp với bảng bên dưới.
SốVùngDùng để làm gì
①Thanh công cụCác nút điều khiển (bảng ngay dưới)
②Ô lọc hiển thị (display filter)Gõ điều kiện, nhấn Enter, chỉ giữ lại gói khớp. Đây là ô bạn dùng nhiều nhất. Nền xanh lá là cú pháp đúng, đỏ là sai (chưa Enter được), vàng là cảnh báo nhưng vẫn chạy. Nút mũi tên xanh bên phải là "áp dụng" (giống Enter), mũi tên xuống mở lịch sử bộ lọc, nút X xóa trắng ô lọc, biểu tượng bookmark ở bên trái mở bộ lọc đã lưu, dấu + (không cần dùng) mở thanh "Filter Buttons" với ô Label, Filter, Comment để lưu bộ lọc thành nút bấm nhanh. Lỡ bấm nhầm + thì bấm Cancel ở góc phải thanh đó là đóng lại, dữ liệu không mất. Phím tắt đưa con trỏ vào ô này: ⌘ + /
③Danh sách gói (Packet List)Mỗi dòng là một gói. Cột: No. số thứ tự; Time giây kể từ gói đầu; Source/Destination IP gửi và nhận; Protocol giao thức cao nhất Wireshark nhận ra (TCP, HTTP, TLSv1.3, DNS…); Length số byte; Info tóm tắt, ví dụ GET / HTTP/1.1 hoặc 51514 → 8000 [SYN]. Nhấp một dòng để xem chi tiết ở khung ④ và ⑤. Màu nền chỉ là gợi ý theo giao thức, đừng dựa vào màu mà hãy đọc cột Protocol
④Chi tiết gói (Packet Details)Gói được bóc theo từng lớp như bài đã học: Frame → Internet Protocol (IP) → Transmission Control Protocol (TCP) → Hypertext Transfer Protocol (HTTP). Bấm mũi tên ▸ để mở từng lớp và thấy từng trường, ví dụ Cookie
⑤Byte của gói (Packet Bytes)Dữ liệu thô: bên trái là số hex, bên phải là ký tự đọc được. Với HTTP bạn đọc được chữ ngay ở cột phải, với HTTPS chỉ thấy ký tự vô nghĩa. Bấm vào một trường ở ④ thì đoạn byte tương ứng ở ⑤ được tô sáng
⑥Thanh trạng tháiBên trái là tên giao diện đang bắt. Bên phải: Packets là tổng số gói đã thu, Displayed là số gói đang hiển thị sau khi lọc. Hai số khác nhau nghĩa là bộ lọc đang ẩn bớt dòng (không xóa)
3d. Các nút trên thanh công cụ (từ trái sang phải)

Rê chuột lên một nút để xem tên đầy đủ. Những nút cần dùng trong bài:

NútTênLàm gìLưu ý
Vây cá mập xanh dươngStart capturing packets (⌘ + E)Bắt đầu bắt gói trên giao diện đang chọnChỉ sáng khi đã chọn giao diện. Bấm trước khi gõ lệnh curl
Hình vuông đỏStop capturing (⌘ + E)Dừng bắt góiDừng xong gói vẫn còn trên màn hình để phân tích. Nếu quên dừng, bảng cuộn mãi và file phình to
Vây cá mập xanh lá có mũi tên vòngRestart current captureDừng và bắt đầu lại ngay trên cùng giao diệnGói cũ sẽ mất; Wireshark hỏi lưu hay không. Rất tiện khi muốn làm sạch rồi bắt lần mới
Bánh răngCapture options (⌘ + K)Mở hộp thoại chọn giao diện, đặt capture filter, giới hạn kích thướcBài này không cần chỉnh
Thư mụcOpen a capture fileMở file .pcapng đã lưuDùng để xem lại hoặc mở bản capture mẫu
Tờ giấy có bútSave this capture fileLưu toàn bộ gói đã bắt thành fileChỉ lưu khi cần giữ bằng chứng. File chứa dữ liệu thật, nhớ xóa khi xong
Dấu XClose this capture fileĐóng bản capture hiện tại, quay về màn hình chàoHỏi lưu nếu chưa lưu
Kính lúpFind a packet (⌘ + F)Tìm gói có chuỗi, hex hoặc tên trườngThanh tìm hiện bên dưới ô lọc, nhớ chọn đúng vùng tìm (Packet bytes để tìm chữ thô)
Hai mũi tên xanh trái, phảiGo back / forwardLùi và tiến trong lịch sử các gói bạn đã chọn
Mũi tên lên và xuốngGo to first / last packetNhảy tới gói đầu hoặc gói cuối
Nút có mũi tên xuống ở cuối danh sáchAutomatically scroll during live captureBật: bảng tự cuộn xuống gói mới nhất khi đang bắt. Tắt: giữ nguyên chỗ bạn đang đọcTắt đi nếu bạn đang đọc một dòng mà bảng cứ cuộn đi
Dòng kẻ nhiều màuColorize packet listBật/tắt tô màu dòng theo giao thứcTắt đi nếu màu làm khó đọc
Kính lúp có dấu + / − / =Zoom in / out / normalPhóng to, thu nhỏ, khôi phục cỡ chữDùng khi chụp ảnh màn hình hoặc chữ nhỏ
Hai nút cuối (cột, bố cục)Resize columns / layoutTự chỉnh độ rộng cột cho vừa nội dungKhi cột Info bị cắt chữ thì bấm nút này
Ba nút dùng nhiều nhất trong bàiVây cá mập xanh (Start), hình vuông đỏ (Stop) và ô lọc hiển thị. Phần còn lại là phụ.
3e. Bộ lọc hiển thị: gõ gì vào ô ②

Các bộ lọc sau đủ cho cả hai lab. Gõ vào ô lọc rồi nhấn Enter; xóa trắng ô rồi Enter để hiện lại tất cả. Có thể ghép bằng && (và), || (hoặc), ! (phủ định).

Gõ vào ô lọcHiện những gói nàoDùng ở
tcp.port == 8000Mọi gói có port nguồn hoặc đích là 8000 (luồng HTTP của lab)Lab 1
tcp.port == 8000 || tcp.port == 8443Cả luồng HTTP và luồng HTTPSLab 2
httpChỉ gói đã được nhận ra là HTTPLab 1
http.request.method == "POST"Chỉ các request POSTLab 1
tlsChỉ gói TLS (bắt tay và Application Data)Lab 2
tls.handshake.type == 1Chỉ gói Client Hello của TLSLab 2
dnsChỉ truy vấn và trả lời DNSLab 2, bước 5
tcp.flags.syn == 1Gói có cờ SYN (bắt đầu bắt tay TCP, cả SYN và SYN/ACK)Phần B3
frame contains "demo123"Gói có chuỗi demo123 nằm nguyên văn trong dữ liệu. Không có kết quả nghĩa là chuỗi không lộCả hai lab, phép thử chữ rõ

Gõ dần dần, Wireshark gợi ý tên trường trong danh sách thả xuống. Nếu ô chuyển nền đỏ, hay gặp: sai dấu (= thay vì ==), thiếu dấu ngoặc kép quanh chuỗi, gõ sai tên trường.

3e-2. Đọc hiểu một bộ lọc: tên trường, toán tử, giá trị

Mọi bộ lọc hiển thị đều có cùng một hình dạng: tên_trường toán_tử giá_trị. Ví dụ tcp.port == 8000 đọc là "trường tcp.port bằng 8000". Tên trường chính là các mục bạn thấy trong khung ④ (Packet Details): tcp là giao thức, dấu chấm đi vào từng thuộc tính của giao thức đó. Bấm một dòng ở khung ④, thanh dưới cùng của cửa sổ hiện đúng tên trường để bạn chép vào ô lọc. Chỉ gõ tên giao thức (như http, tls, dns) nghĩa là "gói có giao thức này".

Các trường (thuộc tính) hay dùng

TrườngThuộc giao thức / lớpÝ nghĩaKiểu giá trị và ví dụ
frame.lenFrame (gói thô)Kích thước cả gói, tính bằng byteSố: frame.len > 1000
frameFrameToàn bộ nội dung byte của gói. Dùng với contains để tìm chuỗi bất kỳChuỗi: frame contains "demo123"
ip.addrIP (lớp mạng, bài 5)IP của gói, cả nguồn lẫn đíchĐịa chỉ, không có ngoặc kép: ip.addr == 127.0.0.1
ip.src / ip.dstIPIP nguồn / IP đích riêng từng chiềuip.dst == 203.0.113.10
tcp.portTCP (bài 5 và phần B3)Port của gói, cả nguồn lẫn đích. Khớp nếu một trong hai là giá trị đóSố: tcp.port == 8000
tcp.srcport / tcp.dstportTCPPort nguồn / port đích riêng từng chiều. tcp.dstport == 8000 chỉ lấy gói đi tới serverSố
tcp.streamTCPSố thứ tự của một luồng (một kết nối). Do Follow TCP Stream điền sẵnSố: tcp.stream eq 3
tcp.flags.synTCP (bắt tay)Cờ SYN: 1 nghĩa là gói xin kết nốiBật/tắt: tcp.flags.syn == 1 hoặc chỉ tcp.flags.syn
tcp.flags.ackTCPCờ ACK: xác nhận đã nhậntcp.flags.ack == 1
tcp.flags.finTCPCờ FIN: một bên báo đóng kết nối bình thườngtcp.flags.fin == 1
tcp.flags.resetTCPCờ RST: ngắt kết nối đột ngột, thường do port đóng hoặc bị chặntcp.flags.reset == 1
tcp.lenTCPSố byte dữ liệu ứng dụng trong gói. Bằng 0 là gói chỉ điều khiển (SYN, ACK…)tcp.len > 0
http.request.methodHTTP (phần A1)Method của request: GET, POST…Chuỗi: http.request.method == "POST"
http.request.uriHTTPĐường dẫn trong requesthttp.request.uri == "/dong-phi"
http.hostHTTPGiá trị header Hosthttp.host contains "example"
http.cookieHTTPGiá trị header Cookiehttp.cookie contains "phien="
http.response.codeHTTPMã trạng thái của response (200, 404…)Số: http.response.code == 404
tls.handshake.typeTLS (phần C1)Loại thông điệp bắt tay: 1 = Client Hello, 2 = Server Hello, 11 = Certificate, 20 = FinishedSố: tls.handshake.type == 1
tls.handshake.extensions_server_nameTLSTên miền mà client xin kết nối (SNI), nằm chữ rõ trong Client Hellotls.handshake.extensions_server_name == "localhost"
dns.qry.nameDNS (phần B1)Tên miền đang được hỏidns.qry.name == "example.com"

Toán tử (đặt giữa tên trường và giá trị) và cách ghép nhiều điều kiện:

Toán tửCách viết khácNghĩaVí dụ
==eqBằngtcp.port == 8000
!=neKhác. Với trường có thể xuất hiện hai lần như ip.addr, nên viết !(ip.addr == 1.2.3.4) thay vì ip.addr != 1.2.3.4tcp.port != 22
> < >= <=gt lt ge leSo sánh sốframe.len >= 500
containsCó chứa chuỗi con, phân biệt hoa thườngframe contains "Cookie"
matches~Khớp biểu thức chính quyhttp.host matches "^clb\."
in {…}Thuộc một tập giá trị, các giá trị cách nhau bằng dấu cáchtcp.port in {8000 8443}
&&andVà: cả hai điều kiện cùng đúnghttp && tcp.port == 8000
||orHoặc: một trong hai đúngtcp.port == 8000 || tcp.port == 8443
!notPhủ định cả điều kiện đứng sau!tls
( )Nhóm điều kiện để rõ thứ tự(tcp.port == 8000 || tcp.port == 8443) && tcp.len > 0

Mổ xẻ một bộ lọc dài:

BỘ LỌC
http.request.method == "POST" && tcp.dstport == 8000 && frame contains "demo123"
MảnhĐọc là
http.request.method == "POST"Gói là request HTTP có method POST
&& tcp.dstport == 8000và đang đi tới port 8000, tức chiều client gửi lên server
&& frame contains "demo123"và trong dữ liệu có nguyên văn chuỗi demo123 (cookie giả)

Kết quả: đúng gói request của Lan có cookie, bỏ qua mọi gói khác. Nếu bộ lọc này không trả về dòng nào khi bạn bắt HTTPS, đó chính là bằng chứng dữ liệu đã được mã hóa.

Cột Info: các cờ TCP bạn sẽ gặp

Cờ trong ngoặc vuôngNghĩaGặp ở đâu
[SYN]Client xin mở kết nốiGói đầu của bắt tay ba bước
[SYN, ACK]Server đồng ý và xác nhậnGói thứ hai
[ACK]Xác nhận đã nhậnGói thứ ba, và sau mỗi lần nhận dữ liệu
[PSH, ACK]Có dữ liệu ứng dụng, đẩy lên ngay. Request và response HTTP nằm ở các gói nàyGói mang GET, POST, 200 OK
[FIN, ACK]Một bên báo đóng kết nối bình thườngCuối cuộc hội thoại
[RST] hoặc [RST, ACK]Ngắt đột ngột; thường là port không có ai nghe hoặc bị từ chốiKhi gọi tới port đóng, ví dụ phép thử nhanh ở cuối bước 3
Đừng nhầm hai loại bộ lọcBộ lọc bắt gói (màn hình chào, cú pháp port 8000) quyết định gói nào được thu từ đầu; gói bị loại bỏ thì mất. Bộ lọc hiển thị (ô ②, cú pháp tcp.port == 8000) chỉ ẩn bớt dòng, gói vẫn còn trong bản capture. Học viên mới nên để ô capture filter trống và chỉ dùng bộ lọc hiển thị.
3f. Follow TCP Stream: đọc cả cuộc hội thoại như một đoạn chat

Đây là tính năng làm nên "khoảnh khắc ngộ ra" của lab. Một request và response thường rải qua nhiều gói; Follow TCP Stream ghép chúng lại. Chuột phải vào một dòng gói của luồng cần xem → Follow → TCP Stream (hoặc menu Analyze → Follow → TCP Stream, phím tắt ⌥⌘⇧T trên macOS, Ctrl + Alt + Shift + T trên Windows/Linux). Cửa sổ mới hiện ra:

PhầnÝ nghĩa
Chữ màu đỏDữ liệu client gửi đi (ví dụ request POST /dong-phi kèm cookie)
Chữ màu xanhDữ liệu server trả lại (response)
Ô "Entire conversation (… bytes)"Chọn xem cả hai chiều hoặc chỉ một chiều
Ô "Show as"Cách hiển thị: ASCII (mặc định, đọc chữ), Hex Dump, Raw… Dùng ASCII
Ô "Stream"Số thứ tự luồng. Đổi số để xem các luồng khác trong cùng bản capture
Ô "Find" và "Find Next"Tìm chuỗi trong cuộc hội thoại, ví dụ Cookie
Nút "Filter Out This Stream"Ẩn luồng này khỏi danh sách để tập trung vào luồng khác
Nút "Save as…" và "Print"Lưu hoặc in nội dung. Cẩn thận, nội dung chứa dữ liệu thật
Nút "Back" / "Close"Quay lại cửa sổ chính. Chú ý: Wireshark tự điền bộ lọc kiểu tcp.stream eq 3 vào ô ②, nên danh sách chỉ còn luồng đó. Muốn xem lại tất cả: xóa trắng ô ② rồi Enter

Với luồng HTTP ở port 8000, bạn đọc được trọn vẹn request và response. Với luồng HTTPS ở port 8443, cửa sổ chỉ hiện ký tự lộn xộn: đó là bằng chứng bằng mắt rằng nội dung đã được mã hóa.

3g. Phím tắt đáng nhớ
ViệcmacOSWindows / Linux
Bắt đầu / dừng bắt gói⌘ + ECtrl + E
Đưa con trỏ vào ô lọc hiển thị⌘ + /Ctrl + /
Tìm gói⌘ + FCtrl + F
Capture options⌘ + KCtrl + K
Follow TCP Stream⌥ ⌘ ⇧ TCtrl + Alt + Shift + T
Lưu bản capture⌘ + SCtrl + S
3h. Lỗi thường gặp khi dùng Wireshark
Dấu hiệuNguyên nhânCách xử lý
Khung vàng "don't have permission to capture"Chưa cài ChmodBPF (macOS) hoặc chưa vào nhóm wireshark (Linux)Làm bước 3a, thoát hẳn Wireshark rồi mở lại
Bắt gói chạy nhưng bảng trốngChọn sai giao diện (ví dụ Wi-Fi trong khi server chạy ở loopback), hoặc chưa có ai gọi serverNhìn thanh tiêu đề: phải là Capturing from Loopback: lo0. Dừng, bấm X về màn hình chào, chọn đúng loopback, bắt đầu lại rồi mới gõ lệnh curl
Có gói nhưng không thấy dòng HTTPBộ lọc quá hẹp, hoặc port saiXóa ô lọc rồi Enter; thử tcp.port == 8000. Luồng 8443 mà Protocol chỉ hiện TCP thì chuột phải → Decode As… → port 8443 → TLS
Ô lọc nền đỏ, Enter không chạySai cú phápDùng ==, đặt chuỗi trong ngoặc kép, xem gợi ý thả xuống
Số "Displayed" nhỏ hơn "Packets"Bộ lọc đang ẩn bớtBình thường; xóa ô lọc để hiện hết
Wireshark hỏi "Save packets before continuing?"Bạn bấm Start/Restart khi bản capture cũ chưa lưuChọn Continue without Saving nếu không cần giữ
Với HTTPS vẫn không đọc được nội dungĐúng như thiết kế: người bắt gói không có khóa phiênĐây là kết quả mong muốn của lab, không phải lỗi
Giữ an toàn khi dùng WiresharkChỉ bắt gói trên máy và mạng của bạn hoặc nơi được cho phép. Khi bắt trên Wi-Fi thật, Wireshark thu cả lưu lượng của các ứng dụng khác trong máy bạn; đóng bớt ứng dụng và đừng đăng nhập thứ nhạy cảm. Lưu file .pcapng chứa dữ liệu thật, nên xóa khi xong. Ở lab này chỉ dùng loopback và dữ liệu giả nên rất an toàn.
Kiểm tra nhanh trước khi sang bước 4Mở Wireshark, nhấp đúp Loopback: lo0. Trong lúc đó chạy curl http://127.0.0.1:1 ở một terminal (lệnh này báo lỗi kết nối bị từ chối, bình thường). Quay lại, bạn thấy vài dòng TCP với cờ [SYN] và [RST, ACK]: bạn đã bắt được gói đầu tiên. Bấm hình vuông đỏ để dừng. Nếu thấy dòng, mọi thứ đã sẵn sàng.

Bước 4. Bắt gói và đọc chữ rõ bằng Wireshark

Server vẫn chạy ở Terminal A. Giờ ta quan sát những gì thực sự chạy trên dây (ở đây là giao diện loopback). Tên giao diện loopback tùy hệ điều hành:

Hệ điều hànhGiao diện loopback trong Wireshark
macOSLoopback: lo0
LinuxLoopback: lo (hoặc lo)
WindowsAdapter for loopback traffic capture (Npcap; tên có thể khác theo phiên bản)
  1. Mở Wireshark. Ở màn hình đầu, nhấp đúp vào giao diện loopback ở bảng trên. Đường sóng bên cạnh tên sẽ nhảy lên và gói bắt đầu hiện. Nếu chưa có gói nào, đừng lo, chưa có ai gọi server. Kiểm tra thanh tiêu đề cửa sổ: phải ghi Capturing from Loopback: lo0. Nếu ghi Wi-Fi: en0 là bạn đang bắt sai giao diện: gói gửi tới 127.0.0.1 không bao giờ đi qua Wi-Fi nên bảng sẽ trống mãi. Khi đó bấm hình vuông đỏ, bấm nút X để về màn hình chào rồi chọn lại loopback. Nếu bạn chạy server ở port khác 8000 thì sửa luôn bộ lọc cho khớp port đó.
  2. Ở Terminal B, gửi một request có kèm cookie giả (cookie là đoạn "bằng chứng đã đăng nhập" của bài 3, ở đây chỉ là dữ liệu giả):
TERMINAL B
curl -H "Cookie: phien=demo123" http://127.0.0.1:8000/
PhầnÝ nghĩa
curlGửi một request HTTP và in response ra màn hình.
-H "Cookie: phien=demo123"-H thêm một header vào request. Ở đây ta thêm header Cookie với giá trị giả phien=demo123.
http://127.0.0.1:8000/Địa chỉ đích: máy này, port 8000, đường dẫn /. Phần http:// cho biết đây là HTTP thường, không mã hóa.
  1. Quay lại Wireshark, bấm nút hình vuông đỏ (Stop) để dừng bắt gói.
  2. Gõ vào ô lọc phía trên cùng (nền chuyển xanh lá là cú pháp đúng) rồi nhấn Enter:
Ô LỌC CỦA WIRESHARK
tcp.port == 8000

Đây là : chỉ ẩn bớt dòng, không xóa gói. Bạn sẽ thấy khoảng chục dòng: ba gói đầu là bắt tay TCP (SYN, SYN, ACK, ACK, phần B3), tiếp theo là dòng HTTP GET / HTTP/1.1, dòng HTTP/1.0 200 OK, rồi các gói đóng kết nối.

  1. Nhấp vào dòng GET / HTTP/1.1. Ở khung giữa, mở mục Hypertext Transfer Protocol để thấy từng header.
  2. Chuột phải vào dòng đó, chọn Follow → TCP Stream (hoặc menu Analyze → Follow → TCP Stream). Wireshark ghép các gói thành cuộc hội thoại: chữ đỏ là client gửi, chữ xanh là server trả.
CỬA SỔ FOLLOW TCP STREAM (MINH HỌA)
GET / HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: curl/8.7.1
Accept: */*
Cookie: phien=demo123

HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.9.6
Content-type: text/html
Content-Length: 37

<h1>Cau lac bo - Lich sinh hoat</h1>

Dòng Cookie: phien=demo123 nằm đó, đọc được nguyên văn. Với một cookie phiên thật, bất kỳ thiết bị nào nhìn thấy gói này cũng có thể dùng lại nó. Nếu không thấy gói: kiểm tra đã chọn đúng giao diện loopback, Terminal A còn chạy, và capture đã bắt đầu trước khi gõ lệnh curl (gói đã đi qua trước đó thì không bắt lại được). Bảng dưới là dữ liệu minh họa đã giản lược (không phải capture từ máy bạn); bấm một dòng để xem giải thích.

LOOPBACK · 127.0.0.16 dòng minh họa
No.ProtocolSource portDest. portInfo · Chọn để xem
Không cài được Wireshark?Trên macOS và Linux, xem gói ngay trong terminal bằng tcpdump. Mở một terminal, gõ sudo tcpdump -i lo0 -A -s 0 "tcp port 8000" (Linux đổi lo0 thành lo), nhập mật khẩu máy, rồi chạy lệnh curl ở terminal khác. -i chọn giao diện, -A in nội dung gói dạng chữ, -s 0 lấy trọn gói. Cookie hiện ngay trên màn hình. Dừng bằng Ctrl+C.

Bước 5. Mô phỏng Lan bấm "Đóng phí" (gửi dữ liệu bằng POST)

Ở bước 4 bạn mới bắt request GET. Tình huống của bài là Lan gửi tên và số tiền, tức POST có body. Server Python mặc định không nhận POST, nên ta viết một server nhỏ hơn, dài chừng 40 dòng, dùng chung cho cả hai lab.

Trước hết dừng server cũ: ở Terminal A nhấn Ctrl + C (port 8000 phải được giải phóng). Rồi tạo file server.py trong thư mục network-lab. Cách nhanh nhất là dán lệnh sau vào terminal (nhấn nút Sao chép):

MACOS: TẠO server.py
cat > server.py <<'EOF'
# server.py - web server thu nghiem cho bai 6. Chi nghe tren may cua ban.
# Chay HTTP:   python3 server.py        (port 8000)
# Chay HTTPS:  python3 server.py --tls  (port 8443, can cert.pem va key.pem)
import ssl
import sys
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs

USE_TLS = "--tls" in sys.argv
PORT = 8443 if USE_TLS else 8000


class Handler(BaseHTTPRequestHandler):
    def reply(self, status, body):
        self.send_response(status)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def do_GET(self):
        try:
            with open("index.html", "rb") as f:
                self.reply(200, f.read())
        except FileNotFoundError:
            self.reply(404, b"Khong tim thay index.html. Hay chay server trong thu muc network-lab.")

    def do_POST(self):
        size = int(self.headers.get("Content-Length", 0))
        fields = parse_qs(self.rfile.read(size).decode("utf-8"))
        print("  Cookie server nhan duoc :", self.headers.get("Cookie"))
        print("  Du lieu server nhan duoc:", fields)
        self.reply(200, b"<h1>Da nhan phi cua Lan</h1>")


server = HTTPServer(("127.0.0.1", PORT), Handler)
if USE_TLS:
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    context.load_cert_chain("cert.pem", "key.pem")
    server.socket = context.wrap_socket(server.socket, server_side=True)
scheme = "https" if USE_TLS else "http"
print(f"Dang chay tai {scheme}://127.0.0.1:{PORT}/  (Ctrl+C de dung)")
server.serve_forever()
EOF
WINDOWS POWERSHELL: TẠO server.py
@'
# server.py - web server thu nghiem cho bai 6. Chi nghe tren may cua ban.
# Chay HTTP:   python3 server.py        (port 8000)
# Chay HTTPS:  python3 server.py --tls  (port 8443, can cert.pem va key.pem)
import ssl
import sys
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs

USE_TLS = "--tls" in sys.argv
PORT = 8443 if USE_TLS else 8000


class Handler(BaseHTTPRequestHandler):
    def reply(self, status, body):
        self.send_response(status)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def do_GET(self):
        try:
            with open("index.html", "rb") as f:
                self.reply(200, f.read())
        except FileNotFoundError:
            self.reply(404, b"Khong tim thay index.html. Hay chay server trong thu muc network-lab.")

    def do_POST(self):
        size = int(self.headers.get("Content-Length", 0))
        fields = parse_qs(self.rfile.read(size).decode("utf-8"))
        print("  Cookie server nhan duoc :", self.headers.get("Cookie"))
        print("  Du lieu server nhan duoc:", fields)
        self.reply(200, b"<h1>Da nhan phi cua Lan</h1>")


server = HTTPServer(("127.0.0.1", PORT), Handler)
if USE_TLS:
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    context.load_cert_chain("cert.pem", "key.pem")
    server.socket = context.wrap_socket(server.socket, server_side=True)
scheme = "https" if USE_TLS else "http"
print(f"Dang chay tai {scheme}://127.0.0.1:{PORT}/  (Ctrl+C de dung)")
server.serve_forever()
'@ | Set-Content -Path server.py -Encoding ascii
LINUX: TẠO server.py
cat > server.py <<'EOF'
# server.py - web server thu nghiem cho bai 6. Chi nghe tren may cua ban.
# Chay HTTP:   python3 server.py        (port 8000)
# Chay HTTPS:  python3 server.py --tls  (port 8443, can cert.pem va key.pem)
import ssl
import sys
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs

USE_TLS = "--tls" in sys.argv
PORT = 8443 if USE_TLS else 8000


class Handler(BaseHTTPRequestHandler):
    def reply(self, status, body):
        self.send_response(status)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def do_GET(self):
        try:
            with open("index.html", "rb") as f:
                self.reply(200, f.read())
        except FileNotFoundError:
            self.reply(404, b"Khong tim thay index.html. Hay chay server trong thu muc network-lab.")

    def do_POST(self):
        size = int(self.headers.get("Content-Length", 0))
        fields = parse_qs(self.rfile.read(size).decode("utf-8"))
        print("  Cookie server nhan duoc :", self.headers.get("Cookie"))
        print("  Du lieu server nhan duoc:", fields)
        self.reply(200, b"<h1>Da nhan phi cua Lan</h1>")


server = HTTPServer(("127.0.0.1", PORT), Handler)
if USE_TLS:
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    context.load_cert_chain("cert.pem", "key.pem")
    server.socket = context.wrap_socket(server.socket, server_side=True)
scheme = "https" if USE_TLS else "http"
print(f"Dang chay tai {scheme}://127.0.0.1:{PORT}/  (Ctrl+C de dung)")
server.serve_forever()
EOF

Kiểm tra bằng ls (macOS/Linux) hoặc dir (Windows): thư mục phải có index.html và server.py. Cũng có thể tạo bằng trình soạn thảo: dán nguyên đoạn Python vào, lưu với tên server.py (cùng lưu ý về Notepad và TextEdit ở bước 1). Ý nghĩa các phần chính của file:

PhầnÝ nghĩa
HTTPServer(("127.0.0.1", PORT), Handler)Tạo server nghe ở loopback, port 8000 (hoặc 8443 khi có --tls ở Lab 2). Mỗi request đến được giao cho lớp Handler xử lý.
do_GETHàm chạy khi có request GET: đọc file index.html và trả về với mã 200. Không có file thì trả 404.
do_POSTHàm chạy khi có request POST: đọc đúng Content-Length byte của body, tách thành các cặp tên=giá trị, rồi in cookie và dữ liệu ra terminal. Server nào cũng phải làm việc tương tự để nhận form.
parse_qsTách chuỗi ten=Lan&so_tien=200000 thành từng trường, giống cách form HTML được gửi.
--tls (dùng ở Lab 2)Khi có tham số này, server bọc socket bằng TLS và chạy HTTPS ở port 8443.

Chạy server mới ở Terminal A, rồi gửi POST từ Terminal B khi Wireshark đang bắt gói (bấm Start lại trên loopback; nếu Wireshark hỏi lưu bản capture cũ thì chọn Continue without Saving):

TERMINAL A
python3 server.py
TERMINAL A
py server.py
TERMINAL A
python3 server.py
TERMINAL B
curl -i -X POST -H "Cookie: phien=demo123" -d "ten=Lan&so_tien=200000&ghi=ok" http://127.0.0.1:8000/dong-phi
PhầnÝ nghĩa
-iIn cả header của response, để thấy mã trạng thái.
-X POSTDùng method POST thay cho GET mặc định.
-H "Cookie: phien=demo123"Header Cookie giả, đóng vai mã phiên đăng nhập của Lan.
-d "ten=Lan&so_tien=200000&ghi=ok"-d là data: nội dung body. curl tự đặt Content-Length và Content-Type kiểu form như request ở phần A1.
.../dong-phiĐường dẫn xử lý việc đóng phí, giống request minh họa ở phần A1.
KẾT QUẢ MONG ĐỢI Ở TERMINAL A (SERVER)
Dang chay tai http://127.0.0.1:8000/  (Ctrl+C de dung)
  Cookie server nhan duoc : phien=demo123
  Du lieu server nhan duoc: {'ten': ['Lan'], 'so_tien': ['200000'], 'ghi': ['ok']}
127.0.0.1 - - [19/Oct/2026 20:05:47] "POST /dong-phi HTTP/1.1" 200 -
KẾT QUẢ MONG ĐỢI Ở TERMINAL B (CLIENT)
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.9.6
Content-Type: text/html; charset=utf-8
Content-Length: 28

<h1>Da nhan phi cua Lan</h1>

Dừng capture, lọc tcp.port == 8000, chuột phải vào dòng POST /dong-phi → Follow → TCP Stream. Bạn đọc được cả Cookie: phien=demo123 lẫn body ten=Lan&so_tien=200000&ghi=ok. Server nhận được dữ liệu vì nó là một đầu của kết nối; nhưng bất cứ ai nằm giữa đường cũng đọc được y hệt, và với HTTP thì còn sửa được trước khi tới server. Phần C sẽ chặn việc này.

BÀI TẬP 2 · 10 PHÚT

Tìm chữ rõ trong capture của chính bạn

Trong cửa sổ Follow TCP Stream của lần bắt gói POST, ghi lại:

  1. Port nguồn (port tạm của client) và port đích.
  2. Dòng request đầu tiên và dòng đầu của response (mã trạng thái).
  3. Dòng Cookie bạn đã gửi: có đọc được không?
  4. Nội dung body của request và nội dung body của response.
  5. Dùng ô lọc frame contains "demo123" (thay cho tcp.port == 8000). Còn bao nhiêu gói hiện ra, và vì sao đó là bằng chứng của chữ rõ?

Sau đó dừng capture và server (Ctrl+C), xóa file capture nếu không cần: file PCAP có thể chứa dữ liệu của luồng khác.

Xem đáp án
  1. Port đích là 8000; port nguồn là số ngẫu nhiên cao (thường trên 49152), mỗi lần chạy khác nhau.
  2. POST /dong-phi HTTP/1.1 và HTTP/1.0 200 OK (server Python trả HTTP/1.0; curl gửi 1.1, hai bên có thể khác phiên bản).
  3. Đọc được nguyên văn Cookie: phien=demo123. Đây chính là điều bất kỳ ai trên đường đi cũng làm được với HTTP.
  4. Body request: ten=Lan&so_tien=200000&ghi=ok. Body response: <h1>Da nhan phi cua Lan</h1>.
  5. Hiện ra gói (hoặc các gói) chứa request có cookie, vì chuỗi demo123 nằm nguyên văn trong dữ liệu gói. Nếu dữ liệu được mã hóa, chuỗi đó không xuất hiện và bộ lọc không tìm thấy gì; Lab 2 kiểm tra đúng điều này.

Kết luận phần A: HTTP không mã hóa lộ mọi thứ. Phần B xem ai nằm trên đường đi, phần C cách chặn.

04

B1. Đường đi (1): DNS tìm địa chỉ máy chủ

8 phút
clb.exampleTên người dùng gõ
Bộ phân giải DNSTra hoặc dùng cache
203.0.113.10IP trả về

Phần A dùng địa chỉ số trực tiếp. Trên Internet, Lan gõ tên, nên trước tiên máy phải đổi tên thành IP. Việc này do làm: nhận câu hỏi, dùng kết quả đã lưu () hoặc hỏi tiếp các máy chủ DNS.

Thông tinVí dụÝ nghĩa
Tên hỏiclb.exampleTên đang cần tra
Loại bản ghiA (IPv4), AAAA (IPv6)Loại thông tin cần
Kết quả203.0.113.10Địa chỉ trả về (địa chỉ tài liệu, minh họa)
TTL300 giâyThời gian được phép lưu cache

Rủi ro bảo mật của DNS

  • DNS thông thường không mã hóa và không tự xác thực: ai ở giữa đường nhìn thấy tên website bạn truy cập, và nếu giả được câu trả lời (DNS spoofing) thì đưa được người dùng tới máy chủ giả.
  • Kẻ chiếm được tài khoản nhà đăng ký tên miền (bài 2) sửa được bản ghi A và chuyển cả website sang máy chủ của họ. Cần MFA và quyền tối thiểu cho tài khoản này.
  • Tra được IP chưa chứng minh trang tải được, hay đúng là trang mong muốn.

BÀI TẬP 3 · 5 PHÚT

Quan sát DNS và nghĩ như kẻ tấn công

Chạy hai lần liên tiếp:

TERMINAL
nslookup example.com
dig example.com
  1. Ghi IP và TTL (dig hiện TTL ở cột thứ hai). Lần chạy thứ hai TTL có giảm không? Vì sao?
  2. Nếu kẻ tấn công sửa được bản ghi A của clb.example, Lan gõ đúng tên vẫn thấy gì? Tài khoản nào cần được bảo vệ?
Xem đáp án
  1. TTL thường giảm dần vì kết quả đang nằm trong cache của resolver và đếm ngược tới khi hết hạn. Hết TTL thì tra lại.
  2. Lan vào một máy chủ do kẻ tấn công điều khiển, có thể là bản sao giống hệt trang thật để lấy tiền hoặc mật khẩu. Cần bảo vệ tài khoản ở nhà đăng ký tên miền và DNS (MFA, quyền tối thiểu, theo dõi thay đổi bản ghi). Ngoài ra HTTPS (phần C) giúp trình duyệt nhận ra máy chủ không đúng chủ tên miền.
05

B2. Đường đi (2): router và NAT

10 phút
Laptop192.168.1.10:51514
Router / NAT198.51.100.25:62001
Máy chủ203.0.113.10:443

Biết IP máy chủ rồi, gói tin rời mạng nhà qua . Router có hai việc đáng chú ý về bảo mật.

Việc 1: dịch địa chỉ (NAT)

IP riêng như 192.168.1.10 không dùng trực tiếp trên Internet. Khi gói đi ra, router thực hiện : thay địa chỉ nguồn bằng IP công cộng của router. Nhiều thiết bị chung một IP công cộng nên router còn đổi cả port () và ghi vào bảng ánh xạ:

Kết nối bên trongÁnh xạ bên ngoàiĐích
192.168.1.10:51514198.51.100.25:62001203.0.113.10:443
192.168.1.11:51514198.51.100.25:62002203.0.113.10:443

Hai máy cùng dùng port 51514 vẫn được tách nhờ hai port ngoài khác nhau. Khi server trả lời về 62001 hoặc 62002, router tra bảng và chuyển về đúng máy.

Việc 2: là điểm mọi gói đều đi qua

Router (và mọi thiết bị trên đường: Wi-Fi công cộng, nhà mạng, thiết bị trung gian) thấy được IP, port và với HTTP cả nội dung. Router bị chiếm thì kẻ tấn công đọc và sửa được lưu lượng chưa mã hóa (tấn công kẻ đứng giữa, ). Vì vậy: đổi mật khẩu quản trị mặc định của router, cập nhật firmware, và đừng tin Wi-Fi lạ cho dữ liệu nhạy cảm.

NAT không phải tường lửaHệ quả phụ của NAT là kết nối mới từ ngoài vào thường không có ánh xạ nên bị bỏ, nhưng đó không phải chính sách bảo mật có chủ đích. Mạng nhà còn có thể nằm sau của nhà mạng, và IPv6 thường không dùng NAT. Việc kiểm soát thật sự là của tường lửa (phần B3).

BÀI TẬP 4 · 10 PHÚT

Đọc bảng NAT và đối chiếu với máy bạn

Phần 1 (trên giấy). Dùng bảng NAT ở trên:

  1. Một gói từ 203.0.113.10:443 đến 198.51.100.25:62002. Router chuyển nó về đâu?
  2. Một gói lạ từ 192.0.2.77:4444 đến 198.51.100.25:62999. Chuyện gì xảy ra và vì sao?

Phần 2 (trên máy bạn). Dùng lệnh ở bài 5 để ghi IP riêng và gateway của máy. Tùy chọn: chạy curl https://ifconfig.me để xem IP công cộng của bạn và so với IP riêng.

Xem đáp án

Phần 1.

  1. Về 192.168.1.11:51514, vì bảng ghi 62002 tương ứng với máy .11.
  2. Bị bỏ: không có ánh xạ nào cho port 62999 nên router không biết chuyển cho máy nào. Đây là lý do mạng nhà ít bị "gõ cửa" từ ngoài, nhưng cần firewall để chủ động chặn.

Phần 2. IP riêng thường dạng 192.168.x.x hoặc 10.x.x.x; IP công cộng là địa chỉ khác hẳn và chung cho mọi thiết bị trong nhà (hoặc cả nhiều nhà nếu có CGNAT). Gateway thường là 192.168.x.1.

06

B3. Đường đi (3): firewall và TCP

12 phút
SYNClient xin kết nối
SYN/ACKServer đồng ý
ACKClient xác nhận

Tường lửa

cho phép hoặc chặn lưu lượng theo quy tắc (IP, port, giao thức, trạng thái kết nối). Nguyên tắc: chặn mặc định, chỉ mở thứ cần thiết (default deny). Mỗi port mở ra ngoài là một điểm có thể bị tấn công. Ví dụ quy tắc cho máy chủ của câu lạc bộ:

Thứ tựHành độngĐến portTừ
1Cho phép443 (HTTPS)Mọi nơi
2Cho phép22 (quản trị từ xa SSH)Chỉ 203.0.113.50 (máy của quản trị viên)
3ChặnTất cả port còn lạiMọi nơi

Kết nối chỉ thành công khi nhiều lớp cùng đúng: có đường đi, firewall không chặn, có chương trình đang lắng nghe đúng IP và port, hai bên nói giao thức tương thích, và ứng dụng cho phép yêu cầu. Vì vậy "mở port", "chạy server" và "cấp quyền sửa dữ liệu" là ba việc khác nhau. Mở port 8000 không tạo ra web server; server chỉ lắng nghe 127.0.0.1 thì máy khác không vào được dù firewall đã mở.

TCP: bắt tay ba bước

cho luồng byte đúng thứ tự, truyền lại phần bị mất. Trước khi gửi dữ liệu, hai bên làm : SYN (client xin kết nối) → SYN/ACK (server đồng ý) → ACK (client xác nhận). Chỉ sau đó HTTP mới bắt đầu chạy bên trên.

  • Bắt tay TCP không mã hóa. Kết nối HTTP vẫn dùng TCP, nội dung vẫn là chữ rõ.
  • Server phải giữ trạng thái cho mỗi kết nối đang bắt tay dở. Kẻ tấn công gửi rất nhiều SYN mà không hoàn tất (SYN flood) làm cạn tài nguyên: một dạng . Phòng bằng giới hạn tốc độ và cơ chế chống SYN flood của hệ điều hành hoặc nhà cung cấp.
  • TCP có thể chuyển đúng request mà ứng dụng vẫn trả 403 hay 404. TCP không biết gì về nghiệp vụ.

Ghi chú: gửi từng gói rời, không bảo đảm đủ và đúng thứ tự. chạy trên UDP nhưng có độ tin cậy và TLS tích hợp, là nền của HTTP/3, nên thấy UDP cổng 443 không tự là dấu hiệu tấn công.

BÀI TẬP 5 · 10 PHÚT

Quyết định của firewall và đọc dấu hiệu SYN flood

Phần 1. Dùng bộ quy tắc ở trên, quyết định cho phép hay chặn:

  1. Gói từ 198.51.100.9 đến cổng 443.
  2. Gói từ 198.51.100.9 đến cổng 22.
  3. Gói từ 203.0.113.50 đến cổng 22.
  4. Gói từ 203.0.113.50 đến cổng 3306 (cơ sở dữ liệu).

Phần 2. Đọc đoạn capture phía server (rút gọn) và cho biết đâu là bắt tay bình thường, đâu đáng ngờ:

CAPTURE MINH HỌA
1  192.0.2.10:40001 -> server:443  SYN
2  server:443 -> 192.0.2.10:40001  SYN/ACK
3  192.0.2.10:40001 -> server:443  ACK
4  192.0.2.21:50110 -> server:443  SYN
5  192.0.2.22:50111 -> server:443  SYN
6  192.0.2.23:50112 -> server:443  SYN
7  192.0.2.24:50113 -> server:443  SYN
(... hàng nghìn dòng SYN từ nhiều IP, không có ACK ...)
Xem đáp án

Phần 1.

  1. Cho phép (quy tắc 1).
  2. Chặn (quy tắc 2 chỉ cho 203.0.113.50, rơi xuống quy tắc 3).
  3. Cho phép (quy tắc 2).
  4. Chặn (không có quy tắc cho 3306, rơi xuống chặn mặc định). Cơ sở dữ liệu không nên mở ra ngoài.

Phần 2. Dòng 1 đến 3 là bắt tay bình thường đủ ba bước. Dòng 4 trở đi: rất nhiều SYN từ nhiều IP khác nhau, server trả SYN/ACK nhưng không nhận ACK, kết nối treo dở. Đó là dấu hiệu SYN flood (tấn công từ chối dịch vụ). Cách ứng phó: bật SYN cookies hoặc bảo vệ chống DoS của nhà cung cấp, giới hạn tốc độ, ghi lại thời điểm và log để báo cáo (bài 4).

07

B4. Lab 3: nhìn mạng nhà mình từ trong và từ ngoài

15 phút
Laptop trong nhà192.168.1.23 · IP nội bộ
Router (NAT)WAN 203.0.113.77 · IP công cộng
InternetMáy bên ngoài chỉ thấy IP công cộng

Lab này dùng chính mạng nhà bạn để trả lời ba câu hỏi: trong nhà đang có thiết bị nào, mỗi thiết bị có IP và port gì; IP công cộng của nhà là gì; và có thiết bị nào "chìa ra" Internet mà không cần thiết không. Nhớ lại bài 5 và phần B2: các thiết bị trong nhà dùng IP nội bộ (thường 192.168.x.x, 10.x.x.x), còn router dùng một IP công cộng duy nhất để nói với Internet.

Mỗi bước có tab cho macOS, Windows và Linux. Chọn tab đúng với máy bạn. Dưới mỗi khối lệnh có bảng giải thích từng phần của lệnh, để bạn đổi được tham số khi cần.

Bước 0. Cài công cụ nmap

nmap là công cụ quét mạng miễn phí, dùng xuyên suốt lab. Cài một lần:

MACOS (HOMEBREW)
brew install nmap
WINDOWS
Tải bộ cài tại https://nmap.org/download.html, chạy file .exe và giữ tùy chọn cài Npcap
LINUX (UBUNTU / DEBIAN)
sudo apt install nmap
# Fedora: sudo dnf install nmap
PhầnÝ nghĩa
brew install nmapbrew là Homebrew, trình quản lý gói của macOS. install nmap cài gói tên nmap. Chưa có Homebrew thì cài theo brew.sh.
sudoChạy lệnh với quyền quản trị. Linux sẽ hỏi mật khẩu máy. Lệnh cài đặt cần quyền này.
apt install / dnf installTrình quản lý gói của Ubuntu/Debian (apt) và Fedora (dnf). Lệnh tải và cài nmap từ kho chính thức của hệ điều hành.
NpcapDriver bắt gói trên Windows. Nmap cần nó để quét chính xác. Bộ cài nmap có sẵn tùy chọn này.

Bước 1. Tìm IP của máy mình và của router

Router là của mạng nhà: mọi gói ra ngoài đi qua nó. Chạy lệnh theo hệ điều hành của bạn:

MACOS (WI-FI THƯỜNG LÀ en0)
ipconfig getifaddr en0
route -n get default | grep gateway
WINDOWS (POWERSHELL HOẶC CMD)
ipconfig
# Xem dòng "IPv4 Address" (IP máy) và "Default Gateway" (router)
LINUX
ip -4 addr show
ip route | grep default
PhầnÝ nghĩa
ipconfig getifaddr en0ipconfig: lệnh xem cấu hình mạng trên macOS. getifaddr: lấy địa chỉ của một giao diện. en0: tên giao diện Wi-Fi trên đa số Mac. Nếu lệnh không ra IP, chạy ifconfig để tìm giao diện có inet 192.168.x.x rồi thay en0 bằng tên đó (ví dụ en1).
route -n get defaultroute: xem bảng định tuyến. -n: không đổi IP thành tên miền, cho ra nhanh hơn. get default: hỏi tuyến mặc định, tức đường đi ra Internet.
| grep gatewayDấu | đưa kết quả lệnh trước vào lệnh sau. grep gateway chỉ giữ dòng có chữ gateway. Dòng đó chứa IP của router.
ipconfig (Windows)Không có tham số thì in mọi card mạng. Tìm mục Wi-Fi (Wireless LAN adapter Wi-Fi): IPv4 Address là IP máy, Default Gateway là router. Thêm /all để xem thêm DNS và MAC.
ip -4 addr showip: công cụ mạng của Linux. -4: chỉ hiện địa chỉ IPv4. addr show: hiện địa chỉ của các giao diện. Đọc dòng inet 192.168.1.23/24: 192.168.1.23 là IP máy, /24 là độ dài phần mạng.
ip route | grep defaultip route: in bảng định tuyến. Dòng default via 192.168.1.1 cho biết 192.168.1.1 là gateway. grep default chỉ giữ dòng đó.

Ghi lại hai số: IP máy (ví dụ 192.168.1.23) và gateway (ví dụ 192.168.1.1).

Bước 2. Liệt kê thiết bị đang "quen mặt" với máy bạn

Lệnh arp -a chạy được trên cả ba hệ điều hành. Nó in bảng ARP: cặp IP và MAC của các thiết bị mà máy bạn vừa trao đổi gói tin với nó. Đây không phải danh sách đầy đủ, vì máy chỉ biết những thiết bị đã nói chuyện với nó.

MACOS
arp -a
WINDOWS
arp -a
LINUX
arp -a
# Hoặc (không cần net-tools): ip neigh
PhầnÝ nghĩa
arp -aarp: xem bảng ARP (ánh xạ IP sang MAC). -a: hiện mọi mục. Mỗi dòng gồm IP, MAC và loại (dynamic: tự học từ mạng).
ip neigh (Linux)Cùng việc với arp -a, dùng công cụ ip hiện đại. Hữu ích khi máy không có lệnh arp.

Để thấy đầy đủ hơn, dùng nmap quét ping toàn mạng. Thay dải mạng bằng dải của nhà bạn:

MỌI HỆ ĐIỀU HÀNH (MACOS / LINUX: THÊM sudo ĐỂ KẾT QUẢ ĐẦY ĐỦ HƠN)
nmap -sn 192.168.1.0/24
PhầnÝ nghĩa
nmapCông cụ quét mạng đã cài ở bước 0.
-snPing scan: chỉ hỏi xem IP nào đang bật, không quét port. Nhanh và nhẹ.
192.168.1.0/24Dải mạng. /24 nghĩa là 256 địa chỉ từ .0 đến .255. Đổi theo IP máy ở bước 1: nếu máy là 10.0.0.15 thì dải là 10.0.0.0/24.
sudo (Mac, Linux)Quyền quản trị giúp nmap dùng ARP, thấy được nhiều thiết bị hơn. Windows: mở PowerShell hoặc CMD bằng quyền Administrator.
Host is upDòng xuất hiện khi thiết bị đang bật và trả lời.

Kết quả mẫu (đã rút gọn, địa chỉ minh họa):

KẾT QUẢ MẪU
Nmap scan report for 192.168.1.1   (router)
Host is up.
Nmap scan report for 192.168.1.23  (máy của bạn)
Host is up.
Nmap scan report for 192.168.1.40  (điện thoại?)
Host is up.
Nmap done: 256 IP addresses (3 hosts up)
Nếu không muốn dùng dòng lệnhCó thể dùng Angry IP Scanner (giao diện đồ họa, miễn phí) trên máy tính, hoặc Fing trên điện thoại. Cách nào cũng cho danh sách IP đang dùng và tên thiết bị nếu máy đó tự khai.

Bước 3. Xem từng thiết bị đang mở port nào

Với một IP trong nhà mà bạn sở hữu (ví dụ máy của chính bạn), quét các port phổ biến và đoán dịch vụ. Lệnh giống nhau trên ba hệ điều hành:

MỌI HỆ ĐIỀU HÀNH
nmap -sV --top-ports 100 192.168.1.23
PhầnÝ nghĩa
nmapCông cụ quét mạng.
-sVVersion detection: cố đoán tên và phiên bản dịch vụ đang chạy ở mỗi port (ví dụ ssh, http). Chậm hơn một chút nhưng đọc kết quả dễ hơn.
--top-ports 100Chỉ quét 100 port phổ biến nhất thay vì mặc định khoảng 1000. Nhanh hơn. Muốn quét kỹ hơn thì bỏ tham số này.
192.168.1.23IP của thiết bị cần xem. Chỉ dùng IP máy bạn sở hữu.

Đọc kết quả từng dòng: 22/tcp open ssh nghĩa là port 22 đang có dịch vụ SSH chờ kết nối. Máy đang nghe ở port nào thì đó là điểm có thể bị gõ cửa, dù cùng mạng nhà. Nhớ rằng là số, còn dịch vụ là chương trình đứng sau số đó.

Bước 4. Tìm IP công cộng của nhà

Có hai cách và nên làm cả hai để đối chiếu:

  • Từ trang quản trị router: mục trạng thái Internet hoặc WAN ghi địa chỉ IP của router ra Internet. Đây là IP công cộng nếu nó không nằm trong dải nội bộ.
  • Từ một dịch vụ hiển thị IP: dùng lệnh dưới đây. Dịch vụ thấy IP bạn đang đi ra, nên trả về IP công cộng của mạng nhà.
MACOS / LINUX
curl ifconfig.me
WINDOWS
curl.exe ifconfig.me
LINUX
curl ifconfig.me
PhầnÝ nghĩa
curlCông cụ gửi yêu cầu HTTP từ dòng lệnh. Có sẵn trên macOS, Linux và Windows 10 trở lên.
curl.exe (Windows)Dùng tên đầy đủ để chắc chắn gọi curl thật. PowerShell có alias curl trỏ tới lệnh khác, nên gõ curl không đúng như mong đợi.
ifconfig.meDịch vụ trả về IP mà nó nhìn thấy khi bạn kết nối. Thay bằng api.ipify.org nếu dịch vụ này không phản hồi.

Nếu địa chỉ trên router là 100.64.x.x đến 100.127.x.x, hoặc khác với IP dịch vụ trả về, nhà có thể đang dùng : nhà mạng cho nhiều khách hàng dùng chung một IP. Khi đó bạn không thể mở port từ ngoài vào nhà bằng cách cấu hình router, vì IP công cộng không thuộc riêng nhà bạn.

Bước 5. Thử nhìn nhà mình từ ngoài

Muốn biết thiết bị nào đang chìa ra Internet, phải nhìn từ bên ngoài mạng nhà. Cách an toàn nhất: tắt Wi-Fi nhà, bật 4G hoặc phát hotspot từ điện thoại, rồi dùng laptop (đang ở mạng ngoài) quét IP công cộng của chính nhà bạn với một danh sách port ngắn. Lệnh giống nhau trên ba hệ điều hành:

MỌI HỆ ĐIỀU HÀNH (CHẠY TỪ MẠNG NGOÀI)
nmap -Pn -p 21,22,23,80,443,3389,8080 203.0.113.77
PhầnÝ nghĩa
-PnBỏ qua bước ping trước khi quét. Nhiều router và firewall không trả lời ping, nên nếu không có -Pn nmap có thể báo sai là máy tắt.
-p 21,22,23,80,443,3389,8080Danh sách port cần thử, cách nhau bằng dấu phẩy. Có thể dùng dải như 20-100. Không dùng -p- (quét cả 65535 port): lâu và dễ bị coi là hành vi tấn công.
203.0.113.77IP công cộng của nhà bạn (lấy ở bước 4). Đây là địa chỉ tài liệu, chỉ để minh họa; thay bằng IP thật của bạn.

Ý nghĩa các trạng thái port:

Trạng tháiNghĩaHướng xử lý
openCó dịch vụ đang nhận kết nối từ ngoàiNếu không chủ đích mở, tìm nguồn: port forwarding hoặc UPnP. Tắt dịch vụ hoặc chặn ở router
closedCó đường tới nhưng không có dịch vụ nghe ở port đóỔn. Không có gì để khai thác ở port này
filteredRouter hoặc firewall chặn, không trả lờiTốt, đúng nguyên tắc chặn mặc định
Lưu ý về UPnPNhiều router bật UPnP để game hay ứng dụng tự mở port ra ngoài. Một port mở từ ngoài mà không ai nhớ đã cấu hình thường là do UPnP. Kiểm tra danh sách port forwarding và UPnP trong trang quản trị router, rồi tắt những gì không cần.
Giới hạn của labChỉ quét IP công cộng của chính nhà bạn, một lần, với danh sách port ngắn như trên. Không quét dải IP của người khác, mạng trường hay công ty khi chưa được cho phép. Quét mạng người khác dù chỉ để "thử" có thể vi phạm pháp luật và điều khoản của nhà mạng. Nếu nhà mạng báo bất thường, dừng lại.

Kết luận phần B4

Mạng nhà có ba lớp cần nhìn: trong nhà (những IP nội bộ và port đang nghe), ranh giới (router và NAT, có phải CGNAT không), và ngoài Internet (port nào thấy được từ bên ngoài). Mục tiêu không phải không có port nào mở, mà là mọi port mở đều có lý do và có người chịu trách nhiệm.

BÀI TẬP 6 · 10 PHÚT

Lập sơ đồ mạng nhà

Với mạng nhà bạn (hoặc mạng thử của lớp):

  1. Ghi IP của máy bạn và IP gateway.
  2. Chạy arp -a và nmap -sn trên dải mạng. Lập bảng: IP, tên thiết bị (đoán được hay không), ghi chú.
  3. Chọn một thiết bị bạn sở hữu và liệt kê các port đang mở từ nmap -sV --top-ports 100.

Gợi ý: nếu thấy thiết bị không nhận ra, đừng vội kết luận là xấu. Nhiều điện thoại dùng MAC ngẫu nhiên nên tên và địa chỉ có thể lạ.

Xem đáp án
  1. IP máy lấy từ lệnh ipconfig hoặc ip addr. Gateway thường là .1, nhưng cần đối chiếu bằng lệnh vì không phải lúc nào cũng vậy.
  2. Bảng có thể có vài dòng: router, máy bạn, TV thông minh, máy in, điện thoại. Thiết bị không nhận ra thì tra MAC hoặc tạm ngắt Wi-Fi từng thiết bị để xem IP nào biến mất.
  3. Máy của bạn có thể mở port 5000 hoặc 7000 (AirPlay Receiver trên macOS) hoặc các port tương tự. Ghi lại dịch vụ và xác nhận bạn đang cần nó.

BÀI TẬP 7 · 10 PHÚT

Đọc kết quả quét từ ngoài

Bạn quét từ mạng 4G tới IP công cộng của nhà và nhận được:

PORT     STATE     SERVICE
22/tcp   open      ssh
80/tcp   filtered  http
443/tcp  closed    https
8080/tcp open      http-proxy
  1. Port nào cần xử lý ngay? Vì sao?
  2. Port 443 closed có nghĩa là website nhà đang bị lỗi hay không? Giải thích.
  3. Nếu WAN của router là 100.72.14.9, kết quả quét có còn ý nghĩa với việc mở port trên router không?
Xem đáp án
  1. Port 22 (SSH) và 8080 đang open từ Internet. Port 22 là cổng quản trị từ xa, nếu không cần thì đóng, nếu cần thì giới hạn IP được phép. Port 8080 thường là web quản trị hoặc dịch vụ thử nghiệm, cần xác nhận thiết bị nào đang trả lời và tắt hoặc chặn nếu không chủ đích. Đây là ưu tiên cao.
  2. Không nhất thiết. closed nghĩa là có đường tới nhưng không có dịch vụ nghe ở port 443 trên IP đó. Nếu website được đặt ở nơi khác (hosting, cloud) thì 443 của nhà đóng là đúng. Muốn chắc, hỏi lại: website đang chạy ở đâu?
  3. Không có ý nghĩa để mở port vào nhà. Với CGNAT, IP công cộng dùng chung nên cấu hình router không đảm bảo kết nối từ ngoài. Muốn truy cập từ xa, dùng VPN hoặc dịch vụ trung gian, không mở port ra Internet.
08

C1. TLS và HTTPS: biến chữ rõ thành chữ mã

8 phút
Kết nối TCPCó luồng dữ liệu
Bắt tay TLSThống nhất khóa, kiểm tra chứng chỉ
HTTP được mã hóaRequest và response

Phần A cho thấy vấn đề (chữ rõ), phần B cho thấy ai nằm trên đường đi. Giải pháp: , cơ chế mã hóa kênh truyền. là HTTP chạy bên trong kênh TLS, thường ở port 443. Sau khi TCP bắt tay xong, hai bên làm bắt tay TLS:

  1. Thống nhất phiên bản và thuật toán.
  2. Server gửi : gắn tên miền với khóa công khai, được ký bởi một tổ chức cấp chứng chỉ (CA) mà trình duyệt tin tưởng.
  3. Client kiểm tra: tên miền khớp, chưa hết hạn, chuỗi chứng chỉ dẫn tới CA tin cậy.
  4. Hai bên tạo khóa phiên chung và dùng khóa đó mã hóa mọi dữ liệu còn lại.

Kênh thiết lập xong cho ba bảo vệ, khớp với bài 1: bí mật (người ngoài không đọc được), toàn vẹn (sửa giữa đường bị phát hiện), xác thực máy chủ (đúng chủ của tên miền). Nhờ đó, request của Lan ở phần A1 đi qua router và nhà mạng dưới dạng dữ liệu mã hóa: người trung gian không đọc được cookie và không sửa được trang trả về mà không bị phát hiện.

HTTPS chưa giải quyết hết

HTTPS bảo vệHTTPS không bảo vệ
Nội dung, header, cookie trên đường truyềnNội dung website có trung thực hay không
Phát hiện bị sửa giữa đườngPhân quyền sai trong ứng dụng
Xác nhận đang nói với chủ của tên miềnDữ liệu đã bị sửa sẵn trên server (bài 4)
Metadata: IP, thời điểm, lượng dữ liệu, thường cả tên miền
Ổ khóa không có nghĩa là an toànKẻ lừa đảo đăng ký tên miền gần giống (ví dụ clb-example.com hay thay l bằng 1) và xin chứng chỉ hợp lệ cho chính tên đó. Kênh vẫn mã hóa nhưng bạn đang nói chuyện với sai bên. Luôn đọc tên miền trong thanh địa chỉ.

Cấu hình HTTPS đúng cho website của bạn

  • Chuyển hướng (301) mọi truy cập HTTP sang HTTPS, và bật header Strict-Transport-Security (HSTS) để trình duyệt tự dùng HTTPS từ lần sau.
  • Đặt cờ Secure cho cookie phiên (chỉ gửi qua HTTPS) và HttpOnly (script trong trang không đọc được cookie).
  • Theo dõi hạn chứng chỉ: hết hạn thì trình duyệt cảnh báo và người dùng không vào được.
  • Khi trình duyệt cảnh báo chứng chỉ, đừng bấm bỏ qua với trang có đăng nhập hay thanh toán.

BÀI TẬP 8 · 5 PHÚT

Phân tích ba cảnh báo chứng chỉ

Cho mỗi trường hợp, nêu: ý nghĩa, rủi ro, quản trị viên nên làm gì, người dùng nên làm gì.

  1. Chứng chỉ chỉ cấp cho clb.example, người dùng vào www.clb.example: "name mismatch".
  2. Chứng chỉ hết hạn hôm qua.
  3. Chứng chỉ tự ký (self-signed), không có CA nào đứng sau.
Xem đáp án
  1. Tên trong chứng chỉ không khớp tên đang truy cập. Có thể chỉ là cấu hình thiếu, cũng có thể là máy chủ khác. Quản trị: cấp chứng chỉ bao gồm cả www.clb.example (hoặc chuyển hướng về tên chuẩn). Người dùng: không nhập thông tin nhạy cảm, báo quản trị.
  2. Hết hạn: kênh vẫn mã hóa được nhưng không còn bảo đảm danh tính; thường do quên gia hạn. Quản trị: gia hạn, bật gia hạn tự động và cảnh báo trước hạn. Người dùng: chờ, đừng bỏ qua cảnh báo với trang thanh toán.
  3. Tự ký: không ai xác nhận chủ tên miền nên kẻ giữa đường tự tạo chứng chỉ giống hệt. Chỉ chấp nhận được trong môi trường thử nghiệm nội bộ. Quản trị: dùng CA công cộng miễn phí như Let's Encrypt cho website thật. Người dùng: không tin.
09

C2. Lab 2: so sánh HTTP và HTTPS bằng capture

25 phút

Lab 1 cho thấy HTTP lộ hết. Lab này đặt cùng một request lên hai kênh, HTTP và HTTPS (HTTP chạy trong kênh ), rồi bắt gói để so sánh. Ta dùng đúng server.py vừa viết: không có tham số thì chạy HTTP ở port 8000, có --tls thì chạy HTTPS ở port 8443. Làm trong máy mình nên không cần Internet, không rủi ro và kết quả lặp lại được.

Kết quả cuối labBạn sẽ: (1) tự tạo một chứng chỉ tự ký; (2) chạy hai server song song (HTTP và HTTPS); (3) thấy curl từ chối chứng chỉ chưa được tin, rồi chấp nhận khi bạn chỉ rõ chứng chỉ nào tin; (4) chứng minh bằng bộ lọc rằng cookie lộ ở HTTP nhưng biến mất ở HTTPS.

Bước 1. Tạo chứng chỉ tự ký

HTTPS cần hai file: khóa riêng (key.pem, giữ bí mật ở server) và (cert.pem, gắn tên miền với khóa công khai). Website thật xin chứng chỉ từ một tổ chức cấp (CA). Ở lab, ta tự ký cho chính mình, nên trình duyệt và curl sẽ không tin sẵn; đó là điều ta muốn quan sát. Vào thư mục network-lab (cd ~/network-lab hoặc cd $HOME\network-lab) và gõ trên một dòng:

MACOS
openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 7 -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
WINDOWS POWERSHELL (OPENSSL ĐI KÈM GIT FOR WINDOWS)
& "C:\Program Files\Git\usr\bin\openssl.exe" req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 7 -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
LINUX
openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 7 -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
# Chưa có openssl: sudo apt install openssl
PhầnÝ nghĩa
openssl reqCông cụ OpenSSL, nhóm lệnh req: tạo yêu cầu chứng chỉ.
-x509Thay vì gửi yêu cầu cho CA, tự ký luôn và xuất ra chứng chỉ. Đây là điểm khiến chứng chỉ thành "tự ký".
-newkey rsa:2048Tạo luôn một khóa riêng mới, kiểu RSA 2048 bit.
-nodesKhông đặt mật khẩu cho khóa riêng để server khởi động không bị hỏi. Chỉ chấp nhận ở lab.
-keyout key.pem / -out cert.pemTên file khóa riêng và tên file chứng chỉ sẽ được tạo trong thư mục hiện tại.
-days 7Chứng chỉ chỉ có hiệu lực 7 ngày. Dùng ngắn cho đồ thử nghiệm.
-subj "/CN=localhost"Tên chủ chứng chỉ (Common Name) là localhost, tên máy này.
-addext "subjectAltName=..."Danh sách tên và IP mà chứng chỉ được phép đại diện. Trình duyệt và curl hiện đại chỉ kiểm tra mục này. Thiếu nó sẽ gặp lỗi "name mismatch" (bài tập 8).
WindowsMáy chưa có Git for Windows thì cài tại git-scm.com (đi kèm openssl), hoặc mở Git Bash và gõ đúng lệnh macOS/Linux ở trên.
KẾT QUẢ MONG ĐỢI (RÚT GỌN)
Generating a RSA private key
..+++++
writing new private key to 'key.pem'
-----

Kiểm tra bằng ls hoặc dir: có thêm cert.pem và key.pem.

key.pem là bí mậtAi có khóa riêng này là đóng giả được server. Ở lab nó vô hại vì chỉ dùng trên localhost. Với website thật: không gửi khóa riêng cho ai, không đưa vào Git, không chép vào chat. CA chỉ nhận yêu cầu có khóa công khai, không bao giờ cần khóa riêng.

Bước 2. Chạy cùng lúc server HTTP và server HTTPS

Cần hai server song song nên dùng hai terminal, cả hai đều cd vào network-lab:

TERMINAL A (HTTP, PORT 8000)
python3 server.py
TERMINAL B (HTTPS, PORT 8443)
python3 server.py --tls
TERMINAL A (HTTP, PORT 8000)
py server.py
TERMINAL B (HTTPS, PORT 8443)
py server.py --tls
TERMINAL A (HTTP, PORT 8000)
python3 server.py
TERMINAL B (HTTPS, PORT 8443)
python3 server.py --tls
KẾT QUẢ MONG ĐỢI
Terminal A:  Dang chay tai http://127.0.0.1:8000/  (Ctrl+C de dung)
Terminal B:  Dang chay tai https://127.0.0.1:8443/  (Ctrl+C de dung)

Lỗi FileNotFoundError: cert.pem ở Terminal B nghĩa là bạn đang đứng sai thư mục hoặc chưa làm xong bước 1. Mở thêm Terminal C (cũng trong network-lab) để gõ lệnh curl.

Bước 3. Gọi HTTPS và xem TLS làm gì

3a. Gọi khi chưa tin chứng chỉ. Ở Terminal C:

TERMINAL C
curl https://localhost:8443/
KẾT QUẢ MONG ĐỢI
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.se/docs/sslcerts.html

Đây chính là trường hợp "chứng chỉ tự ký" của bài tập 8: kênh có thể mã hóa được, nhưng không có CA nào bảo đảm rằng chủ của localhost là bạn, nên curl từ chối. Trình duyệt cũng vậy: vào https://localhost:8443/ sẽ thấy trang cảnh báo đỏ ("Your connection is not private"). Ở lab này bấm tiếp tục là chấp nhận được vì chính bạn tạo ra chứng chỉ; với trang đăng nhập hay thanh toán thật thì không bao giờ bấm bỏ qua.

3b. Chỉ rõ chứng chỉ nào được tin. Thay vì tắt kiểm tra, ta bảo curl tin đúng file cert.pem của mình:

TERMINAL C
curl -i --cacert cert.pem https://localhost:8443/
PhầnÝ nghĩa
--cacert cert.pemChỉ định CA (hoặc chứng chỉ) được tin. Vì cert.pem tự ký nên nó cũng là "CA" của chính nó. Nhờ tên localhost khớp trong subjectAltName nên kiểm tra tên cũng qua.
https://localhost:8443/Scheme https:// bảo curl bắt tay TLS trước khi gửi HTTP; 8443 là port ta chọn cho server HTTPS.
Không dùng -k-k (--insecure) tắt hẳn kiểm tra chứng chỉ, tức là chấp nhận cả máy chủ giả. Đừng tập thói quen này, nhất là trong script triển khai.
KẾT QUẢ MONG ĐỢI
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.9.6
Content-Type: text/html; charset=utf-8
Content-Length: 37

<h1>Cau lac bo - Lich sinh hoat</h1>

Nội dung y hệt khi dùng HTTP: người dùng cuối không nhìn thấy khác biệt, khác biệt nằm trên đường truyền. Giờ gửi POST của Lan qua HTTPS:

TERMINAL C
curl -i --cacert cert.pem -X POST -H "Cookie: phien=demo123" -d "ten=Lan&so_tien=200000&ghi=ok" https://localhost:8443/dong-phi

Nhìn Terminal B: server vẫn in ra đủ phien=demo123 và ten=Lan. Server là một đầu của kênh nên đọc được hết; điều TLS làm là khiến người đứng giữa không đọc được.

3c. Xem bắt tay TLS từ phía client. Thêm -v (verbose) để curl kể từng bước:

TERMINAL C
curl -v --cacert cert.pem https://localhost:8443/
KẾT QUẢ MONG ĐỢI (RÚT GỌN; TLS 1.2 HAY 1.3 TÙY MÁY BẠN)
* Host localhost:8443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8443...
* connect to ::1 port 8443 failed: Connection refused
*   Trying 127.0.0.1:8443...
* Connected to localhost (127.0.0.1) port 8443
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
...
> GET / HTTP/1.1

Đọc theo thứ tự: tên localhost được đổi thành IP (DNS, B1); curl thử IPv6 ::1 bị từ chối vì server chỉ nghe IPv4 127.0.0.1, rồi quay về IPv4 (bình thường, liên quan đến bài 5); TCP kết nối xong; sau đó mới đến Client hello, Server hello, Certificate, Finished của TLS; chỉ sau cùng mới là dòng GET / HTTP/1.1 được gửi trong kênh đã mã hóa. Đúng thứ tự DNS → TCP → TLS → HTTP của phần D.

Bước 4. Bắt gói và so sánh hai kênh

  1. Mở Wireshark, bắt trên giao diện loopback như Lab 1 (macOS lo0, Linux lo, Windows Npcap Loopback). Bắt đầu capture trước khi gõ lệnh.
  2. Ở Terminal C gửi lần lượt hai POST giống hệt nhau, một HTTP và một HTTPS:
TERMINAL C: HTTP
curl -i -X POST -H "Cookie: phien=demo123" -d "ten=Lan&so_tien=200000&ghi=ok" http://127.0.0.1:8000/dong-phi
TERMINAL C: HTTPS
curl -i --cacert cert.pem -X POST -H "Cookie: phien=demo123" -d "ten=Lan&so_tien=200000&ghi=ok" https://localhost:8443/dong-phi
  1. Dừng capture. Lọc hai kênh cùng lúc:
Ô LỌC CỦA WIRESHARK
tcp.port == 8000 || tcp.port == 8443

Cột Protocol của luồng port 8000 ghi HTTP; luồng port 8443 ghi TLSv1.2 hoặc TLSv1.3. Nếu luồng 8443 chỉ hiện TCP, chuột phải vào một gói của nó → Decode As… → đặt TCP port 8443 thành TLS → OK.

  1. Nhấp vào các dòng của luồng 8443 và mở khung giữa. Bạn sẽ thấy lần lượt:
GóiÝ nghĩaThấy gì
TCP SYN / SYN-ACK / ACKBắt tay TCP (phần B3)Không mã hóa, giống Lab 1
Client HelloClient chào, đề xuất thuật toánMở Extension: server_name: thấy tên localhost ở dạng chữ rõ. Đây là lý do tên miền thường vẫn lộ với HTTPS
Server Hello (rồi Certificate nếu là TLS 1.2)Server chọn thuật toán và gửi chứng chỉVới TLS 1.2 mở được chứng chỉ, thấy CN=localhost. Với TLS 1.3 chứng chỉ đã được mã hóa nên không có dòng riêng
Application DataDữ liệu HTTP bên trong kênhChỉ còn byte vô nghĩa. Không thấy POST, cookie hay body
  1. Chuột phải vào một gói của luồng 8443 → Follow → TCP Stream: chỉ là ký tự lộn xộn. So với luồng 8000 vừa đọc được trọn vẹn request.
  2. Phép thử quyết định. Gõ ô lọc sau và Enter:
Ô LỌC CỦA WIRESHARK
frame contains "demo123"
Ô LỌC CỦA WIRESHARK (THỬ THÊM)
frame contains "so_tien"

Chỉ gói của luồng port 8000 hiện ra. Không có gói nào ở port 8443 chứa chuỗi này, dù cùng một cookie và cùng một body đã được gửi. Đó là sự khác biệt giữa HTTP và HTTPS, tự bạn chứng minh bằng dữ liệu của chính mình.

Bước 5 (tùy chọn). Thử với một website thật

Muốn thấy cả DNS, hãy bắt trên giao diện Wi-Fi hoặc Ethernet thật (không phải loopback), đóng ứng dụng không cần thiết và không đăng nhập thứ nhạy cảm trong lúc bắt. Dùng example.com, trang mẫu công khai:

TERMINAL
nslookup example.com
curl --http1.1 -I https://example.com

--http1.1 ép HTTP/1.1 cho dễ quan sát; -I chỉ lấy header (method HEAD). Trên Windows PowerShell dùng curl.exe. Dừng capture, lọc lần lượt dns, tcp, tls. Bạn thấy truy vấn DNS (chữ rõ, ai cũng đọc được tên bạn tra), bắt tay TCP, bắt tay TLS với server_name là example.com, rồi chỉ còn Application Data. Truy vấn DNS và kết nối HTTPS có thể ra IP khác nhau (cache, IPv4/IPv6, cân bằng tải), nên đừng ghép hai dòng chỉ vì chúng gần nhau.

Dọn dẹp

Ở mỗi terminal đang chạy server nhấn Ctrl + C. Xóa khóa riêng và file capture bạn không còn cần: rm key.pem cert.pem (macOS/Linux) hoặc del key.pem, cert.pem (Windows); file .pcapng xóa bằng trình quản lý file vì có thể chứa dữ liệu luồng khác. Có thể giữ thư mục network-lab để làm lại.

BÀI TẬP 9 · 10 PHÚT

Điền bảng "ai thấy gì"

Từ hai lab, điền bảng cho một request HTTP (Lab 1) và một request HTTPS (Lab 2). Mỗi ô ghi "thấy" hoặc "không thấy" đối với người bắt gói ở giữa đường:

Thông tinHTTPHTTPS
IP và port đích??
Tên miền truy cập??
Đường dẫn và method (GET /…)??
Cookie??
Nội dung trang??
Truy vấn DNS (DNS thường)??

Câu hỏi thêm: nếu kẻ giữa đường cố sửa số tài khoản trong trang HTTPS, chuyện gì xảy ra?

Xem đáp án
Thông tinHTTPHTTPS
IP và port đíchThấyThấy
Tên miền truy cậpThấy (Host header, DNS)Thường thấy (DNS, Server Name trong TLS)
Đường dẫn và methodThấyKhông thấy
CookieThấyKhông thấy
Nội dung trangThấyKhông thấy
Truy vấn DNS (DNS thường)ThấyThấy

Sửa giữa đường: TLS kiểm tra toàn vẹn nên dữ liệu bị sửa làm bắt tay hoặc giải mã thất bại, kết nối bị ngắt thay vì hiển thị trang sai. Metadata (IP, tên miền, lượng dữ liệu) vẫn lộ, đó là lý do HTTPS giảm rủi ro chứ không xóa hết.

10

D. Chẩn đoán theo lớp và rà soát website

15 phút
DNSTên → IP
TCPKết nối
TLSKênh bảo vệ
HTTPYêu cầu / phản hồi

Hành trình đi qua nhiều lớp, và mỗi lớp lỗi cho một dấu hiệu khác. Biết thứ tự này, thay vì sửa ngẫu nhiên, bạn đọc dấu hiệu để chọn đúng lớp kiểm tra:

Dấu hiệuLớp nghi ngờKiểm tra tiếp
Không tra được tênDNSTên, resolver, loại bản ghi
Có IP nhưng không kết nối đượcMạng, firewall, dịch vụĐích, port, tuyến, firewall, server có lắng nghe không
TCP có, TLS lỗiChứng chỉ, cấu hình TLSTên khớp, hạn dùng, chuỗi tin cậy
TLS có, HTTP 403Quyền, cấu hình ứng dụngQuy tắc truy cập, đường dẫn
HTTP 200 nhưng dữ liệu saiỨng dụng, dữ liệu, cacheNghiệp vụ, bản ghi, lịch sử sửa (bài 4)

Khi gắn thêm tên miền mới vào cùng máy chủ, phải đúng cả bốn lớp: DNS trỏ đúng máy; web server biết tên mới thuộc website nào; chứng chỉ TLS có tên mới; ứng dụng chỉnh URL chuẩn và cookie. "Đã trỏ A record đúng" chỉ là một quan sát ở lớp DNS, chưa phải kết luận mọi thứ xong.

BÀI TẬP 10 · 8 PHÚT

Chẩn đoán năm tình huống

Với mỗi tình huống, nêu lớp nghi ngờ nhất và việc kiểm tra đầu tiên:

  1. nslookup clb.example báo "NXDOMAIN" (không tồn tại).
  2. Tra DNS ra IP đúng, curl treo rồi báo "connection timed out".
  3. Kết nối được nhưng trình duyệt báo "certificate expired".
  4. Trang mở được nhưng thành viên thường thấy 403 khi vào trang danh sách.
  5. Số tài khoản hiển thị sai nhưng mọi thứ trả mã 200 và có ổ khóa.
Xem đáp án
  1. DNS: bản ghi chưa có hoặc tên miền hết hạn. Kiểm tra bản ghi tại nhà đăng ký và hạn tên miền.
  2. Mạng/firewall/dịch vụ: gói đi mà không có phản hồi nên thường là firewall chặn hoặc server không lắng nghe. Kiểm tra port có mở, server có chạy, bắt gói xem có SYN mà không thấy SYN/ACK.
  3. TLS: chứng chỉ hết hạn. Gia hạn và bật tự động gia hạn.
  4. Ứng dụng: 403 là phân quyền (đúng cho thành viên thường nếu danh sách chỉ dành cho người phụ trách). Kiểm tra quy tắc quyền, không phải router.
  5. Dữ liệu: HTTPS và 200 không bảo đảm toàn vẹn. Xem lịch sử chỉnh sửa, quyền sửa, log (bài 4), đối chiếu bản đã duyệt.

BÀI TẬP 11 · Về nhà, 20 PHÚT

Rà soát một website bằng danh sách kiểm tra

Chọn website của câu lạc bộ (hoặc website bạn có quyền kiểm tra) và điền bảng. Mỗi mục ghi Đạt, Chưa đạt hoặc Chưa biết, kèm bằng chứng (lệnh đã chạy, ảnh chụp):

MụcCách kiểm tra
1. Tài khoản tên miền có MFA, email khôi phục còn thuộc quyềnĐăng nhập nhà đăng ký, xem cài đặt bảo mật
2. Tên miền và chứng chỉ còn hạn trên 30 ngàyXem hạn ở nhà đăng ký; bấm vào ổ khóa xem chứng chỉ
3. HTTP tự chuyển sang HTTPScurl -I http://tên-miền, tìm mã 301 và dòng Location: https://…
4. Có header HSTScurl -I https://tên-miền, tìm Strict-Transport-Security
5. Cookie phiên có Secure và HttpOnlyCông cụ nhà phát triển của trình duyệt, mục Application → Cookies
6. Chỉ mở các port cần thiếtHỏi nhà cung cấp hosting danh sách quy tắc firewall
7. File nhạy cảm không nằm trong thư mục công khaiThử truy cập đường dẫn tới file danh sách thành viên mà không đăng nhập

Chỉ kiểm tra website của mình hoặc nơi được cho phép; các lệnh trên là yêu cầu thông thường, không dò quét.

Xem đáp án

Không có đáp án duy nhất. Một báo cáo tốt: mỗi mục có kết quả và bằng chứng; mục "Chưa đạt" kèm cách sửa và người chịu trách nhiệm; mục "Chưa biết" ghi rõ cần ai xác nhận. Xếp thứ tự xử lý theo rủi ro (bài 2): mất quyền tên miền và lộ dữ liệu thành viên nặng hơn thiếu HSTS.

Tóm tắt

Tự kiểm tra · 5 câu có giải thích +
1. Request HTTP không mã hóa đi qua router của quán cà phê. Người điều khiển router đọc được gì?
2. Firewall chỉ mở 443. Một gói đến cổng 3306 sẽ ra sao?
3. Thấy hàng nghìn SYN từ nhiều IP mà không có ACK. Đây có thể là gì?
4. Trang có ổ khóa HTTPS nhưng tên miền là clb-example.com (giả). Điều gì đúng?
5. Tra DNS ra IP đúng nhưng báo "certificate name mismatch". Nên làm gì?

Ghi chú cá nhân +

Tự lưu trên trình duyệt. Không nhập thông tin bí mật.

Có thể bỏ đánh dấu bất cứ lúc nào.
Tài liệu tham khảo chính thức

Tra thuật ngữ