Bảo mật website: hướng dẫn 6 lớp bảo vệ kèm checklist (2026)

Điểm chính

Bảo mật website hiệu quả được xây theo từng lớp: khóa chặt tên miền và DNS (registrar lock, DNSSEC, CAA), bắt buộc TLS hiện đại kèm HSTS, gửi một bộ HTTP security header nghiêm ngặt, băm mật khẩu bằng Argon2id kèm MFA và rate limit, kiểm tra đầu vào và thực thi kiểm soát truy cập trên máy chủ, ghim và audit thư viện phụ thuộc, đóng mọi cổng bạn không sử dụng, và ghi log đủ để nhận ra khi bị xâm nhập. Mỗi biện pháp dưới đây đều đi kèm cấu hình chính xác và một cách miễn phí để kiểm chứng rằng nó thực sự đang hoạt động, bởi một biện pháp kiểm soát chưa được kiểm thử thì coi như bạn chưa có.

Kiểm tra ngay

Bảo mật website theo sáu lớp: tên miền và DNS, TLS, HTTP header, ứng dụng, thư viện phụ thuộc, máy chủ
Bảo mật website theo sáu lớp: tên miền và DNS, TLS, HTTP header, ứng dụng, thư viện phụ thuộc, máy chủ
Bắt đầu đọc
  1. Bảo mật website thực sự nghĩa là gì?
  2. Mô hình bảo mật website: sáu lớp cần bảo vệ
  3. Lớp 1: khóa chặt tên miền và DNS
  4. Lớp 2: triển khai HTTPS và TLS đúng cách
  5. Lớp 3: HTTP security header
  6. Lớp 4: xác thực chống được credential stuffing
  7. Session, cookie và CSRF
  8. Injection và XSS: kiểm tra đầu vào, mã hóa đầu ra
  9. Broken Access Control: rủi ro số một
  10. Lớp 5: thư viện phụ thuộc và chuỗi cung ứng phần mềm
  11. Lớp 6: gia cố máy chủ (cổng, bản vá, secret, sao lưu)
  12. Xác thực email: SPF, DKIM và DMARC
  13. Ghi log, giám sát và lên kế hoạch cho sự cố
  14. Kiểm thử: công cụ quét, pentest và kiểm tra liên tục
  15. Checklist bảo mật website
  16. Đối chiếu với OWASP Top 10:2025
  17. Câu hỏi thường gặp về bảo mật website

Bảo mật website thực sự nghĩa là gì?

Các biện pháp bảo mật website là tập hợp những lớp kiểm soát giúp một website hay ứng dụng web không bị chiếm quyền, bị thay đổi giao diện (deface), bị lợi dụng để tấn công chính người truy cập, hay bị rút dữ liệu một cách âm thầm. Đó không phải một sản phẩm hay một tùy chọn duy nhất. Đó là một chuỗi quyết định bắt đầu từ nhà đăng ký tên miền (registrar), đi qua DNS, TLS, các HTTP header mà máy chủ gửi đi, phần code xử lý đăng nhập và dữ liệu đầu vào, các package bên thứ ba mà bạn xây dựng dựa trên, bản thân máy chủ, và cuối cùng là log — thứ báo cho bạn biết khi có chuyện không ổn.

Lý do nên nghĩ theo từng lớp là vì kẻ tấn công cũng nghĩ như vậy. Báo cáo Verizon 2026 Data Breach Investigations Report, bao quát hơn 22.000 vụ rò rỉ từ tháng 11/2024 đến tháng 10/2025, cho thấy 31% vụ rò rỉ bắt đầu từ một lỗ hổng phần mềm bị khai thác, tăng từ 20% một năm trước và lần đầu vượt qua thông tin đăng nhập bị đánh cắp (13%), trong khi phishing giữ nguyên ở 16%. Ransomware xuất hiện trong 48% vụ rò rỉ, tăng từ 44%. Chỉ cần một bản vá bị bỏ sót, một API key bị lộ hoặc một trang admin không giới hạn tốc độ là đủ. Không biện pháp nào trong hướng dẫn này là xa lạ; những website bị tấn công thường là những nơi bỏ qua kiến thức cơ bản ở một lớp trong khi chăm chút cho lớp khác.

Hướng dẫn này được sắp xếp từ ngoài vào trong. Mỗi biện pháp cho bạn biết vì sao nó quan trọng, cần cấu hình chính xác điều gì và cách kiểm chứng bằng một lệnh hoặc một công cụ miễn phí như Kiểm Tra Header HTTP hay Kiểm Tra Chứng Chỉ SSL, vì một thiết lập mà bạn tin là đã bật nhưng chưa bao giờ kiểm tra thì không bảo vệ được gì.

Kiểm tra security header của website

Mô hình bảo mật website: sáu lớp cần bảo vệ

Mọi cuộc tấn công vào website đều nhắm vào một trong sáu lớp. Bảng dưới đây là bản đồ cho phần còn lại của hướng dẫn: mỗi lớp chứa những gì, thường bị tấn công ra sao, và công cụ kiểm tra miễn phí nào xác nhận lớp phòng thủ của bạn thực sự đang hoạt động.

LớpKẻ tấn công làm gì ở đâyBiện pháp cốt lõiKiểm chứng bằng
1. Tên miền và DNSChiếm tên miền, đổi nameserver, chiếm các subdomain bị bỏ quên, xin chứng chỉ giả mạoRegistrar lock, MFA, DNSSEC, CAA, rà soát bản ghi cũTra Cứu WHOIS, Kiểm tra sức khỏe DNS, Tìm Tên Miền Phụ
2. Truyền tải (TLS)Hạ cấp xuống HTTP, gỡ bỏ lớp mã hóa, khai thác bộ mã hóa cũ, chứng chỉ hết hạnTLS 1.2+, HSTS (preload tùy chọn), gia hạn tự độngKiểm Tra Chứng Chỉ SSL
3. HTTP headerChèn script (XSS), nhúng website vào frame để clickjacking, đoán kiểu nội dung, rò rỉ referrerCSP, frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyKiểm Tra Header HTTP
4. Ứng dụngCredential stuffing, injection, lỗi kiểm soát truy cập, CSRF, upload file không an toànArgon2id + MFA + rate limit, truy vấn tham số hóa, phân quyền phía máy chủ, cookie SameSiteRà soát code, ZAP, Kiểm Tra Độ Mạnh Mật Khẩu
5. Thư viện phụ thuộcPackage bị cài mã độc, CVE đã biết trong thư viện, pipeline CI bị xâm nhậpLockfile, audit, ghim phiên bản, SBOM, token đặc quyền tối thiểunpm audit, Dependabot, Trivy
6. Máy chủ và vận hànhCổng mở, thông tin đăng nhập mặc định, thiếu bản vá, không có bản sao lưu, không có logTường lửa, SSH chỉ dùng key, vá lỗi, sao lưu 3-2-1, log tập trungKiểm Tra Cổng, Kiểm Tra Danh Sách Đen IP

Làm từ trên xuống. Lớp 1 đến 3 là phần cấu hình bạn có thể xong trong một buổi chiều, và chúng bảo vệ mọi trang cùng lúc. Lớp 4 đến 6 là những thói quen lâu dài cần nằm sẵn trong quy trình review code và triển khai của bạn.

Lớp 1: khóa chặt tên miền và DNS

Mọi thứ khác trong hướng dẫn này đều giả định bạn vẫn kiểm soát tên miền của mình. Nếu kẻ tấn công đăng nhập được vào tài khoản registrar hoặc đổi được nameserver, chúng có thể trỏ lưu lượng của bạn đi bất cứ đâu, xin một chứng chỉ hợp lệ cho tên miền của bạn và đọc mọi email gửi đến bạn, trong khi code ứng dụng của bạn thậm chí không bao giờ được chạy. Vì vậy, bảo mật tên miền và DNS là biện pháp bảo mật website đầu tiên, và gần như hoàn toàn chỉ là việc cấu hình.

Hãy bắt đầu bằng một lượt Tra Cứu WHOIS cho chính tên miền của bạn và xác nhận ba điều: mã trạng thái có clientTransferProhibited, ngày hết hạn còn hơn một năm nữa, và registrar là nơi bạn thực sự có tài khoản. Chuyện tên miền của doanh nghiệp nằm trong tài khoản registrar của một nhà thầu cũ phổ biến đến bất ngờ. Hướng dẫn tra cứu WHOIS của chúng tôi giải thích mọi mã trạng thái bạn sẽ gặp.

Registrar lock, MFA và cảnh báo hết hạn

Bật registrar lock (còn gọi là khóa chuyển nhượng — transfer lock) để tên miền không thể bị chuyển sang registrar khác nếu bạn không chủ động mở khóa, và bật xác thực đa yếu tố (MFA) cho chính tài khoản registrar. Tài khoản registrar là mục tiêu phishing ưa thích chính vì một lần đăng nhập kiểm soát mọi thứ phía sau. Hãy dùng khóa bảo mật phần cứng hoặc ứng dụng xác thực thay cho SMS ở bất cứ đâu registrar cho phép.

