Wavi Books · Kỹ nghệ phần mềm & Clean Code
AI viết code có an toàn không? Cách review bảo mật trước khi merge pull request
Nguyễn Minh Trí · Biên tập chuyên môn Wavi Books

Checklist review bảo mật code do AI tạo: injection, phân quyền, secret, SSRF, dependency và cách dùng code scanning mà không phó mặc quyết định cho AI.
## Agent thêm một API đọc ảnh từ URL — và vô tình mở cửa vào mạng nội bộ
Ticket nghe rất bình thường: cho phép khách dán đường dẫn ảnh, hệ thống tải ảnh về rồi tạo thumbnail. Coding agent dựng endpoint nhanh, kiểm tra content type, giới hạn dung lượng và viết đủ unit test. Pull request nhìn sạch, test xanh, reviewer dễ bấm Approve.
Nhưng URL là dữ liệu do người dùng kiểm soát. Nếu server có thể gọi bất kỳ địa chỉ nào, kẻ tấn công có thể thử `localhost`, dải IP nội bộ, metadata service của cloud hoặc một tên miền chuyển hướng vào hệ thống phía sau firewall. Đây là SSRF — Server-Side Request Forgery. Code không lỗi cú pháp. Tính năng cũng chạy đúng demo. Sai ở ranh giới tin cậy.
Đây là kiểu lỗ hổng AI rất dễ tạo khi yêu cầu chỉ mô tả luồng thành công. Agent tối ưu cho việc ‘tải được ảnh’, trong khi sản phẩm thật cần trả lời thêm: server được phép kết nối tới đâu, redirect có được theo không, DNS thay đổi giữa lúc kiểm tra và kết nối thì xử lý thế nào, timeout và kích thước phản hồi giới hạn ra sao?
GitHub đưa AI-powered security detections vào pull request ở trạng thái public preview ngày 14/07/2026. Công cụ mở rộng phát hiện sang những ngôn ngữ và framework chưa được CodeQL bao phủ đầy đủ, đồng thời gắn nhãn AI để reviewer phân biệt. Điểm đáng chú ý: các finding này mang tính tư vấn và chưa tự chặn merge. Nói cách khác, công cụ chỉ đưa thêm tín hiệu; trách nhiệm quyết định vẫn nằm ở con người.
## AI viết code có an toàn không?
Câu trả lời ngắn là: AI có thể viết code an toàn, nhưng không có lý do gì để mặc định code do AI tạo là an toàn. Model sinh lời giải từ pattern, ngữ cảnh repository và yêu cầu được cung cấp. Nếu threat model, quy tắc phân quyền hoặc đặc thù hạ tầng không nằm trong ngữ cảnh, lời giải hợp lý nhất theo thống kê có thể sai với hệ thống của bạn.
Con người cũng viết lỗ hổng. Khác biệt nằm ở tốc độ và quy mô. Một developer có thể thêm vài chục dòng thiếu kiểm tra quyền; agent có thể triển khai endpoint, migration, workflow CI và dependency mới trong cùng một lần chạy. Khi lượng thay đổi tăng nhanh hơn khả năng review, xác suất bỏ sót tăng theo.
Bởi vậy, đừng tranh luận ‘AI hay con người viết code tốt hơn’ theo kiểu tuyệt đối. Câu hỏi thực tế hơn là: quy trình nào khiến mọi thay đổi — bất kể do ai tạo — phải đưa ra đủ bằng chứng trước khi được merge?
## Security review khác code review thông thường ở đâu?
Code review thông thường thường nhìn correctness, readability, test và kiến trúc. Security review thêm một lớp câu hỏi về cách hệ thống phản ứng trước đầu vào có chủ đích xấu. Người review không chỉ hỏi ‘luồng này có chạy không’, mà hỏi ‘một người muốn lạm dụng nó sẽ điều khiển được dữ liệu, quyền và tài nguyên nào’.
Một cách dễ nhớ là vẽ ba thứ: tài sản cần bảo vệ, ranh giới tin cậy và khả năng của kẻ tấn công. Tài sản có thể là dữ liệu khách hàng, token, tiền, quyền quản trị hoặc tài nguyên cloud. Ranh giới tin cậy nằm giữa browser và API, service và database, hệ thống của bạn và dịch vụ bên thứ ba. Khả năng của kẻ tấn công gồm gửi request tùy ý, thay đổi tham số, gọi lại request, tạo nhiều tài khoản và quan sát phản hồi.
Khi ba phần này rõ, checklist bảo mật không còn là danh sách học thuộc. Nó trở thành cách kiểm tra từng đường dữ liệu có vượt qua ranh giới mà thiếu xác thực, kiểm soát quyền, xác thực đầu vào hoặc log phù hợp hay không.
## Chín nhóm lỗi cần nhìn trước khi merge code do AI tạo
### 1. Broken access control — đăng nhập rồi chưa chắc được phép
Lỗi phổ biến nhất không phải quên đăng nhập, mà là kiểm tra quyền ở sai chỗ. API `/orders/:id` xác nhận người gọi có token nhưng không kiểm tra đơn hàng có thuộc người đó hay không. UI ẩn nút quản trị nhưng endpoint vẫn nhận request trực tiếp. Agent dễ tái sử dụng middleware authentication và bỏ qua authorization theo tài nguyên.
Hãy kiểm tra quyền ở server, gần dữ liệu cần bảo vệ. Test phải có ít nhất hai người dùng và chứng minh người A không đọc, sửa hoặc xóa tài nguyên của người B. Với role quản trị, test cả trường hợp role bị hạ trong khi session cũ còn sống.
### 2. Injection — string đẹp vẫn có thể là câu lệnh nguy hiểm
SQL injection, command injection, HTML injection và template injection đều bắt đầu từ việc dữ liệu không tin cậy được ghép vào ngôn ngữ có khả năng thực thi. Agent có thể dùng parameterized query ở một chỗ nhưng lại ghép chuỗi cho `ORDER BY`, câu lệnh shell hoặc tên file.
Đừng chỉ tìm dấu cộng nối chuỗi. Hãy lần theo dữ liệu từ request tới database, shell, template, JSON/YAML parser và log. Mỗi nơi có quy tắc escaping khác nhau; sanitize chung một lần ở đầu vào thường không đủ.
### 3. Secret và dữ liệu nhạy cảm — debug log có thể trở thành sự cố
Một bản sửa lỗi nhanh thường thêm log toàn bộ request, response hoặc environment. Điều này hữu ích trên máy cá nhân nhưng có thể đưa access token, cookie, mật khẩu, email và dữ liệu thanh toán vào hệ thống log mà nhiều người truy cập.
Review mọi log mới, file cấu hình, fixture test và workflow CI. Secret phải nằm trong secret manager hoặc biến môi trường được kiểm soát; log cần redaction; lỗi trả về client không được lộ stack trace hay cấu trúc nội bộ.
### 4. SSRF — server không nên đi đến mọi URL người dùng đưa
Nếu code fetch URL do người dùng cung cấp, hãy xem xét allowlist protocol và host, chặn dải IP riêng, xử lý redirect, DNS rebinding, giới hạn timeout, kích thước phản hồi và số lần retry. Chỉ kiểm tra chuỗi URL trước khi gọi chưa chắc đủ vì tên miền có thể phân giải thành IP khác.
### 5. Authentication — luồng đăng nhập không kết thúc ở việc nhận được token
Kiểm tra xác thực issuer, audience, signature, thời gian hết hạn và nonce/state khi dùng OAuth/OIDC. Reset mật khẩu và magic link cần token dùng một lần, TTL ngắn và rate limit. Thông báo lỗi không nên giúp kẻ tấn công xác định email nào tồn tại.
### 6. Cryptography — đừng tự chế thuật toán để ‘nhẹ hơn’
Agent có thể đề xuất hash nhanh cho mật khẩu, random không phù hợp cho token hoặc chế độ mã hóa thiếu xác thực toàn vẹn. Với mật khẩu, dùng thư viện và thuật toán chuyên dụng như Argon2id, scrypt hoặc bcrypt theo chính sách hệ thống. Với token, dùng nguồn ngẫu nhiên mật mã và đủ entropy.
### 7. Deserialization và integrity — dữ liệu có chữ ký mới đáng tin
Đừng thực thi hoặc deserialize đối tượng từ nguồn không tin cậy bằng cơ chế có thể gọi code. Webhook cần xác minh chữ ký trên raw body, kiểm tra timestamp và chống replay. File tải về, artifact build và model AI cần nguồn đáng tin cùng kiểm tra integrity khi phù hợp.
### 8. Dependency và supply chain — một package mới là một quan hệ tin cậy mới
OWASP Top 10:2025 đặt Software Supply Chain Failures ở vị trí A03. Khi agent thêm package để tiết kiệm 20 dòng code, reviewer cần xem package đến từ đâu, còn được duy trì không, quyền post-install là gì, phiên bản có được khóa và dependency lồng nhau có tạo rủi ro không.
Đừng đánh giá dependency chỉ bằng số sao. Kiểm tra repository chính thức, release, maintainer, license, CVE, kích thước cây phụ thuộc và khả năng tự viết phần nhỏ đó. Workflow CI, action và container image cũng là dependency.
### 9. Exceptional conditions — lỗi mạng và timeout là một phần của thiết kế
OWASP Top 10:2025 tách riêng Mishandling of Exceptional Conditions. Agent thường viết rất tốt happy path nhưng xử lý timeout bằng retry vô hạn, nuốt exception hoặc trả trạng thái thành công dù dữ liệu mới ghi một nửa. Với thanh toán và workflow phân tán, lỗi một phần phải có idempotency, trạng thái trung gian, đối soát và quan sát vận hành.
## AI security detection và CodeQL nên đứng ở đâu trong pipeline?
Static analysis phù hợp để quét tự động và lặp lại theo mỗi pull request. CodeQL có độ chính xác cao trên tập ngôn ngữ và query được hỗ trợ. AI-powered detections bổ sung vùng ngôn ngữ hoặc framework còn thiếu, sử dụng thêm ngữ cảnh code và code search để đưa ra finding.
Hai loại tín hiệu không thay thế nhau. Finding AI có thể có false positive; chính GitHub cũng ghi rõ giới hạn này. Trong public preview, chúng chỉ phân tích pull request, không tạo backlog cho toàn repository và chưa dùng được trực tiếp trong ruleset để chặn merge. Vì vậy, team cần biết công cụ đang nhìn phần diff nào và phần nào vẫn là điểm mù.
Một pipeline hợp lý có nhiều lớp: formatter/lint cho lỗi hình thức; unit và integration test cho hành vi; SAST/CodeQL cho pattern lỗ hổng; secret scanning cho credential; dependency review và SBOM cho chuỗi cung ứng; DAST hoặc kiểm thử môi trường chạy; cuối cùng là human review dựa trên threat model.
Không lớp nào một mình chứng minh phần mềm an toàn. Chúng giảm xác suất và rút ngắn thời gian phát hiện theo những cách khác nhau.
## Cách triage một finding do AI tạo mà không phí thời gian
Bước đầu tiên là xác nhận đường dữ liệu: đầu vào đến từ đâu, đi qua những hàm nào và tới sink nào. Nếu finding nói injection nhưng dữ liệu đã được parameterize đúng, ghi rõ bằng chứng và phản hồi false positive. Nếu rủi ro thật, xác định phạm vi ảnh hưởng trước khi chấp nhận autofix.
Bước thứ hai là đọc bản sửa như một thay đổi hành vi. Một autofix có thể chặn payload hợp lệ, đổi encoding, phá tương thích hoặc chỉ che triệu chứng ở một endpoint. Hãy thêm test tái hiện lỗ hổng trước, áp dụng sửa, rồi chứng minh test không còn vượt qua.
Bước thứ ba là tìm lỗi cùng họ. Nếu một endpoint thiếu authorization, rất có thể endpoint tương tự cũng thiếu. Nếu secret lọt vào log, hãy kiểm tra middleware chung. Sửa một dòng nhưng bỏ lại pattern lặp trong codebase chỉ làm dashboard đẹp hơn.
Bước cuối cùng là ghi lại quyết định. NIST SSDF khuyến nghị đưa kết quả code review/code analysis, triage và remediation vào workflow phát triển. Lịch sử này giúp team phân biệt ngoại lệ có chủ đích với lỗi bị bỏ quên.
## Checklist 12 câu trước khi bấm Merge
1. Dữ liệu nào trong thay đổi này do người dùng hoặc hệ thống bên ngoài kiểm soát? 2. Authorization có được kiểm tra ở server và theo đúng tài nguyên không? 3. Có dữ liệu nào đi vào SQL, shell, HTML, template hoặc parser bằng nối chuỗi không? 4. Log và lỗi trả về có chứa token, cookie, dữ liệu cá nhân hoặc stack trace không? 5. Có request từ server tới URL do người dùng ảnh hưởng không? 6. Token có kiểm tra signature, issuer, audience, expiry và chống replay không? 7. Random, hash và encryption có dùng thư viện/thuật toán phù hợp không? 8. Dependency, action hoặc container image mới đến từ nguồn nào và có khóa phiên bản không? 9. Timeout, retry và lỗi một phần có tạo giao dịch trùng hoặc trạng thái mồ côi không? 10. Test có chứng minh người dùng không đủ quyền bị từ chối không? 11. Finding từ tool đã được triage với bằng chứng hay chỉ bị dismiss để merge? 12. Nếu lỗi xảy ra production, log, metric, alert và rollback đã đủ chưa?
## Một kế hoạch 30 ngày cho team chưa có AppSec chuyên trách
**Tuần 1 — lập bản đồ rủi ro:** chọn một repository quan trọng, liệt kê dữ liệu nhạy cảm, endpoint public, quyền người dùng, dependency và luồng CI/CD. Bật secret scanning, dependency review và code scanning phù hợp. Chưa dùng số finding làm KPI.
**Tuần 2 — security checklist trong pull request:** thêm câu hỏi ngắn theo loại thay đổi. PR authentication phải có test authorization; PR fetch URL phải kiểm tra SSRF; PR thêm dependency phải giải thích nguồn và lý do. Chỉ checklist liên quan mới xuất hiện để tránh hình thức.
**Tuần 3 — chặn một số rủi ro chắc chắn:** yêu cầu xử lý alert mức nghiêm trọng cao, secret thật và dependency có CVE phù hợp trước merge. Với AI finding còn ở preview, dùng như advisory và theo dõi false positive thay vì biến nó thành cổng chặn mù quáng.
**Tuần 4 — diễn tập một tình huống:** chọn một lỗi như token lộ trong log hoặc endpoint thiếu authorization. Đi từ phát hiện, triage, sửa, rotate secret, thông báo và retrospective. Team chỉ biết quy trình incident có hoạt động khi đã thử nó.
## Secure coding là kỹ năng thiết kế, không phải một nút quét
Công cụ giúp nhìn ra pattern, nhưng phần khó nhất vẫn là hiểu hệ thống đang bảo vệ điều gì. Broken access control cần hiểu ownership dữ liệu. SSRF cần hiểu mạng nội bộ. Retry thanh toán cần hiểu idempotency. Supply chain cần hiểu đường đi từ source code tới artifact production.
[Clean Code, 2nd Edition bản tiếng Việt](/sach/clean-code-robert-c-martin-2026) giúp developer viết code rõ ý định và dễ review hơn. [Building Microservices, 2nd Edition bản tiếng Việt](/sach/building-microservices-sam-newman-2026) giúp nhìn ranh giới dịch vụ, giao tiếp và vận hành — nơi nhiều quyết định bảo mật thật sự nằm. [Designing Data-Intensive Applications, 2nd Edition bản tiếng Việt](/sach/designing-data-intensive-applications-martin-kleppmann-2026) mở rộng góc nhìn về dữ liệu, consistency và failure trong hệ thống phân tán.
Wavi Books phụ trách biên phiên dịch, dữ liệu sản phẩm và nội dung chuyên môn cho sách lập trình tiếng Việt. 89ebook là đối tác thương mại độc quyền phân phối sách tiếng Việt của Wavi Books tại Việt Nam trong thời điểm hiện tại. AI có thể viết phần lớn code của một feature. Quyền quyết định feature đó có đủ an toàn để phục vụ người dùng thật vẫn phải có một con người đứng tên.
Nguồn tham khảo và tài liệu đối chiếu
Sách liên quan
Câu hỏi thường gặp
AI viết code có an toàn không?
AI có thể tạo code an toàn nhưng không nên được mặc định là an toàn. Mức an toàn phụ thuộc ngữ cảnh, threat model, quyền truy cập, kiểm thử và quy trình review trước khi merge.
AI-powered security detection có thay thế CodeQL không?
Không. AI detection bổ sung vùng ngôn ngữ và framework CodeQL chưa bao phủ đầy đủ. CodeQL vẫn cung cấp static analysis độ chính xác cao; hai nguồn tín hiệu nên được dùng bổ trợ.
Finding bảo mật do AI phát hiện có tự chặn merge không?
Theo GitHub ở giai đoạn public preview tháng 7/2026, AI-powered security findings mang tính tư vấn, chưa dùng được trong ruleset để bắt buộc chặn merge và có thể có false positive.
Security code review nên kiểm tra gì trước tiên?
Ưu tiên broken access control, injection, secret và dữ liệu nhạy cảm, SSRF, authentication, cryptography, dependency/supply chain, lỗi một phần và khả năng quan sát khi production xảy ra sự cố.
Có nên áp dụng Copilot Autofix ngay không?
Có thể dùng như đề xuất, nhưng nên viết test tái hiện lỗ hổng, đọc thay đổi hành vi, kiểm tra phạm vi ảnh hưởng và xác nhận bản sửa không phá luồng hợp lệ trước khi merge.