💡 Key Takeaways
- Authentication and Authorization: The Foundation That Everyone Rushes Past
- Request Validation: Where Most Bugs Actually Live
- Response Validation: Trust, But Verify
- State Management and Idempotency: The Subtle Art of Consistency
Ba năm trước, tôi đã chứng kiến một API sản xuất thất bại một cách ngoạn mục vào lúc 2 giờ sáng vì không ai kiểm tra điều gì sẽ xảy ra khi bạn gửi một trường ngày tháng được định dạng là "32/13/2021." Hiệu ứng dây chuyền thật đẹp theo cách tồi tệ nhất có thể: 47.000 giao dịch thất bại, khách hàng tức giận tràn vào các kênh hỗ trợ, và một CEO muốn có câu trả lời mà tôi không có. Đêm đó đã thay đổi cách tôi tiếp cận việc thử nghiệm API mãi mãi.
💡 Những Điều Cần Lưu Ý
- Xác Thực và Phân Quyền: Nền Tảng Mà Mọi Người Đều Vội Vã Bỏ Qua
- Xác Thực Yêu Cầu: Nơi Hầu Hết Các Lỗi Thực Sự Xuất Hiện
- Xác Thực Phản Hồi: Tin Tưởng, Nhưng Kiểm Tra
- Quản Lý Trạng Thái và Idempotency: Nghệ Thuật Tinh Tế Của Sự Nhất Quán
Tôi là Sarah Chen, và tôi đã làm kỹ sư tự động hóa QA trong tám năm qua, năm năm qua tập trung hoàn toàn vào việc thử nghiệm API cho các nền tảng fintech và chăm sóc sức khỏe. Tôi đã thử nghiệm mọi thứ từ các điểm cuối CRUD đơn giản đến các API xử lý thanh toán phức tạp xử lý hàng triệu đô la mỗi ngày. Những gì tôi đã học được là: hầu hết các lỗi API không phải là các trường hợp ngoại lệ kỳ lạ - chúng là những vấn đề có thể dự đoán mà một danh sách kiểm tra có hệ thống sẽ phát hiện được.
Danh sách kiểm tra mà tôi chia sẻ hôm nay là danh sách chính xác mà tôi sử dụng cho từng điểm cuối mà tôi thử nghiệm. Nó đã cứu đội ngũ của tôi khỏi ít nhất một tá sự cố sản xuất chỉ trong năm qua, và nó đã giúp chúng tôi duy trì thời gian hoạt động 99,97% trên hơn 230 điểm cuối API. Đây không phải lý thuyết - đây là thực tế đã được kiểm tra qua chiến đấu từ một người đã được gọi vào lúc 3 giờ sáng nhiều hơn mức tôi muốn nhớ.
Xác Thực và Phân Quyền: Nền Tảng Mà Mọi Người Đều Vội Vã Bỏ Qua
Đây là một thống kê mà nên khiến bạn kinh hoàng: theo kinh nghiệm của tôi khi kiểm toán các API trên bảy công ty khác nhau, khoảng 60% có ít nhất một điểm cuối có logic phân quyền bị hỏng. Không phải xác thực - phân quyền. Điểm cuối đã xác minh bạn đã đăng nhập, nhưng không kiểm tra đúng cách xem bạn có nên truy cập tài nguyên cụ thể đó hay không.
Danh sách kiểm tra xác thực và phân quyền của tôi bắt đầu với những điều cơ bản rõ ràng nhưng thường bị bỏ qua:
- Thử nghiệm với không có mã thông báo xác thực - nên trả về 401
- Thử nghiệm với mã thông báo đã hết hạn - nên trả về 401, không phải 500
- Thử nghiệm với mã thông báo định dạng sai - nên trả về 401, không bị sập
- Thử nghiệm với mã thông báo hợp lệ nhưng sai quyền hạn - nên trả về 403
- Thử nghiệm với mã thông báo của người dùng khác cố gắng truy cập tài nguyên của người dùng khác
Cái cuối cùng là nơi mọi thứ trở nên thú vị. Tôi từng tìm thấy một điểm cuối nơi bạn có thể lấy lịch sử thanh toán của bất kỳ người dùng nào chỉ bằng cách thay đổi ID người dùng trong URL, mặc dù bạn đã được xác thực là một người dùng khác. Điểm cuối đã kiểm tra xem bạn đã đăng nhập hay chưa, nhưng không bao giờ xác minh liệu ID người dùng được yêu cầu có khớp với ID người dùng đã xác thực của bạn hay không. Điều này được gọi là Tham Chiếu Đối Tượng Trực Tiếp Không An Toàn (IDOR), và nó rất phổ biến một cách đáng kinh ngạc.
Tôi cũng kiểm tra các luồng làm mới mã thông báo một cách rõ ràng. Điều gì xảy ra khi một mã thông báo hết hạn giữa yêu cầu? API của bạn xử lý điều đó một cách duyên dáng, hay để lại cho khách hàng trong một trạng thái kỳ lạ? Tôi đã thấy các hệ thống nơi một mã thông báo hết hạn trong khi thực hiện một yêu cầu POST sẽ trả về 401, nhưng dữ liệu vẫn được ghi một phần vào cơ sở dữ liệu. Đó là một cơn ác mộng cho tính nhất quán của dữ liệu.
Đối với các API sử dụng khóa API thay vì mã thông báo, tôi xác minh rằng quy trình xoay vòng khóa hoạt động đúng. Bạn có thể tạo một khóa mới không? Khóa cũ có ngừng hoạt động ngay lập tức, hay có một khoảng thời gian ân hạn? Khoảng thời gian ân hạn đó có được tài liệu không? Tôi từng làm việc với một API mà việc xoay vòng khóa có một khoảng thời gian chồng chéo 24 giờ mà không ai biết về nó, dẫn đến sự thất bại trong kiểm toán bảo mật.
Ma trận phân quyền là vũ khí bí mật của tôi ở đây. Tôi tạo một bảng tính với mỗi điểm cuối trên một trục và mỗi vai trò người dùng trên trục khác. Sau đó, tôi tiến hành thử nghiệm từng sự kết hợp một cách có hệ thống. Điều này mất thời gian, nhưng đã phát hiện ra các lỗi phân quyền trong 100% các dự án mà tôi đã áp dụng. Đúng, 100%. Đó không phải là khoa trương - mỗi dự án đều có ít nhất một điểm cuối mà logic phân quyền sai cho ít nhất một vai trò.
Xác Thực Yêu Cầu: Nơi Hầu Hết Các Lỗi Thực Sự Xuất Hiện
Nếu tôi phải đoán nơi 70% các lỗi API xuất phát, đó sẽ là trong xác thực yêu cầu. Các nhà phát triển là những sinh vật lạc quan - họ viết mã với giả định rằng các đầu vào sẽ hợp lý. Nhưng internet không hợp lý, và các hệ thống gọi API của bạn cũng không.
Danh sách kiểm tra xác thực yêu cầu của tôi rất đầy đủ bởi vì nó cần phải như vậy:
- Gửi nội dung yêu cầu hoàn toàn trống - điều gì sẽ xảy ra?
- Gửi null cho từng trường bắt buộc một cách riêng biệt
- Gửi chuỗi rỗng cho các trường chuỗi
- Gửi chuỗi chỉ chứa khoảng trắng
- Gửi chuỗi dài hơn 1 ký tự so với bất kỳ giới hạn độ dài nào
- Gửi chuỗi dài gấp 1000 lần so với giới hạn
- Gửi số âm cho các trường mong đợi số nguyên dương
- Gửi bằng không cho những trường mà bằng không có thể không hợp lệ
- Gửi số thập phân cho các trường số nguyên
- Gửi số cực lớn (kiểm tra tràn số nguyên)
- Gửi số cực nhỏ (kiểm tra thiếu hụt)
- Gửi ký tự đặc biệt trong các trường chuỗi: dấu ngoặc kép, dấu gạch chéo ngược, byte null, Unicode
- Gửi cố gắng tiêm SQL (ngay cả khi bạn đang sử dụng ORM)
- Gửi tải trọng XSS trong các trường chuỗi
- Gửi loại dữ liệu không khớp (chuỗi nơi mong đợi số, v.v.)
Tôi biết bạn đang nghĩ gì: "Sarah, điều đó thật điên rồ. Không ai có thời gian cho tất cả điều đó." Nhưng - tôi đã tự động hóa toàn bộ danh sách kiểm tra này. Tôi có một trình tạo dữ liệu thử nghiệm tạo ra tất cả những biến thể này tự động. Việc thiết lập ban đầu mất tôi khoảng hai tuần để xây dựng, nhưng bây giờ tôi có thể chạy toàn bộ bộ này chống lại một điểm cuối mới trong khoảng 15 phút.
Lợi ích là điều có thật. Tháng trước, danh sách kiểm tra này đã phát hiện một điểm cuối sẽ làm sập toàn bộ máy chủ API khi bạn gửi một chuỗi dài hơn 65.535 ký tự. Nhà phát triển đã giả định rằng cơ sở dữ liệu sẽ xử lý xác thực độ dài, nhưng cơ sở dữ liệu được cấu hình để cắt ngắn êm dịu, và mã ứng dụng đã cố gắng ghi lại toàn bộ chuỗi trong một bộ đệm cố định kích thước. Boom—lỗi phân đoạn, máy chủ hỏng.
Đối với các trường ngày tháng và giờ, tôi có một danh sách phụ đặc biệt vì những cái này thật kinh khủng:
- Gửi ngày tháng ở các định dạng khác nhau (ISO 8601, MM/DD/YYYY, DD/MM/YYYY, v.v.)
- Gửi ngày tháng không hợp lệ (ngày 30 tháng 2, tháng 13, ngày 32)
- Gửi ngày tháng từ rất xa trong quá khứ (năm 1900, năm 1)
- Gửi ngày tháng từ rất xa trong tương lai (năm 2100, năm 9999)
- Gửi ngày tháng với các khoảng cách múi giờ khác nhau
- Gửi ngày tháng trong các khoảng thời gian chuyển tiếp giờ mùa hè
- Gửi dấu thời gian với mili giây, micro giây, nano giây
Cái về giờ mùa hè đã khiến tôi bị tổn thương hai lần. Hai lần! Bạn có thể nghĩ tôi sẽ học, nhưng đó là một trường hợp ngoại lệ kỳ lạ mà dễ dàng để quên. Bây giờ tôi có một bài kiểm tra cụ thể chạy giao dịch vào lúc 2 giờ sáng của ngày thay đổi đồng hồ, bởi vì đó là lúc mọi thứ kỳ lạ xảy ra.
Xác Thực Phản Hồi: Tin Tưởng, Nhưng Kiểm Tra
Hầu hết các người thử nghiệm tập trung rất nhiều vào các yêu cầu và chỉ liếc nhìn vào các phản hồi. Điều đó là ngược lại. Các phản hồi của API của bạn là hợp đồng của nó với thế giới. Nếu chúng không nhất quán, không đầy đủ hoặc không chính xác, bạn đã phá vỡ hợp đồng đó.
| Danh Mục Kiểm Tra | Điểm Thất Bại Chung | Phản Hồi Mong Đợi | Điều Gì Thực Sự Xảy Ra |
|---|---|---|---|
| Không Có Mã Thông Báo Xác Thực | Thiếu xử lý lỗi | 401 Không Được Phép | 500 Lỗi Máy Chủ Nội Bộ hoặc dữ liệu lộ ra |
| Mã Thông Báo Hết Hạn | Logic xác thực mã thông báo | 401 Không Được Phép | Lỗi 500 hoặc thất bại lặng lẽ |
| Mã Thông Báo Định Dạng Sai | Xác thực đầu vào | 401 Không Được Phép | Ứng dụng bị sập hoặc lộ thông tin ngăn xếp |
| Mã Thông Báo Hợp Lệ, Sai Quyền Hạn | Kiểm tra phân quyền | 403 Bị Cấm | 200 OK với quyền truy cập dữ liệu không hợp lệ |
| Định Dạng Ngày Không Hợp Lệ | Xác thực đầu vào | 400 Yêu Cầu Không Hợp Lệ | Thất bại chuỗi giao dịch |
Danh sách kiểm tra xác thực phản hồi của tôi bao gồm:
- Xác minh mã trạng thái phản hồi khớp với hành vi đã được tài liệu hóa
- Xác minh tiêu đề kiểu nội dung phản hồi đúng
- Xác minh cấu trúc cơ thể phản hồi khớp với sơ đồ
- Xác minh tất cả các trường được tài liệu hóa đều có mặt
- Xác minh không có trường nào không được tài liệu hóa (điều này quan trọng cho phiên bản API)
- Xác minh kiểu dữ liệu của trường khớp với tài liệu
- Xác minh giá trị trường nằm trong các khoảng được tài liệu hóa
- Xác minh dấu thời gian nằm trong múi giờ đúng
- Xác minh siêu dữ liệu phân trang là chính xác và nhất quán
- Xác minh phản hồi lỗi bao gồm thông điệp lỗi hữu ích
- Xác minh phản hồi lỗi bao gồm mã lỗi để xử lý lập trình
Điểm thứ hai từ cuối về thông điệp lỗi là rất quan trọng. Tôi đã thấy các API trả về "Lỗi" như toàn bộ thông điệp lỗi. Điều đó là vô ích. Một thông điệp lỗi tốt cho bạn biết điều gì đã sai, tại sao nó lại sai, và lý tưởng là những gì bạn có thể làm để sửa chữa nó. So sánh hai phản hồi lỗi này:
Xấu: {"error": "Yêu cầu không hợp lệ"}
Tốt: {"error": "Yêu cầu không hợp lệ", "message": "Trường 'email' là bắt buộc nhưng không được cung cấp", "code": "MISSING_REQUIRED_FIELD", "field": "email"}
Điều thứ hai