Đặt tên miền tự động gia hạn bằng phương thức thanh toán sẽ không hết hạn, và vẫn nên thêm lời nhắc trong lịch trước ngày hết hạn 60 ngày. Tên miền hết hạn không mất ngay trong ngày hết hạn, nhưng khi thời gian ân hạn và thời gian chuộc lại kết thúc (tối đa khoảng 80 ngày với .com) thì nó bị xóa, và các dịch vụ drop-catch sẽ đăng ký nó trong vài giây sau khi được nhả ra. Người mua sẽ thừa hưởng email, lưu lượng truy cập của bạn và mọi đăng nhập OAuth tin tưởng tên miền của bạn.

  • Registry lock (khóa thủ công ở cấp nhà quản lý tên miền — registry, được xác nhận qua một kênh riêng ngoài hệ thống) đáng với khoản phí thêm cho một tên miền mà doanh nghiệp phụ thuộc vào; nó ngăn cả một tài khoản registrar đã bị xâm nhập thay đổi nameserver.
  • Tách bạch vai trò. Người trả tiền cho tên miền, tài khoản sở hữu tên miền và nhà cung cấp DNS đều cần được ghi lại rõ ràng và không gắn với hộp thư của một nhân viên duy nhất.
  • Bật WHOIS privacy để thông tin liên hệ của bạn không trở thành bản đồ cho kẻ phishing, và giữ trên tài khoản một địa chỉ email theo vai trò có người theo dõi, chẳng hạn domains@.

Ký zone bằng DNSSEC

DNSSEC ký vùng DNS của bạn để resolver có thể phát hiện câu trả lời giả mạo. Nếu không có nó, kẻ tấn công đầu độc được bộ nhớ đệm của resolver có thể đưa khách truy cập của bạn đến một máy chủ giả trong khi trình duyệt vẫn hiển thị tên miền của bạn. Hầu hết nhà cung cấp DNS được quản lý (Cloudflare, Route 53, Google Cloud DNS và nhiều nhà đăng ký tên miền) bật nó chỉ bằng một công tắc; bước thủ công duy nhất là đăng bản ghi DS ở nhà đăng ký. Hãy kiểm tra bằng dig, hoặc bằng Kiểm tra sức khỏe DNS, công cụ kiểm tra bản ghi DS và các chữ ký:

bash
dig +dnssec +short yourdomain.com A
# A signed zone returns the record AND an RRSIG line:
# 203.0.113.10
# A 13 2 3600 20270115000000 20261225000000 34505 yourdomain.com. Kx3f...==

dig +short yourdomain.com DS
# A DS record at the parent zone proves the chain of trust is complete
# 2371 13 2 6A1B...C9

Giới hạn việc cấp chứng chỉ bằng CAA

Bản ghi CAA (RFC 8659) cho các tổ chức cấp chứng chỉ (CA) biết CA nào được phép cấp chứng chỉ cho tên miền của bạn. Mọi CA công khai đều bắt buộc phải kiểm tra bản ghi này trước khi cấp, nên một bản ghi CAA sẽ chặn đường kẻ tấn công đã đánh lừa được quy trình xác thực tên miền của một CA khác. Ba bản ghi bao quát các trường hợp phổ biến: ai được cấp, ai được cấp chứng chỉ wildcard, và báo cáo yêu cầu bị từ chối gửi về đâu:

dns
yourdomain.com.  CAA 0 issue "letsencrypt.org"
yourdomain.com.  CAA 0 issuewild ";"
yourdomain.com.  CAA 0 iodef "mailto:security@yourdomain.com"

Rà soát bản ghi cũ: subdomain takeover

Chiếm quyền tên miền phụ (subdomain takeover) xảy ra khi một bản ghi DNS vẫn trỏ tới dịch vụ bạn đã ngừng dùng: CNAME trỏ tới một trang GitHub Pages đã xóa, một ứng dụng Azure, một S3 bucket hoặc tên máy chủ của một nhà cung cấp SaaS. Bất kỳ ai cũng có thể đăng ký đích bị bỏ rơi đó rồi phục vụ nội dung trên old-app.yourdomain.com dưới danh nghĩa của bạn, kèm cả chứng chỉ hợp lệ. Đây là phát hiện thường gặp trong các chương trình bug bounty vì không ai nhớ bản ghi đó còn tồn tại.

Hãy cho tên miền của bạn chạy qua Tìm Tên Miền Phụ: công cụ này tìm trong hai dịch vụ nhật ký certificate transparency, Cert Spotter (chứng chỉ hiện hành) và crt.sh (mọi chứng chỉ từ năm 2013), thử 1.000 tên phổ biến, phân giải từng tên trực tiếp, đánh dấu các CNAME bị bỏ lửng và cho biết máy chủ hoặc CDN nào đang chạy từng tên. Hãy xóa mọi bản ghi có đích trả về NXDOMAIN hoặc trang “no such app” của nhà cung cấp; Tra Cứu DNS xác nhận được một tên riêng lẻ. Lặp lại hằng quý, và đưa việc xóa bản ghi DNS vào quy trình ngừng dùng bất kỳ dịch vụ nào.

Certificate transparency cũng là hệ thống cảnh báo sớm của bạn: Cert Spotter và tính năng giám sát CT của Cloudflare có thể gửi email cho bạn mỗi khi bất kỳ CA nào cấp chứng chỉ cho tên miền của bạn. Một chứng chỉ bất ngờ xuất hiện thường là dấu hiệu đầu tiên có thể nhìn thấy của việc DNS hoặc registrar bị xâm nhập.

Lớp 2: triển khai HTTPS và TLS đúng cách

HTTPS không còn là thực hành tốt nhất mà là mức cơ bản; trình duyệt đánh dấu các trang HTTP thường là “Không an toàn”. Google cũng đã thông báo rằng từ Chrome 154 (tháng 10/2026), trình duyệt sẽ hỏi trước khi mở bất kỳ website công khai nào qua HTTP thường (Google). Những điều vẫn phân biệt một website an toàn với một website chỉ được mã hóa là các phiên bản TLS bạn chấp nhận, việc có ai còn truy cập được bạn qua HTTP hay không, và việc gia hạn được tự động hóa đủ tốt để vượt qua đợt rút ngắn thời hạn chứng chỉ bắt đầu từ tháng 3/2026.

Tối thiểu TLS 1.2, ưu tiên TLS 1.3

TLS 1.0 và 1.1 đã chính thức bị loại bỏ theo RFC 8996 từ năm 2021 và không trình duyệt hiện hành nào còn thương lượng hai phiên bản này. Hãy tắt chúng trên máy chủ, ưu tiên TLS 1.3 (phiên bản loại bỏ mọi bộ mã hóa yếu đã biết và hoàn tất bắt tay chỉ trong một vòng trao đổi), và chỉ giữ TLS 1.2 với các bộ mã hóa AEAD như ECDHE-ECDSA-AES128-GCM-SHA256 hoặc ECDHE-RSA-CHACHA20-POLY1305.

Khi kiểm tra từ bên ngoài, hai dòng quan trọng: giao thức được thương lượng và Verify return code: 0, nghĩa là toàn bộ chuỗi chứng chỉ đã được xác thực. Thiếu chứng chỉ trung gian là nguyên nhân thường gặp của các báo cáo “chạy trên Chrome, lỗi trên curl và Android”; hướng dẫn về chuỗi chứng chỉ SSL của chúng tôi chỉ cách sửa, và Kiểm Tra Chứng Chỉ SSL báo trực tiếp khi chuỗi không đầy đủ. Đây là lần kiểm tra chạy với dnsrobot.net vào ngày 27 tháng 10 năm 2026, rồi một bài kiểm tra xem máy chủ có từ chối TLS 1.1 không:

bash
echo | openssl s_client -connect dnsrobot.net:443 -servername dnsrobot.net 2>/dev/null \
  | grep -E 'Protocol|Cipher|Verify return'

# New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
# Protocol: TLSv1.3
# Verify return code: 0 (ok)

# Is TLS 1.1 refused? SECLEVEL=0 lets OpenSSL 3 and later offer it at all
openssl s_client -connect example.com:443 -servername example.com -tls1_1 \
  -cipher 'DEFAULT:@SECLEVEL=0' </dev/null 2>&1 | grep -E 'alert|Cipher is'

# Refused, as it should be:  ...tlsv1 alert protocol version...
#                            New, (NONE), Cipher is (NONE)
# Still accepted (fix it):   New, TLSv1.0, Cipher is ECDHE-ECDSA-AES128-SHA
#   (TLSv1.0 is the cipher's version; the handshake was TLS 1.1)

Danh sách cipher là nơi các cấu hình sao chép dán dần lỗi thời. Thay vì tự viết tay, hãy tạo khối cấu hình máy chủ được khuyến nghị hiện hành cho nginx, Apache, Caddy hoặc HAProxy bằng Mozilla SSL Configuration Generator và chọn hồ sơ “Intermediate” trừ khi bạn phải hỗ trợ các client rất cũ.

HSTS: không bao giờ để trình duyệt dùng lại HTTP

Chỉ chuyển hướng HTTP sang HTTPS là chưa đủ. Yêu cầu đầu tiên mà người truy cập gửi đến http://yourdomain.com vẫn đi dưới dạng văn bản thuần, và kẻ tấn công trong cùng mạng có thể trả lời nó trước khi lệnh chuyển hướng của bạn kịp đến. HTTP Strict Transport Security (RFC 6797) khắc phục điều này: khi trình duyệt đã thấy header này, nó sẽ tự viết lại mọi URL http:// sau này của tên miền bạn thành https:// trước khi gửi bất cứ thứ gì.

Dùng max-age ít nhất một năm (31536000 giây) và thêm includeSubDomains khi mọi tên miền phụ đều phục vụ HTTPS. Việc preload tại hstspreload.org, tức nhúng cứng tên miền vào Chrome, Firefox, Safari và Edge, là tùy chọn: chính những người duy trì danh sách này nay nói rằng nên dùng HSTS nhưng không khuyến nghị preload, vì Chrome và Safari vốn đã nâng các lượt điều hướng lên HTTPS, còn rút khỏi danh sách mất hàng tháng. Hãy kiểm tra header bằng Kiểm Tra Header HTTP, công cụ chấm điểm HSTS bằng các bài kiểm tra của Mozilla HTTP Observatory.

