99 Ngày Spring — Ngày 97: Security Hardening cho Production
Xác thực và phân quyền đúng mới là điều kiện cần. Hardening là phần còn lại: thu nhỏ bề mặt tấn công và giới hạn thiệt hại khi một lớp phòng thủ thất bại. Bài này gom bốn nhóm việc nên rà trước mỗi lần đưa một service Spring Boot ra Internet.

1. Security header
Spring Security mặc định đã thêm một số header: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Cache-Control chống cache nội dung riêng tư, và Strict-Transport-Security khi request đi qua HTTPS. Thứ bạn cần tự thêm là Content-Security-Policy, vì nó phụ thuộc vào tài nguyên mà giao diện của bạn nạp. Một CSP chặt là lớp phòng thủ hiệu quả trước XSS. Luôn chạy sau HTTPS và chuyển hướng mọi request HTTP.
@Bean
SecurityFilterChain security(HttpSecurity http) throws Exception {
return http
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp.policyDirectives(
"default-src 'self'; frame-ancestors 'none'"))
.referrerPolicy(referrer -> referrer.policy(
ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health/**").permitAll()
.requestMatchers("/actuator/**").hasRole("OPS")
.anyRequest().authenticated())
.build();
}2. Không lộ thông tin
Stack trace, tên bảng và phiên bản thư viện trong response lỗi là bản đồ cho kẻ tấn công. Trả về một thông điệp chung kèm mã tra cứu, còn chi tiết nằm trong log. Với Actuator, chỉ mở những endpoint cần thiết, đặt trên cổng quản trị không ra Internet và yêu cầu xác thực cho mọi thứ ngoài health. Tắt các trang tài liệu API và công cụ dev ở production nếu chúng không dành cho bên ngoài.
server.error.include-stacktrace=never
server.error.include-message=never
server.error.include-binding-errors=never
management.endpoints.web.exposure.include=health,prometheus
management.endpoint.health.show-details=when-authorized
management.server.port=90913. Quét dependency
Phần lớn code chạy trong ứng dụng không do bạn viết. Lỗ hổng trong một thư viện bắc cầu vẫn là lỗ hổng của bạn. Đưa việc quét vào CI để build thất bại khi có CVE nghiêm trọng, và dùng công cụ tự mở pull request cập nhật phiên bản. Quét cả image, vì hệ điều hành nền cũng có lỗ hổng. Giữ Spring Boot ở bản vá mới nhất của nhánh đang dùng là cách đơn giản nhất để nhận bản sửa.
# fail the build on high-severity CVEs
./mvnw org.owasp:dependency-check-maven:check -DfailBuildOnCVSS=7
# what is actually on the classpath?
./mvnw dependency:tree4. Quyền tối thiểu ở mọi tầng
Giả định rằng một ngày nào đó ứng dụng sẽ bị khai thác, và hỏi kẻ tấn công làm được gì tiếp theo. Tài khoản database của ứng dụng chỉ cần đọc ghi dữ liệu, không cần quyền tạo hay xóa bảng; migration chạy bằng tài khoản khác. Container chạy bằng user không phải root với hệ thống file chỉ đọc. Mỗi service có credential riêng, chỉ đủ cho việc của nó.
Giới hạn tốc độ ở gateway cho đăng nhập và các endpoint tốn kém.
Kiểm tra dữ liệu vào ở biên bằng Bean Validation; giới hạn kích thước request.
CORS chỉ cho phép đúng origin cần thiết, không dùng dấu sao cùng credentials.
Ghi nhật ký các sự kiện bảo mật: đăng nhập thất bại, bị từ chối quyền, đổi quyền.
Xoay vòng secret định kỳ và sau mỗi lần nghi lộ.
Hardening là chuẩn bị cho ngày một lớp phòng thủ thất bại. Ngày 98 gom lại những thực hành tốt nhất của cả series vào một checklist.
Tài liệu đối chiếu
https://docs.spring.io/spring-security/reference/servlet/exploits/headers.html
https://owasp.org/www-project-top-ten/
Site Admin
Engineer and writer. Building things with TypeScript and distributed systems.
Bình luận (0)
Bạn cần đăng nhập bằng Google để bình luận.
Hãy là người bình luận đầu tiên.