http
Strict-Transport-Security: max-age=31536000; includeSubDomains

Chứng chỉ 47 ngày: tự động hóa gia hạn ngay từ bây giờ

Nghị quyết SC-081 của CA/Browser Forum đang rút ngắn thời hạn tối đa của mọi chứng chỉ TLS công khai theo từng giai đoạn. Đợt cắt giảm đầu tiên có hiệu lực từ ngày 15/3/2026, nên bất kỳ chứng chỉ nào bạn mua hay gia hạn hôm nay đều đã bị giới hạn ở 200 ngày, và đến năm 2029, chứng chỉ sẽ phải thay khoảng sáu tuần một lần:

Ngày hiệu lựcThời hạn chứng chỉ tối đaThời gian tái sử dụng xác thực tên miền
Trước 15/3/2026398 ngày398 ngày
15/3/2026200 ngày200 ngày
15/3/2027100 ngày100 ngày
15/3/202947 ngày10 ngày

Gia hạn thủ công không thể theo kịp lịch trình này. Cách làm đúng là cấp chứng chỉ hoàn toàn tự động qua ACME: Let's Encrypt hoặc Google Trust Services thông qua certbot, acme.sh, Caddy, hoặc chứng chỉ tự động có sẵn trong Cloudflare, Vercel, Netlify và hầu hết các bảng điều khiển hosting. Hãy thử quy trình gia hạn trước khi thực sự cần đến nó (certbot renew --dry-run với certbot); lỗi cần để ý là một bản ghi CAA hoặc quy tắc tường lửa được thêm sau lần gia hạn trước và giờ đang chặn bước xác thực. Dù dùng giải pháp nào, hãy theo dõi cả ngày hết hạn từ bên ngoài: công cụ Kiểm Tra Chứng Chỉ SSL hiển thị số ngày còn lại, và một chứng chỉ hết hạn sẽ biến mọi lượt truy cập thành một trang cảnh báo toàn màn hình của trình duyệt.

Lớp 3: HTTP security header

Security header là những chỉ dẫn máy chủ của bạn gửi cho trình duyệt về việc được và không được làm gì với các trang của bạn: script nào được chạy, trang có thể bị nhúng vào khung hay không, trình duyệt có được đoán kiểu nội dung không và nên báo gì cho các website khác về nơi khách truy cập đến. Chúng không tốn chi phí, áp dụng cho mọi trang cùng lúc và chặn cả những nhóm tấn công. Đây cũng là lớp mà hầu hết website làm sai một phần, vì vậy Kiểm Tra Header HTTP chấm điểm chúng bằng các bài kiểm tra của Mozilla HTTP Observatory. Đây là những gì github.com gửi vào ngày 27 tháng 10 năm 2026, rút gọn còn các security header (script-src của họ nêu một máy chủ tài nguyên và một mã băm script, không có 'unsafe-inline'):

bash
curl -sI https://github.com/ | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer-policy'

strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
content-security-policy: default-src 'none'; base-uri 'self'; ... frame-ancestors 'none'; ... script-src github.githubassets.com 'sha256-6AKuI+cDd1MoUL1u4eqrA9PXmnPAkOB4h7421hPUUm0='; ...

Bảy header mọi website nên gửi

Đây là các giá trị nên hướng tới trên một website thông thường. Trong cách chấm điểm của Mozilla HTTP Observatory mà Kiểm Tra Header HTTP của chúng tôi dùng, thiếu CSP bị trừ 25 điểm, thiếu HSTS hoặc chống nhúng khung bị trừ 20 điểm mỗi mục, còn thiếu nosniff bị trừ 5; Referrer-Policy và COOP cộng điểm thưởng khi điểm vẫn từ 90 trở lên. Permissions-Policy không được chấm điểm (chỉ trình duyệt Chromium đọc nó), nhưng vẫn nên đặt.

HeaderGiá trị khuyến nghịNgăn chặn điều gì
Strict-Transport-Securitymax-age=31536000; includeSubDomainsHạ cấp giao thức, đánh cắp cookie qua HTTP
Content-Security-Policyscript-src dựa trên nonce kèm 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'Cross-site scripting (XSS), chèn dữ liệu, clickjacking
X-Content-Type-OptionsnosniffMIME sniffing biến một file upload thành script thực thi được
Referrer-Policystrict-origin-when-cross-originRò rỉ URL đầy đủ (token, từ khóa tìm kiếm) cho bên thứ ba
Permissions-Policycamera=(), microphone=(), geolocation=(), payment=()Script bên thứ ba âm thầm sử dụng các API trình duyệt nhạy cảm
X-Frame-OptionsDENY (phương án dự phòng kiểu cũ cho frame-ancestors)Clickjacking trên các trình duyệt không hỗ trợ CSP Level 2
Cross-Origin-Opener-Policysame-originTấn công xuyên cửa sổ thông qua window.opener

Content Security Policy mà không làm hỏng website

Content Security Policy là biện pháp phòng thủ hiệu quả nhất trước XSS, vì nó ngăn các script bị chèn vào được chạy ngay cả khi tồn tại lỗi injection. Điểm khó là một chính sách nghiêm ngặt sẽ làm hỏng mọi script inline hay thẻ bên thứ ba mà bạn đã quên mất. Cách tiếp cận hiện đại, được Google khuyến nghị và có tài liệu trên MDN, là chính sách dựa trên nonce: máy chủ tạo một nonce ngẫu nhiên cho mỗi response, gắn nó vào mọi thẻ script mà nó chủ động render, và trình duyệt từ chối mọi thứ còn lại.

'strict-dynamic' là thứ làm cho chính sách này khả thi trong thực tế: một script có nonce được phép tải thêm các script khác (analytics, tag manager, widget) mà không cần đưa từng cái vào allowlist, còn các token https: và 'unsafe-inline' bị trình duyệt hiện đại bỏ qua và chỉ đóng vai trò dự phòng cho trình duyệt cũ. Hãy triển khai với Content-Security-Policy-Report-Only trước, theo dõi các báo cáo vi phạm trong một tuần, rồi mới chuyển sang chế độ thực thi. Các framework như Next.js, Rails và Django có hỗ trợ nonce chính thức; website tĩnh có thể dùng script-src dựa trên hash thay thế.

http
Content-Security-Policy:
  script-src 'nonce-r4nd0m1z3dV4lu3' 'strict-dynamic' https: 'unsafe-inline';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'none';
  form-action 'self';
  report-to csp-endpoint

<!-- Only scripts carrying the nonce run; strict-dynamic lets them load their own dependencies -->
<script nonce="r4nd0m1z3dV4lu3" src="/app.js"></script>

Một chính sách allowlist như script-src 'self' https://cdn.example.com vẫn tốt hơn không có gì, nhưng bất kỳ endpoint JSONP hay thư viện cũ nào trên một host nằm trong allowlist đều có thể bị lợi dụng để vượt qua nó. Nếu chưa thể dùng nonce, ít nhất hãy đặt object-src 'none' và base-uri 'none', hai chỉ thị giúp đóng ngay hai cách vượt qua phổ biến.

Clickjacking: frame-ancestors và X-Frame-Options

Clickjacking tải website của bạn một cách vô hình bên trong trang của kẻ tấn công và lừa người truy cập bấm vào một nút họ không nhìn thấy. frame-ancestors 'none' trong CSP (hoặc 'self' nếu bạn nhúng các trang của chính mình) ngăn chặn điều này trên mọi trình duyệt hiện hành, còn X-Frame-Options: DENY bao phủ các trình duyệt cũ. Nếu bạn cố ý cung cấp một widget có thể nhúng, chỉ miễn trừ đúng đường dẫn đó và chỉ cho các origin cần đến nó; hướng dẫn X-Frame-Options của chúng tôi trình bày chi tiết các quy tắc máy chủ chính xác và những lỗi "refused to connect" bạn sẽ gặp khi thử nghiệm.

nosniff, Referrer-Policy, Permissions-Policy và COOP

X-Content-Type-Options: nosniff ngăn trình duyệt tự đoán lại Content-Type, chính điều có thể biến một "ảnh" do người dùng tải lên nhưng chứa HTML thành một trang thực thi được. Referrer-Policy: strict-origin-when-cross-origin (mặc định trên các trình duyệt hiện nay, nhưng vẫn nên đặt rõ ràng) chỉ gửi origin của bạn cho các website khác, nhờ đó token đặt lại mật khẩu và từ khóa tìm kiếm trong URL vẫn được giữ kín. Permissions-Policy tắt các tính năng trình duyệt bạn không dùng, để một script bên thứ ba bị xâm nhập không thể mở camera hay đọc vị trí. Cross-Origin-Opener-Policy: same-origin cắt liên kết window.opener tới các trang bạn mở, qua đó chặn một nhóm tấn công xuyên cửa sổ.

Những header cần loại bỏ cũng quan trọng: Server và X-Powered-By quảng bá chính xác phiên bản phần mềm cho các trình quét lỗ hổng, còn X-XSS-Protection đã lỗi thời và có thể gây lỗi ở trình duyệt cũ, nên hãy đặt nó thành 0 hoặc bỏ đi. Phát Hiện CMS cho thấy bất kỳ ai cũng có thể biết được gì về stack và phiên bản của bạn ngay từ trang.

Đặt header một lần tại lớp biên (CDN, reverse proxy hoặc middleware của framework) thay vì cho từng trang. Trong Next.js, đó là file proxy hoặc middleware; trong nginx là khối add_header trong context server; trong Apache là Header always set. Sau đó chạy lại công cụ Kiểm Tra Header HTTP sau mỗi lần deploy, vì một phiên bản framework mới hay một thiết lập CDN có thể âm thầm làm mất một header.

Lớp 4: xác thực chống được credential stuffing

Kẻ tấn công hiếm khi đoán mật khẩu từng cái một. Chúng dùng lại hàng tỷ cặp email và mật khẩu bị rò rỉ từ các website khác (credential stuffing) và dùng phishing cho phần còn lại. Vì thế, xác thực đúng cách gồm ba phần: lưu mật khẩu sao cho rò rỉ cơ sở dữ liệu không đồng nghĩa với rò rỉ mật khẩu, khiến một mật khẩu bị đánh cắp trở nên vô dụng nếu đứng một mình, và làm cho brute force chậm đến mức vô nghĩa. OWASP xếp Authentication Failures (lỗi xác thực) ở vị trí A07 trong OWASP Top 10:2025.

Băm mật khẩu bằng Argon2id hoặc bcrypt

Không bao giờ lưu mật khẩu, và cũng không bao giờ lưu giá trị băm nhanh của mật khẩu. MD5, SHA-1 và cả SHA-256 được thiết kế để chạy nhanh, nên một bảng giá trị băm bị rò rỉ có thể bị thử với tốc độ hàng tỷ lần đoán mỗi giây chỉ trên một GPU. Hãy dùng hàm băm mật khẩu chậm và tốn bộ nhớ (memory-hard) với salt riêng cho mỗi mật khẩu. OWASP Password Storage Cheat Sheet khuyến nghị theo thứ tự:

  • Argon2id với tối thiểu 19 MiB bộ nhớ, 2 vòng lặp và mức song song 1 (hoặc 46 MiB với 1 vòng lặp).
  • scrypt với N = 2^17, r = 8, p = 1 khi không có Argon2.
  • bcrypt với hệ số công việc (work factor) từ 10 trở lên (lưu ý giới hạn đầu vào 72 byte; việc băm trước các mật khẩu dài hơn cần làm cẩn thận).
  • PBKDF2-HMAC-SHA256 với 600.000 vòng lặp, chỉ dùng khi bắt buộc phải tuân thủ FIPS.
javascript
// Node.js with the argon2 package
import argon2 from "argon2";

const hash = await argon2.hash(password, {
  type: argon2.argon2id,
  memoryCost: 19456, // KiB = 19 MiB
  timeCost: 2,
  parallelism: 1,
});

// Later, on login:
const ok = await argon2.verify(hash, submittedPassword);

Hãy chỉnh chi phí sao cho một lần băm mất khoảng 100 đến 250 ms trên máy chủ đăng nhập của bạn. Người dùng thật không nhận ra, nhưng nó giới hạn mỗi nhân CPU chỉ còn vài lượt đoán mỗi giây, và ngay cả một card đồ họa cao cấp cũng chỉ còn hàng nghìn thay vì hàng tỷ. Hãy băm lại khi đăng nhập thành công mỗi khi bạn nâng tham số, để các mã băm cũ tự được nâng cấp.

Quy tắc mật khẩu thực sự hữu ích (NIST SP 800-63B)

Các quy tắc về thành phần mà hầu hết website vẫn áp dụng (một chữ hoa, một ký hiệu, đổi mỗi 90 ngày) tạo ra những mật khẩu dễ đoán như Summer2026! và đẩy người dùng tới việc dùng lại mật khẩu. Hướng dẫn hiện hành NIST SP 800-63B thay chúng bằng các quy tắc đo lường đúng điều thực sự quan trọng:

  • Tối thiểu 8 ký tự khi đồng thời bắt buộc MFA, và ít nhất 15 ký tự với mật khẩu được dùng một mình; cho phép độ dài tối thiểu 64 ký tự.
  • Không có quy tắc về thành phần và không bắt buộc đổi định kỳ; chỉ yêu cầu đổi khi có bằng chứng bị xâm phạm.
  • Đối chiếu mọi mật khẩu mới với danh sách mật khẩu bị rò rỉ (range API của Have I Been Pwned cho phép làm điều này mà không phải gửi mật khẩu đi) và từ chối những mật khẩu đã bị lộ.
  • Cho phép dán và dùng trình quản lý mật khẩu, chấp nhận dấu cách và Unicode, và đưa ra hướng dẫn giúp người dùng chọn được mật khẩu mạnh, nhất là ngay sau khi bạn từ chối một mật khẩu.

Công cụ Kiểm Tra Độ Mạnh Mật Khẩu của chúng tôi cho thấy các thước đo này khác quy tắc cũ ra sao: nó ước tính thời gian bẻ khóa một mật khẩu trước 8 kiểu tấn công có tên, chỉ ra các mẫu làm yếu mật khẩu, và đối chiếu mật khẩu với dữ liệu rò rỉ mà không gửi nó đi, một phản hồi hữu ích hơn nhiều so với thông báo màu đỏ “cần có ký hiệu”.

MFA và passkey

Xác thực đa yếu tố biến một mật khẩu bị đánh cắp thành ngõ cụt. Hãy cung cấp nó cho mọi người và bắt buộc với các vai trò quản trị, tài chính và hỗ trợ. Xếp hạng các lựa chọn theo khả năng chống phishing: passkey và khóa bảo mật FIDO2 không thể bị phishing vì thông tin xác thực gắn với origin thật của bạn; ứng dụng xác thực (TOTP) là tốt; mã SMS tốt hơn không có gì nhưng có thể bị chặn qua hình thức tráo SIM (SIM swapping). Passkey được hỗ trợ trên mọi trình duyệt và hệ điều hành hiện hành và loại bỏ hoàn toàn mật khẩu, nhờ đó cũng xóa sổ credential stuffing như một loại hình tấn công.

Bảo vệ quy trình khôi phục tài khoản cẩn thận như chính việc đăng nhập: mã khôi phục được lưu dưới dạng băm, đặt lại qua email bằng token dùng một lần hết hạn trong vòng 15 phút, và không dùng câu hỏi bảo mật.

Rate limiting, khóa tài khoản và chống bot

Áp dụng rate limiting cho các endpoint đăng nhập, đăng ký, đặt lại mật khẩu và MFA theo từng IP và theo từng tài khoản, và trả về 429 Too Many Requests kèm header Retry-After khi vượt giới hạn (hướng dẫn về lỗi HTTP 429 của chúng tôi trình bày cách client nên phản ứng). Kết hợp với độ trễ tăng dần hoặc khóa tạm thời sau nhiều lần thất bại trên cùng một tài khoản, và CAPTCHA hoặc thử thách proof-of-work cho các endpoint hứng chịu tấn công phân tán. Ghi log mọi lần đăng nhập thất bại kèm IP nguồn để dấu hiệu của một đợt credential stuffing lộ ra trong vài phút thay vì vài tháng.

nginx
# nginx: 5 login attempts at once, then 1 every 12 seconds, per client IP
# (limit_req sends no Retry-After header; add one on your 429 page if clients need it)
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

location = /api/login {
    limit_req zone=login burst=4 nodelay;
    limit_req_status 429;
    proxy_pass http://app;
}

Giữ thông báo lỗi giống hệt nhau cho "người dùng không tồn tại" và "sai mật khẩu", và làm cho thời gian phản hồi của cả hai như nhau (băm một mật khẩu giả khi người dùng không tồn tại). Nếu không, form đăng nhập sẽ vô tình trở thành một API dò tìm người dùng.

Session, cookie và CSRF

Sau khi đăng nhập, cookie phiên chính là người dùng, nên nó xứng đáng được bảo vệ như mật khẩu. Ba thuộc tính cookie và một tiền tố tên đảm nhận phần lớn công việc:

  • Secure nghĩa là cookie không bao giờ được gửi qua HTTP thuần, nên không thể bị nghe lén trên Wi-Fi công cộng.
  • HttpOnly khiến JavaScript không thể nhìn thấy cookie, nên một lỗi XSS không đọc được nó.
  • SameSite=Lax (hoặc Strict cho trang quản trị) giữ cookie khỏi các request POST liên trang, qua đó vô hiệu hóa phần lớn các cuộc tấn công CSRF.
  • Tiền tố __Host- khiến trình duyệt từ chối cookie trừ khi nó có Secure, có Path=/ và không có thuộc tính Domain, nên một subdomain không thể ghi đè lên nó.
http
Set-Cookie: __Host-session=9f1c7e2a...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=28800

Các hành động làm thay đổi trạng thái tuyệt đối không được thực hiện qua GET. Một liên kết như /account/delete?id=42 có thể bị kích hoạt bởi một thẻ <img> trên bất kỳ trang nào người dùng truy cập, bất kể các cờ cookie của bạn tốt đến đâu.

CSRF: lớp phòng thủ thứ hai phía sau SameSite

Cross-site request forgery (CSRF) lừa một trình duyệt đang đăng nhập gửi request làm thay đổi trạng thái tới website của bạn từ một trang khác. Cookie SameSite chặn được trường hợp phổ biến, nhưng vẫn nên giữ một lớp phòng thủ thứ hai trên mọi request không phải GET: một token chống CSRF theo từng phiên trong trường ẩn hoặc header tùy chỉnh, hoặc kiểm tra header Origin (hay Sec-Fetch-Site) khớp với origin của chính bạn. Hầu hết framework (Django, Rails, Laravel, server action của Next.js) mặc định đã làm điều này; sai lầm thường gặp là tắt nó cho một endpoint API rồi lại gọi endpoint đó từ trình duyệt.

Session ID, xoay vòng và JWT

Tạo session ID với ít nhất 128 bit ngẫu nhiên, cấp lại ID khi đăng nhập và khi có bất kỳ thay đổi quyền hạn nào để chống session fixation, cho session hết hạn sau một thời gian không hoạt động, và cung cấp cho người dùng nút "đăng xuất trên mọi thiết bị" có tác dụng vô hiệu hóa session ở phía máy chủ. Với JWT, hãy để thời hạn ngắn (vài phút, kèm refresh token có thể thu hồi), không bao giờ lưu trong localStorage nơi mọi script đều đọc được, và coi việc lộ khóa ký là một vụ xâm phạm toàn diện, vì mọi token từng được ký bằng khóa đó giờ đều có thể bị giả mạo.

Injection và XSS: kiểm tra đầu vào, mã hóa đầu ra

Injection (A05:2025) và cross-site scripting là cùng một sai lầm ở những chỗ khác nhau: dữ liệu từ người dùng được đưa cho một trình thông dịch (SQL, shell, truy vấn LDAP, trang HTML) như thể đó là code. Cách khắc phục ở mọi nơi cũng giống nhau: tách biệt dữ liệu và code, và không bao giờ xây dựng lệnh bằng cách nối chuỗi.

Truy vấn tham số hóa thay vì nối chuỗi

Với SQL, hãy dùng prepared statement hoặc một ORM tạo ra chúng; khi đó cơ sở dữ liệu coi đầu vào là một giá trị không bao giờ có thể thay đổi cấu trúc câu truy vấn. Quy tắc tương tự áp dụng cho lệnh shell (truyền một mảng đối số, không bao giờ truyền một chuỗi), cho bộ lọc NoSQL (từ chối các object toán tử như {"$gt": ""} trong dữ liệu người dùng), và cho đường dẫn file (chuẩn hóa đường dẫn và xác nhận nó vẫn nằm trong thư mục dự định).

javascript
// Vulnerable: the input becomes part of the query text
const rows = await db.query(`SELECT * FROM users WHERE email = '${email}'`);

// Safe: the driver sends the value separately from the query
const rows = await db.query("SELECT * FROM users WHERE email = $1", [email]);

// Python / psycopg: same idea
cur.execute("SELECT * FROM users WHERE email = %s", (email,))

Mã hóa đầu ra để chặn XSS

Cross-site scripting xảy ra khi văn bản do người dùng kiểm soát được ghi vào trang mà không được mã hóa (encode) phù hợp với ngữ cảnh nơi nó xuất hiện. Các template engine hiện đại (React và JSX, Vue, Jinja2, Blade, ERB) mặc định đều encode; XSS ngày nay thường đến từ các "lối thoát hiểm": dangerouslySetInnerHTML, v-html, |safe, innerHTML, và việc tạo URL hoặc event handler inline từ dữ liệu người dùng. Hãy encode đúng theo ngữ cảnh, và làm sạch HTML định dạng (rich HTML) bằng một thư viện chuyên dụng như DOMPurify thay vì dùng regex.

Dữ liệu được đặt ở đâuMã hóa dưới dạngVí dụ
Nội dung HTMLHTML entity< thành &lt;, " thành &quot;
Thuộc tính HTMLEntity trong thuộc tính có dấu ngoặc képLuôn đặt giá trị thuộc tính trong dấu ngoặc kép; encode " và '
JavaScriptKhông chèn vào nội dung script; truyền dữ liệu qua thuộc tính data- hoặc một khối JSON <script type="application/json"></script> bên trong một chuỗi trở thành \u003c/script\u003e
Tham số URLPercent-encodingencodeURIComponent(value)
Giá trị CSSTránh hoàn toàn; chọn tên class từ một allowlistKhông bao giờ chèn dữ liệu người dùng vào style

SSRF, upload file và deserialization

Server-side request forgery (SSRF): nếu máy chủ của bạn tải một URL do người dùng cung cấp (webhook, proxy ảnh, xem trước liên kết), kẻ tấn công có thể trỏ nó tới các dịch vụ nội bộ hoặc endpoint metadata của cloud 169.254.169.254 và đọc được thông tin xác thực. Hãy phân giải hostname trước, từ chối các dải địa chỉ private và link-local, tắt chuyển hướng, và đặt các tiến trình tải URL vào một phân đoạn mạng không thể tiếp cận bất cứ thứ gì nội bộ.

Upload file: xác thực loại file bằng cách kiểm tra nội dung, không dựa vào phần mở rộng hay Content-Type do client gửi; áp đặt giới hạn dung lượng; lưu file bên ngoài thư mục gốc của web (web root) hoặc trong object storage dưới một tên ngẫu nhiên do bạn tạo; và phục vụ chúng từ một origin riêng với nosniff và Content-Disposition: attachment khi có thể. Không bao giờ để file upload nằm ở bất kỳ đâu mà máy chủ web sẽ thực thi nó.

Deserialization và mass assignment: không bao giờ deserialize dữ liệu không đáng tin cậy bằng một định dạng có thể khởi tạo lớp tùy ý (Java native serialization, pickle của Python, unserialize của PHP, YAML với tag tùy chỉnh); hãy dùng JSON kèm schema. Ràng buộc body của request vào một allowlist trường rõ ràng để người dùng không thể POST "role": "admin" vào một model tình cờ có cột đó.

Broken Access Control: rủi ro số một

Broken Access Control (lỗi kiểm soát truy cập) giữ vị trí đầu tiên trong OWASP Top 10 từ năm 2021 và tiếp tục đứng ở A01:2025. Đó không phải một lỗi đơn lẻ mà là một thói quen: kiểm tra một người là ai (xác thực — authentication) nhưng quên kiểm tra họ được phép chạm vào những gì (phân quyền — authorization) trên mỗi request. Dạng kinh điển là insecure direct object reference (IDOR): GET /api/invoices/1042 hoạt động với chủ sở hữu hóa đơn, và cũng hoạt động với bất kỳ ai đổi con số đó.

  • Mặc định từ chối. Mọi route đều cần một quy tắc cấp quyền rõ ràng; thiếu quy tắc nghĩa là 403, không phải 200.
  • Kiểm tra trên máy chủ, cho từng đối tượng. Ẩn một nút trên giao diện không phải là kiểm soát truy cập. Mọi thao tác đọc và ghi phải xác nhận người dùng hiện tại sở hữu hoặc được phép truy cập đúng bản ghi đó, kể cả trong các endpoint xử lý hàng loạt, chức năng xuất dữ liệu và tác vụ chạy nền.
  • Dùng ID khó đoán khi có ích (UUID), nhưng không bao giờ phụ thuộc vào chúng: che giấu không phải là phân quyền.
  • Siết chặt CORS. Access-Control-Allow-Origin: * đi kèm credentials, hoặc phản chiếu bất kỳ Origin nào mà request gửi lên, chẳng khác nào trao API của bạn cho mọi website người dùng truy cập.
  • Tắt liệt kê thư mục, chặn .git, .env, file sao lưu và file cấu hình ở cấp máy chủ web, và giữ trang quản trị khỏi internet công cộng hoặc đặt nó sau MFA và allowlist IP.
  • Rate limit và ghi log các lần phân quyền thất bại. Một loạt 403 dồn dập từ một phiên là dấu hiệu một cuộc tấn công dò tìm đang diễn ra.
javascript
// Express: ownership check on every object access
app.get("/api/invoices/:id", requireAuth, async (req, res) => {
  const invoice = await Invoice.findById(req.params.id);
  if (!invoice || invoice.ownerId !== req.user.id) {
    return res.status(404).end(); // 404, not 403: don't confirm the record exists
  }
  res.json(invoice);
});

Lớp 5: thư viện phụ thuộc và chuỗi cung ứng phần mềm

Phần lớn mã trong một ứng dụng web thông thường là mã bạn tải về chứ không phải mã bạn tự viết. Đó là lý do Software Supply Chain Failures lần đầu xuất hiện ở vị trí A03 trong OWASP Top 10 2025, và vì sao việc khai thác lỗ hổng đã vượt phishing cùng thông tin đăng nhập bị đánh cắp trong DBIR 2026. Tháng 9/2025, chỉ một maintainer bị phishing đã khiến mã độc đánh cắp tiền mã hóa lọt vào chalk, debug và 16 gói npm khác, tổng cộng có hơn hai tỷ lượt tải mỗi tuần; mọi dự án cài một phiên bản chưa ghim trong khoảng thời gian đó đều tự động nhận mã độc.

  • Commit lockfile (package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, go.sum) và cài đặt bằng npm ci trong CI để bản build có thể tái lập và một bản phát hành mới từ upstream không thể lọt vào khi chưa được review.
  • Quét liên tục: npm audit, pip-audit, bundler-audit, GitHub Dependabot hoặc Renovate để cập nhật, và một công cụ quét container như Trivy hoặc Grype cho lớp hệ điều hành.
  • Trì hoãn các bản nâng cấp không liên quan đến bảo mật vài ngày (minimumReleaseAge của Renovate) để một bản phát hành bị nhiễm độc thường đã bị gỡ trước khi bạn dùng đến, nhưng áp dụng bản vá bảo mật ngay lập tức.
  • Ghim các action và script bên thứ ba vào một commit SHA trong CI, và dùng Subresource Integrity (integrity="sha384-...") cho mọi script bạn tải từ CDN công cộng.
  • Cấp cho CI đặc quyền tối thiểu: token chỉ đọc khi có thể, thông tin xác thực OIDC ngắn hạn thay cho secret dài hạn, và quyền publish chỉ giới hạn cho job phát hành.
  • Tạo SBOM (CycloneDX hoặc SPDX) khi build để bạn có thể trả lời câu hỏi "chúng ta có bị ảnh hưởng không?" trong vài phút khi CVE tầm cỡ Log4Shell tiếp theo xuất hiện.
bash
# Reproducible install + audit in CI
npm ci --ignore-scripts
npm audit --audit-level=high

# Pin a GitHub Action to a commit, not a floating tag
# uses: actions/checkout@v4                 <- can change underneath you
# uses: actions/checkout@<full-commit-sha>  # v4.2.2

# Subresource Integrity for a CDN script (hash from: openssl dgst -sha384 -binary lib.min.js | openssl base64 -A)
<script src="https://cdn.example.com/lib.min.js"
        integrity="sha384-<base64-hash>"
        crossorigin="anonymous"></script>

npm ci --ignore-scripts chặn các script chạy lúc cài đặt mà phần lớn mã độc npm dùng để thực thi; sau đó chỉ bật lại script cho số ít package thực sự cần bước build.

Nếu bạn dùng WordPress hay một CMS khác, các quy tắc tương tự áp dụng cho plugin và theme, nơi phần lớn các vụ xâm nhập CMS bắt đầu. Hãy cập nhật core và mọi plugin, xóa những thứ bạn không dùng, và kiểm tra xem một công cụ quét có thể biết gì về các phiên bản bạn đang chạy bằng công cụ Phát Hiện CMS.

Lớp 6: gia cố máy chủ (cổng, bản vá, secret, sao lưu)

Lớp ứng dụng chẳng còn ý nghĩa nếu máy chủ bên dưới chấp nhận đăng nhập SSH bằng mật khẩu, chạy cơ sở dữ liệu trên một cổng công khai, hoặc chưa từng được vá kể từ khi dựng lên. Các biện pháp bảo mật máy chủ thì nhàm chán, nhưng đó chính là nơi ransomware lọt vào.

Đóng mọi cổng bạn không sử dụng

Một máy chủ web công khai cần mở cổng 80 và 443, và SSH từ dải IP của riêng bạn. Cơ sở dữ liệu (3306, 5432, 27017), Redis (6379), Elasticsearch (9200), trang quản trị và endpoint metrics chỉ nên bind vào localhost hoặc mạng riêng. Hãy kiểm tra từ bên ngoài bằng công cụ Kiểm Tra Cổng sau mỗi thay đổi, vì đó chính là góc nhìn của kẻ tấn công, và security group trên cloud rất dễ bị đọc nhầm.

bash
# Ubuntu: default-deny firewall, allow only web + SSH from your office range
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp
sudo ufw enable   # check your own IP is in that range first, or you lock yourself out

# SSH: keys only, no root password login, in a drop-in that sshd reads first
printf 'PasswordAuthentication no\nPermitRootLogin prohibit-password\n' \
  | sudo tee /etc/ssh/sshd_config.d/00-hardening.conf
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin) '   # what sshd will really use
sudo systemctl reload ssh

Trên Ubuntu và Debian, sshd đọc các file trong /etc/ssh/sshd_config.d/ trước phần còn lại của sshd_config, và với mỗi thiết lập, giá trị đầu tiên nó đọc được sẽ thắng. Vì vậy các lệnh ở trên ghi một drop-in tên 00-hardening.conf: một chỉnh sửa nằm sâu hơn trong file chính sẽ thua drop-in của image đám mây có dòng PasswordAuthentication yes. Hãy xác nhận kết quả bằng sudo sshd -T trước khi đăng xuất. Trong Kiểm Tra Cổng, một cổng mà tường lửa của bạn chặn sẽ hiện là Bị lọc (không phản hồi), còn cổng không có gì lắng nghe hiện là Đóng: cả hai đều ổn, Mở mới là thứ cần sửa.

Vá lỗi theo lịch, giữ secret ngoài code

Bật cập nhật bảo mật tự động (unattended) cho hệ điều hành, đăng ký các danh sách thông báo bảo mật của runtime và framework bạn dùng, và coi một CVE nghiêm trọng trong bất cứ thứ gì tiếp xúc với internet là việc phải xử lý ngay trong ngày. Chạy các dịch vụ dưới người dùng không có đặc quyền, trong container hoặc với cơ chế sandbox của systemd, để một tiến trình bị xâm nhập không thể đọc toàn bộ máy.

Secret (mật khẩu cơ sở dữ liệu, API key, khóa ký) không bao giờ được nằm trong repository, trong một layer của Docker image hay trong JavaScript phía client. Hãy nạp chúng từ biến môi trường được đưa vào lúc deploy hoặc từ một trình quản lý secret, xoay vòng chúng khi có người từng có quyền truy cập rời đi, và quét lịch sử repository bằng một công cụ như gitleaks, vì một key đã commit một lần là bị lộ vĩnh viễn, kể cả sau khi commit đó bị xóa.

Sao lưu sống sót trước ransomware, và CDN đứng phía trước

Tuân theo quy tắc 3-2-1: ba bản sao, trên hai loại phương tiện lưu trữ khác nhau, một bản ở ngoài hệ thống (off-site), và để ít nhất một bản sao là bất biến (immutable) hoặc ngoại tuyến để ransomware xâm nhập được máy chủ cũng không thể mã hóa luôn bản sao lưu. Mã hóa bản sao lưu, bao gồm cả cơ sở dữ liệu lẫn thư mục upload, và điều cực kỳ quan trọng là thử khôi phục theo lịch định kỳ. Một bản sao lưu chưa ai từng khôi phục chỉ là hy vọng, không phải kế hoạch. Thời gian khôi phục là yếu tố quyết định một sự cố chỉ là gián đoạn dịch vụ hay là sự kiện khiến công ty sụp đổ.

Đặt một CDN hoặc WAF (Cloudflare, Fastly, AWS CloudFront kèm WAF hoặc dịch vụ tương đương của nhà cung cấp hosting) trước máy chủ gốc. Nó hấp thụ DDoS dạng volumetric, áp dụng các quy tắc được quản lý cho payload injection phổ biến và bot xấu, ẩn IP máy chủ gốc, và cho bạn một nơi để áp dụng giới hạn tốc độ và quy tắc theo địa lý mà không phải chạm vào ứng dụng. Sau đó hãy siết tường lửa của máy chủ gốc để chỉ các dải IP của CDN mới truy cập trực tiếp được cổng 443; nếu không, kẻ tấn công sẽ đơn giản đi vòng qua nó. Kiểm tra Hosting cho biết CDN nào đứng trước một website và bằng chứng công khai nói gì về nhà cung cấp hosting phía sau.

Xác thực email: SPF, DKIM và DMARC

Bảo mật web bao gồm cả email chuyển đi thư đặt lại mật khẩu, hóa đơn và phản hồi hỗ trợ của bạn. Không có SPF, DKIM và DMARC, bất kỳ ai cũng có thể gửi thư dưới tên billing@yourdomain.com; từ tháng 2/2024 Google và Yahoo yêu cầu cả ba từ các bên gửi thư hàng loạt, và từ tháng 5/2025 Microsoft cũng yêu cầu như vậy với Outlook.com. Bộ đầy đủ gồm ba bản ghi TXT trong DNS:

dns
yourdomain.com.                    TXT  "v=spf1 include:_spf.google.com -all"
google._domainkey.yourdomain.com.  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
_dmarc.yourdomain.com.             TXT  "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; adkim=s; aspf=s"

DMARC p=reject cũng là một biện pháp bảo vệ thương hiệu: đó là thứ duy nhất ngăn một chiến dịch phishing đặt chính xác tên miền của bạn vào dòng From. Các báo cáo tổng hợp (rua=) cho bạn thấy ai đang cố làm điều đó.

Hãy bắt đầu DMARC ở p=none để thu báo cáo, chuyển sang p=quarantine rồi p=reject khi mọi bên gửi hợp lệ (nền tảng marketing, helpdesk, CRM) đều qua được alignment. Thêm các bản ghi MTA-STS và TLS-RPT để buộc việc gửi thư đến máy chủ mail của bạn phải được mã hóa. Trên các tên miền không bao giờ gửi hoặc nhận thư, hãy đăng null MX (MX 0 .), v=spf1 -all và một bản ghi DMARC với p=reject: null MX chỉ nói rằng tên miền không nhận thư, còn SPF và DMARC mới giúp bên nhận từ chối thư giả mạo. Hãy kiểm tra từng bản ghi bằng Kiểm Tra Bản Ghi SPF, Kiểm Tra DKIM và Kiểm Tra DMARC, và nếu khả năng gửi thư tụt, hãy đối chiếu các IP gửi thư của bạn với danh sách chặn bằng Kiểm Tra Danh Sách Đen IP.

Ghi log, giám sát và lên kế hoạch cho sự cố

Hai trong số mười hạng mục của OWASP 2025 nói về những gì xảy ra sau một sai sót: Security Logging and Alerting Failures (A09) và hạng mục mới Mishandling of Exceptional Conditions (A10). Một vụ xâm phạm điển hình vẫn không bị phát hiện trong nhiều tháng vì bằng chứng chưa bao giờ được ghi lại, hoặc đã được ghi lại nhưng không ai xem.

  • Ghi log sự kiện bảo mật kèm ngữ cảnh: mọi lần đăng nhập thành công và thất bại, thay đổi MFA, đặt lại mật khẩu, thay đổi quyền, các lần bị từ chối truy cập, lỗi kiểm tra đầu vào và thao tác quản trị, mỗi sự kiện kèm dấu thời gian, user ID, IP nguồn và user agent.
  • Không bao giờ ghi log secret: mật khẩu, token phiên, số thẻ đầy đủ, API key. Hãy che chúng ở tầng logging, không phải ở từng chỗ gọi.
  • Đẩy log ra khỏi máy chủ tới một kho lưu trữ tập trung (CloudWatch, Loki, Elastic, một SIEM) với thời gian lưu giữ ít nhất 90 ngày, để kẻ tấn công có quyền root cũng không thể xóa dấu vết.
  • Cảnh báo theo mẫu hình, không theo sự kiện đơn lẻ: 50 lần đăng nhập thất bại trong một phút, số 403 tăng vọt từ một phiên, một tài khoản admin mới được tạo ngoài giờ làm việc, một chứng chỉ được cấp cho tên miền của bạn mà bạn không hề yêu cầu.
  • Fail closed (lỗi thì từ chối): khi một bước kiểm tra phía sau (dịch vụ xác thực, bộ giới hạn tốc độ, WAF) gặp lỗi, hãy từ chối request. A10 tồn tại vì quá nhiều hệ thống lại cấp quyền truy cập khi chính bước kiểm tra lẽ ra phải chặn request lại ném ra một exception.
  • Giám sát từ bên ngoài: thời gian hoạt động (uptime), hạn chứng chỉ, thay đổi DNS, việc bị đưa vào danh sách chặn và các header bị thụt lùi. Hãy chạy lại Kiểm Tra Chứng Chỉ SSL, Kiểm Tra Header HTTP và Kiểm tra sức khỏe DNS (40 mục kiểm tra về ủy quyền, nameserver, DNSSEC và SPF/DMARC) sau mỗi lần deploy.

Viết kế hoạch ứng phó sự cố trước khi cần đến

Hãy quyết định trước ai trực, cách xoay vòng mọi thông tin xác thực, cách chuyển website sang chế độ chỉ đọc, nơi lưu các bản sao lưu sạch, và cơ quan quản lý hay khách hàng nào phải được thông báo trong bao nhiêu giờ (72 giờ theo GDPR). Hãy diễn tập tình huống trên bàn (tabletop) mỗi năm một lần. Một kế hoạch đã được diễn tập biến nhiều ngày xoay xở ứng biến thành một checklist.

Hãy đăng một file security.txt tại /.well-known/security.txt (RFC 9116) với dòng Contact: và ngày Expires:, hai trường bắt buộc (khóa Encryption: là tùy chọn). Các nhà nghiên cứu tìm ra lỗi trong website của bạn sẽ xem ở đó trước; nếu không có, họ có thể không tìm được ai để báo.

Kiểm thử: công cụ quét, pentest và kiểm tra liên tục

Mọi biện pháp ở trên đều có thể kiểm chứng, và việc kiểm chứng nên được tự động hóa bất cứ khi nào có thể để nó không bị mai một theo thời gian. Một lộ trình hợp lý, từ miễn phí và tức thì đến định kỳ và trả phí:

Hạng mục kiểm traCông cụTần suất
Cấu hình TLS, chuỗi chứng chỉ, hạn sử dụngKiểm Tra Chứng Chỉ SSL, SSL Labs, testssl.shSau mỗi thay đổi chứng chỉ hoặc máy chủ; kiểm tra hạn hằng ngày
Security header và CSPKiểm Tra Header HTTP, MDN HTTP ObservatorySau mỗi lần deploy (đưa vào CI)
Cổng đang mởKiểm Tra Cổng, nmap từ bên ngoài mạng của bạnSau mỗi thay đổi tường lửa hoặc cloud
DNS, DNSSEC, xác thực emailKiểm tra sức khỏe DNS, Kiểm Tra DMARCHằng tháng, và sau mỗi lần chỉnh sửa DNS
Subdomain bị bỏ quênTìm Tên Miền PhụHằng quý và mỗi lần ngừng một dịch vụ
Thư viện phụ thuộc có lỗ hổng đã biếtnpm audit, Dependabot, TrivyMỗi lần build
Lỗi ở mức code (SAST)Semgrep, CodeQLMỗi pull request
Lỗ hổng web khi đang chạy (DAST)ZAP, NucleiHằng tuần trên môi trường staging
Phân quyền và logic nghiệp vụKiểm thử xâm nhập thủ công hoặc chương trình bug bountyHằng năm, và sau các tính năng lớn

Công cụ quét giỏi phát hiện injection, header và thành phần lỗi thời nhưng kém ở phân quyền và logic nghiệp vụ, vì vậy hãy dành ngân sách cho ít nhất một đợt kiểm thử bởi con người mỗi năm với bất cứ thứ gì xử lý tiền hoặc dữ liệu cá nhân. Ưu tiên khắc phục theo mức độ phơi nhiễm: bất cứ lỗ hổng nào mà người dùng chưa xác thực có thể khai thác từ internet phải được xử lý đầu tiên.

Checklist bảo mật website

Hãy sao chép bảng này vào README hoặc hệ thống quản lý ticket của dự án. Mỗi dòng là một biện pháp ở trên, được diễn đạt để có thể đánh dấu đã xong hay chưa; cột cuối cùng là bằng chứng.

LớpBiện phápHoàn thành khi
Tên miềnRegistrar lock và MFA trên tài khoản registrar; bật tự động gia hạnWHOIS hiển thị clientTransferProhibited; còn hơn 12 tháng mới hết hạn
DNSĐã ký DNSSEC; bản ghi CAA chỉ liệt kê các CA của bạndig +dnssec trả về RRSIG; có bản ghi DS ở zone cha
DNSKhông có bản ghi CNAME hoặc A trỏ vào dịch vụ đã bỏ (dangling)Mọi hostname tìm được bằng công cụ Tìm Tên Miền Phụ đều phân giải về thứ bạn kiểm soát
TLSChỉ TLS 1.2+, ưu tiên TLS 1.3, phục vụ đầy đủ chuỗi chứng chỉKiểm Tra Chứng Chỉ SSL: chuỗi đầy đủ, TLS 1.0/1.1 bị từ chối
TLSHSTS với max-age một năm và includeSubDomains (preload tùy chọn)Kiểm Tra Header HTTP đạt bài kiểm tra HSTS
TLSGia hạn tự động qua ACME; hạn chứng chỉ được giám sátcertbot renew --dry-run chạy thành công; cảnh báo đặt ở mốc 14 ngày
HeaderCSP (dựa trên nonce), frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyKiểm Tra Header HTTP chấm điểm A hoặc A+
Xác thựcBăm bằng Argon2id hoặc bcrypt; quy tắc mật khẩu theo NIST; đối chiếu danh sách rò rỉMột lần băm mất 100 đến 250 ms; không có quy tắc về thành phần
Xác thựcMFA cho mọi người dùng, bắt buộc với admin; hỗ trợ passkeyKhông thể đăng nhập admin nếu thiếu yếu tố thứ hai
Xác thựcEndpoint đăng nhập, đặt lại mật khẩu và MFA bị giới hạn tốc độ theo IP và theo tài khoảnSáu lần thử nhanh từ một IP: lần thứ sáu trả về 429
SessionCookie __Host- với Secure, HttpOnly, SameSite; ID được cấp lại khi đăng nhậpThuộc tính cookie hiển thị trong DevTools; session cũ mất hiệu lực sau khi đăng nhập
Đầu vàoTruy vấn tham số hóa ở mọi nơi; đầu ra được mã hóa theo ngữ cảnh; file upload được kiểm tra theo nội dungTìm trong code không thấy truy vấn nối chuỗi nào; payload XSS hiển thị dưới dạng văn bản
Kiểm soát truy cậpRouting mặc định từ chối; kiểm tra quyền sở hữu từng đối tượng; CORS nghiêm ngặtPhát lại request với ID của người dùng khác trả về 404 hoặc 403
Thư viện phụ thuộcĐã commit lockfile; npm ci; audit trong CI; action được ghim theo SHA; SRI cho script từ CDNBản build thất bại khi có CVE mức nghiêm trọng cao
Máy chủChỉ 80 và 443 công khai; SSH chỉ dùng key; cập nhật bảo mật tự động; secret nằm trong biến môi trường hoặc vaultKiểm Tra Cổng cho thấy 3306 và 6379 đóng hoặc bị lọc, và cả 22 nữa khi nhìn từ ngoài dải của chính bạn
Sao lưu3-2-1 với một bản sao bất biến; đã thử khôi phụcLần thử khôi phục thành công gần nhất nằm trong vòng 90 ngày
EmailSPF -all, DKIM, DMARC p=reject, MTA-STSKiểm Tra DMARC đạt; báo cáo tổng hợp đang được gửi về
Giám sátSự kiện xác thực và phân quyền được ghi log tập trung; cảnh báo theo mẫu hình; giám sát uptime, chứng chỉ và DNS từ bên ngoàiĐã kích hoạt thử một cảnh báo và nhận được
Ứng phóCó kế hoạch ứng phó sự cố bằng văn bản; đã công bố security.txt; đã diễn tập tabletopKế hoạch được rà soát trong vòng 12 tháng gần nhất

Đối chiếu với OWASP Top 10:2025

OWASP Top 10 là danh sách rủi ro ứng dụng web được trích dẫn nhiều nhất, và phiên bản 2025 đã sắp xếp lại thứ tự cũng như bổ sung hai hạng mục mới. Nếu khách hàng, kiểm toán viên hay một khung tuân thủ hỏi bạn xử lý các rủi ro này thế nào, đây là bảng đối chiếu với các biện pháp trong hướng dẫn này:

OWASP Top 10:2025Biện pháp trong hướng dẫn này
A01 Broken Access ControlMặc định từ chối, kiểm tra từng đối tượng, CORS nghiêm ngặt, khóa chặt trang quản trị
A02 Security MisconfigurationSecurity header, HSTS, đóng cổng, gỡ header lộ phiên bản, tắt liệt kê thư mục
A03 Software Supply Chain Failures (mới)Lockfile, audit, ghim action, SRI, SBOM, CI đặc quyền tối thiểu
A04 Cryptographic FailuresTLS 1.2+ và 1.3, HSTS, Argon2id, quản lý secret, mã hóa bản sao lưu
A05 InjectionTruy vấn tham số hóa, mã hóa đầu ra, CSP, kiểm tra file upload
A06 Insecure DesignMô hình hóa mối đe dọa cho từng lớp, mặc định fail closed, rate limiting ngay từ khâu thiết kế
A07 Authentication FailuresQuy tắc mật khẩu NIST, kiểm tra rò rỉ, MFA và passkey, cấp lại session
A08 Software or Data Integrity FailuresSRI, thư viện phụ thuộc được ký và ghim, deserialization an toàn
A09 Security Logging and Alerting FailuresLog tập trung, cảnh báo theo mẫu hình, giám sát từ bên ngoài
A10 Mishandling of Exceptional Conditions (mới)Fail closed, phản hồi lỗi thống nhất, không hiển thị stack trace cho người dùng

ASVS (Application Security Verification Standard) của OWASP biến cùng nội dung này thành một checklist được đánh số dùng cho kiểm toán. Level 1 là mục tiêu thực tế cho mọi website công khai; Level 2 dành cho bất cứ thứ gì xử lý dữ liệu cá nhân hoặc tài chính.

Kiểm tra security header của website chỉ trong vài giây

Công cụ Kiểm Tra Header HTTP miễn phí của DNS Robot cho thấy header phản hồi của bất kỳ URL nào đúng như máy chủ gửi và chấm điểm các security header bằng bài kiểm tra của Mozilla HTTP Observatory, kèm cách sửa cho từng mục còn thiếu. Không cần đăng ký.

Nguồn

  1. 2026 Data Breach Investigations Report, Verizon
  2. OWASP Top 10:2025, OWASP
  3. Password Storage Cheat Sheet, OWASP
  4. SP 800-63B-4: Authentication and Authenticator Management, NIST
  5. Ballot SC-081v3: reducing certificate validity and data reuse periods, CA/Browser Forum
  6. HTTPS by default, Google
  7. RFC 9116: A File Format to Aid in Security Vulnerability Disclosure, IETF

Câu hỏi thường gặp về bảo mật website

Những biện pháp bảo mật website quan trọng nhất là gì?

Bắt buộc HTTPS với TLS hiện đại và HSTS, gửi các security header nghiêm ngặt (đặc biệt là Content Security Policy), băm mật khẩu bằng Argon2id kèm MFA và rate limiting, dùng truy vấn tham số hóa và mã hóa đầu ra, kiểm soát truy cập trên máy chủ cho từng đối tượng, giữ thư viện phụ thuộc luôn được vá và ghim phiên bản, đóng các cổng không dùng, và ghi log sự kiện bảo mật tập trung. Hãy khóa chặt tên miền và DNS trước tiên, vì mọi thứ khác đều phụ thuộc vào việc bạn vẫn kiểm soát được tên miền của mình.

OWASP Top 10 là gì và năm 2026 có còn quan trọng không?

OWASP Top 10 là bảng xếp hạng do cộng đồng duy trì về các rủi ro bảo mật ứng dụng web nghiêm trọng nhất. Phiên bản 2025 gồm Broken Access Control, Security Misconfiguration, Software Supply Chain Failures, Cryptographic Failures, Injection, Insecure Design, Authentication Failures, Software or Data Integrity Failures, Security Logging and Alerting Failures và Mishandling of Exceptional Conditions. Đây vẫn là tài liệu tham chiếu mà phần lớn các cuộc kiểm toán, khung tiêu chuẩn và khách hàng dựa vào.

Website nên gửi những HTTP security header nào?

Tối thiểu gồm: Strict-Transport-Security, Content-Security-Policy (bao gồm frame-ancestors), X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin và Permissions-Policy. X-Frame-Options: DENY là phương án dự phòng kiểu cũ cho frame-ancestors, còn Cross-Origin-Opener-Policy: same-origin là phần bổ sung dễ thêm. Hãy gỡ bỏ Server và X-Powered-By để công cụ quét không đọc được phiên bản phần mềm của bạn.

Chỉ cần HTTPS là website đã an toàn chưa?

Không. HTTPS mã hóa lưu lượng giữa trình duyệt và máy chủ; nó không làm gì với injection, kiểm soát truy cập hỏng, mật khẩu yếu, thư viện phụ thuộc có lỗ hổng hay cổng cơ sở dữ liệu đang mở. Đó là lớp nền tảng, và HSTS làm nó bền vững: khi trình duyệt đã thấy header, nó sẽ không bao giờ gửi yêu cầu HTTP thường tới tên miền của bạn nữa.

Nên lưu mật khẩu người dùng như thế nào?

Không bao giờ lưu dạng văn bản thuần và không bao giờ dùng hàm băm nhanh như MD5 hay SHA-256. Hãy dùng Argon2id (19 MiB bộ nhớ, 2 vòng lặp) hoặc bcrypt với hệ số công việc từ 10 trở lên, kèm salt riêng cho mỗi mật khẩu, điều chỉnh sao cho một lần băm mất khoảng 100 đến 250 ms. Đối chiếu mật khẩu mới với danh sách rò rỉ và bắt buộc MFA cho các tài khoản đặc quyền.

Content Security Policy là gì và website có cần không?

CSP là một HTTP header cho trình duyệt biết trang được phép tải script, style, frame và các tài nguyên khác từ những nguồn nào. Một CSP dựa trên nonce với 'strict-dynamic' chặn được phần lớn cross-site scripting ngay cả khi tồn tại lỗi injection. Mọi website hiển thị nội dung do người dùng cung cấp hoặc tải script bên thứ ba đều nên có; hãy bắt đầu ở chế độ report-only và chuyển sang chế độ thực thi khi các báo cáo vi phạm đã sạch.

Làm sao để kiểm tra bảo mật website của tôi?

Hãy chạy các kiểm tra từ ngoài vào trước: kiểm tra SSL cho phiên bản TLS, chuỗi chứng chỉ và hạn dùng; kiểm tra header HTTP cho các security header; kiểm tra cổng cho các dịch vụ bị lộ; và kiểm tra sức khỏe DNS cho DNSSEC và SPF/DMARC. Sau đó quét các thư viện phụ thuộc bằng npm audit hoặc công cụ tương đương cho stack của bạn, chạy ZAP trên bản staging, và tự kiểm tra kiểm soát truy cập bằng cách phát lại các yêu cầu với tư cách người dùng khác.

Vì sao thời hạn chứng chỉ TLS ngày càng ngắn hơn?

CA/Browser Forum đã bỏ phiếu rút ngắn thời hạn tối đa của chứng chỉ từ 398 ngày xuống 200 ngày (15/3/2026), 100 ngày (15/3/2027) và 47 ngày (15/3/2029), vì chứng chỉ ngắn hạn hạn chế thiệt hại khi khóa bị đánh cắp hoặc chứng chỉ bị cấp sai, đồng thời giảm sự phụ thuộc vào cơ chế thu hồi. Hệ quả thực tế là việc gia hạn phải được tự động hóa bằng ACME.

Bao lâu nên cập nhật thư viện phụ thuộc của website một lần?

Áp dụng bản vá bảo mật ngay khi được phát hành, lý tưởng là trong vòng 24 giờ với bất cứ thứ gì tiếp xúc với internet, và chạy audit tự động trong mỗi lần build. Với các bản cập nhật không liên quan đến bảo mật, chờ vài ngày sẽ an toàn hơn, vì các bản phát hành package bị xâm nhập thường bị gỡ xuống nhanh chóng; các công cụ như Renovate có thể tự động áp dụng khoảng trễ đó.

Website nhỏ có thực sự bị tấn công không?

Có, và liên tục, vì các cuộc tấn công được tự động hóa và không chọn mục tiêu theo quy mô. Công cụ quét dò mọi địa chỉ IP công khai để tìm cổng mở và lỗ hổng CMS đã biết, còn công cụ credential stuffing thử mật khẩu bị rò rỉ trên mọi form đăng nhập chúng tìm thấy. Một website nhỏ cũng có giá trị như một nơi chứa trang phishing, một trạm chuyển tiếp spam hay một bàn đạp để xâm nhập vào một khách hàng lớn hơn.

Về tác giả

Shaik Vahid

Nhà sáng lập DNS Robot. Vahid đã làm nhiều năm trong bộ phận hỗ trợ hosting, xử lý tên miền, bản ghi DNS, chứng chỉ SSL và việc gửi email cho khách hàng. Anh xây dựng các công cụ của DNS Robot và viết những hướng dẫn này từ các lỗi mà mọi người thực sự gặp.

Kiểm tra HTTP Header

Phân tích header phản hồi HTTP và chấm điểm header bảo mật