Một URL HTTPS đúng chưa đảm bảo file JavaScript tại URL đó vẫn là đúng phiên bản bạn đã duyệt. Nếu CDN, tài khoản nhà cung cấp hoặc pipeline phát hành bị xâm nhập, trình duyệt vẫn có thể tải mã đã bị thay đổi từ máy chủ hợp lệ. Subresource Integrity (SRI) bổ sung một dấu vân tay mật mã vào HTML để trình duyệt chỉ chấp nhận đúng nội dung mong đợi.
SRI đặc biệt phù hợp với JavaScript và CSS tĩnh lấy từ CDN. Nhưng nó không phải chiếc công tắc dùng được cho mọi URL: tài nguyên phải bất biến, hash phải được cập nhật cùng phiên bản, và request cross-origin phải đáp ứng CORS. Hiểu những ranh giới này giúp SRI trở thành kiểm soát thực tế thay vì một thuộc tính dễ làm hỏng giao diện production.
1. SRI giải quyết vấn đề nào?
Khi HTML chứa <script src="...">, trang đang trao quyền thực thi cho nội dung trả về từ URL đó. TLS xác thực kết nối tới máy chủ và bảo vệ dữ liệu trên đường truyền, nhưng không chứng minh rằng chủ máy chủ vẫn đang phân phối đúng byte mà đội phát triển đã kiểm tra.
Đặc tả Subresource Integrity của W3C định nghĩa cơ chế để user agent so sánh nội dung nhận được với hash được khai báo. Nếu không khớp, tài nguyên bị chặn thay vì được thực thi hoặc áp dụng vào trang.
| Lớp bảo vệ | Bảo vệ điều gì? | Không tự giải quyết |
|---|---|---|
| HTTPS/TLS | Kết nối, danh tính máy chủ, dữ liệu khi truyền | File hợp lệ trên máy chủ có bị thay đổi hay không |
| SRI | Nội dung tài nguyên khớp hash đã ghim | HTML gốc bị sửa cùng với hash |
| CSP | Nguồn và điều kiện được phép nạp/thực thi | Không mặc nhiên ghim byte của file CDN |
| Version pinning | URL trỏ tới phiên bản cụ thể | Không tự xác minh nội dung phản hồi |
2. Một thuộc tính integrity hoạt động ra sao?
<script
src="https://cdn.example.net/library/4.2.1/library.min.js"
integrity="sha384-BASE64_DIGEST_HERE"
crossorigin="anonymous"></script>
- Trình duyệt tải tài nguyên theo URL.
- Trình duyệt tính digest bằng thuật toán ghi trong metadata.
- Digest vừa tính được so sánh với giá trị Base64 trong
integrity. - Nếu có giá trị phù hợp, tài nguyên được dùng; nếu không, quá trình nạp thất bại.
Metadata có dạng tên-thuật-toán-digest-base64. SRI hỗ trợ SHA-256, SHA-384 và SHA-512. SHA-384 là lựa chọn cơ sở thực dụng phổ biến; không dùng MD5 hoặc SHA-1.
Hash SRI là hash của chính nội dung tài nguyên, không phải checksum của URL, tên file hay chứng thư TLS.
3. Ví dụ cho JavaScript và CSS
<script
src="https://cdn.example.net/app/2.4.0/app.min.js"
integrity="sha384-AbCdEf..."
crossorigin="anonymous"></script>
<link
rel="stylesheet"
href="https://cdn.example.net/ui/2.4.0/ui.min.css"
integrity="sha384-ZyXwVu..."
crossorigin="anonymous">
Hash rút gọn ở ví dụ chỉ minh họa cấu trúc, không thể dùng thật. Hãy dùng hash do nhà cung cấp công bố cho đúng file, hoặc tự tải artifact qua quy trình tin cậy rồi tính hash. Một ký tự, newline, banner build hoặc bước minify khác cũng tạo digest khác.
4. Vì sao tài nguyên cross-origin cần CORS?
Với tài nguyên đến từ origin khác, SRI yêu cầu request đủ điều kiện CORS. Thuộc tính crossorigin="anonymous" đặt request ở chế độ CORS không dùng credential; máy chủ CDN cần trả header Access-Control-Allow-Origin phù hợp, thường là * cho asset công khai.
Nếu thiếu CORS, trình duyệt có thể từ chối tài nguyên dù hash đúng. Đây không phải lỗi hash. Kiểm tra tab Network và Console để phân biệt CORS failure, HTTP failure và integrity mismatch.
- Dùng
anonymouscho file CDN công khai. - Không chọn
use-credentialstrừ khi luồng thật sự cần cookie/credential và server cấu hình CORS tương ứng. - Giữ cấu hình
crossoriginnhất quán giữa preload và phần tử sử dụng tài nguyên.
5. Tạo hash SHA-384 bằng OpenSSL
Tính hash trên file artifact cuối cùng sẽ được CDN phân phối:
openssl dgst -sha384 -binary library.min.js | openssl base64 -A
Ghép tiền tố sha384- vào kết quả:
sha384-<base64-output>
Không copy file qua công cụ làm đổi line ending trước khi hash. Tốt nhất pipeline tạo artifact một lần, tính SRI từ chính artifact đó, upload cùng byte lên storage/CDN, rồi sinh manifest HTML từ kết quả.
6. Tạo hash bằng PowerShell
$path = 'C:\release\library.min.js'
$bytes = [System.IO.File]::ReadAllBytes($path)
$sha384 = [System.Security.Cryptography.SHA384]::Create()
try {
$digest = $sha384.ComputeHash($bytes)
'sha384-' + [Convert]::ToBase64String($digest)
} finally {
$sha384.Dispose()
}
Get-FileHash mặc định hiển thị hexadecimal, trong khi metadata SRI cần digest Base64. Vì vậy không dán trực tiếp chuỗi hex từ Get-FileHash sau tiền tố sha384-.
7. Tự xác minh hash trước khi deploy
Tải URL production vào một file tạm và tính lại digest:
curl.exe -fL "https://cdn.example.net/app/2.4.0/app.min.js" `
-o ".\app.min.js"
# Sau đó chạy đoạn PowerShell tính SHA-384 ở trên.
Cần xác minh status code, redirect cuối, kích thước và content type. Nếu CDN tự động biến đổi JavaScript/CSS, nén lại ở tầng nội dung hoặc chèn banner theo vùng, byte cuối có thể không ổn định. HTTP compression thông thường có thể được xử lý trong fetch stack, nhưng pipeline vẫn nên kiểm thử đúng URL qua trình duyệt mục tiêu thay vì suy luận từ file nguồn.
8. URL phải bất biến
SRI và URL “luôn mới nhất” xung đột trực tiếp. Nếu /library/latest.js thay nội dung nhưng HTML giữ hash cũ, trình duyệt sẽ chặn bản mới. Đây là hành vi đúng của SRI.
- Ưu tiên URL chứa version cụ thể hoặc content hash.
- Không cho phép ghi đè artifact đã phát hành dưới cùng URL.
- Khi nâng phiên bản, review code, cập nhật URL và hash trong cùng thay đổi.
- Purge CDN có kiểm soát và kiểm tra mọi edge trả cùng nội dung.
- Giữ manifest ánh xạ version → URL → SRI trong source control hoặc output build.
9. Nhiều hash trong cùng metadata
Thuộc tính integrity có thể chứa nhiều biểu thức cách nhau bằng khoảng trắng:
integrity="sha384-DIGEST_A sha384-DIGEST_B"
Nhiều digest cùng thuật toán có thể hỗ trợ một cửa sổ chuyển tiếp nơi hai payload cụ thể đều được chấp nhận. Tuy nhiên, điều này mở rộng tập nội dung hợp lệ và nên tồn tại ngắn. Khi trộn nhiều thuật toán, user agent chọn tập của thuật toán mạnh nhất được hỗ trợ; đừng giả định hash yếu hơn sẽ cứu một hash mạnh hơn bị sai.
10. SRI và preload phải đồng bộ
<link
rel="preload"
as="script"
href="https://cdn.example.net/app/2.4.0/app.min.js"
integrity="sha384-AbCdEf..."
crossorigin="anonymous">
<script
src="https://cdn.example.net/app/2.4.0/app.min.js"
integrity="sha384-AbCdEf..."
crossorigin="anonymous"></script>
URL, integrity và CORS mode nên giống nhau. Nếu preload và script khác thuộc tính, trình duyệt có thể không tái sử dụng response như mong đợi hoặc một bước thành công trong khi bước kia thất bại.
11. SRI không tự động bảo vệ toàn bộ chuỗi dependency
Hash trên một external script bảo vệ response được tham chiếu bởi phần tử đó. Nếu script tải thêm code, worker, WASM hoặc dữ liệu ở runtime, các tài nguyên tiếp theo không mặc nhiên được bảo vệ chỉ nhờ hash của loader. Với module script, thuộc tính trên phần tử bảo vệ lần fetch khởi đầu; dependency graph cần chiến lược build, CSP và cơ chế integrity phù hợp riêng.
Do đó, một loader nhỏ có SRI nhưng tiếp tục tải plugin từ URL mutable vẫn để lại supply-chain surface. Inventory phải bao gồm cả tải tĩnh trong HTML lẫn tải động khi chạy.
12. Thiết kế fallback mà không vô hiệu hóa bảo vệ
SRI mismatch làm tài nguyên thất bại; trình duyệt không tự chuyển sang URL khác. Một handler tự động tải lại cùng thư viện từ nguồn không ghim hash có thể biến sự cố bảo mật thành đường bypass.
- Với chức năng không thiết yếu, chấp nhận degraded mode và ghi telemetry.
- Với tài nguyên thiết yếu, cân nhắc self-host artifact đã kiểm duyệt làm nguồn chính.
- Nếu có fallback, nó phải là một artifact cụ thể, kiểm soát được và có integrity riêng.
- Đừng inline bản sao thư viện lớn chỉ để tránh lỗi CDN; điều đó làm quản lý bản vá khó hơn.
13. SRI kết hợp với CSP
CSP giới hạn origin hoặc điều kiện mà script/style được phép nạp; SRI xác minh byte của một tài nguyên cụ thể. Hai cơ chế bổ sung cho nhau. Ví dụ, CSP có thể giới hạn script-src về chính origin và CDN đã duyệt, trong khi SRI ngăn file tại URL CDN bị thay bằng payload khác.
Không copy hash SRI vào CSP một cách máy móc: cú pháp và cách policy khớp có ngữ cảnh riêng. Hãy rollout CSP ở chế độ report-only trước, thu thập violation, rồi enforce theo threat model. Các đề xuất mới như Integrity Policy vẫn đang phát triển; cần kiểm tra trạng thái tiêu chuẩn và hỗ trợ trình duyệt trước khi dùng làm điều kiện production.
14. SRI không bảo vệ HTML đã bị chiếm quyền
Nếu kẻ tấn công sửa được chính HTML, họ có thể xóa integrity, thay cả URL lẫn hash hoặc chèn script mới. Vì thế HTML phải được phục vụ qua HTTPS, bảo vệ pipeline deploy, kiểm soát quyền CMS và áp CSP phù hợp. SRI mạnh nhất khi trust boundary nằm giữa trang do bạn kiểm soát và máy chủ asset bên ngoài.
15. Pipeline triển khai đề xuất
- Khóa version dependency và tải artifact từ nguồn đã xác minh.
- Quét/review dependency theo quy trình của dự án.
- Tạo artifact cuối; không chỉnh sửa sau bước này.
- Tính SHA-384 và lưu vào manifest build.
- Upload đúng artifact tới URL bất biến.
- Sinh HTML với URL,
integrityvàcrossorigin. - Test trên môi trường staging qua đúng CDN/CORS path.
- Negative test bằng hash sai để chứng minh trình duyệt chặn tài nguyên.
- Triển khai và theo dõi lỗi load, CSP report, JavaScript error cùng chỉ số giao diện.
Checklist production
- URL tài nguyên chứa phiên bản cố định hoặc content hash.
- Digest được tạo từ artifact cuối cùng, ở dạng Base64.
- Dùng SHA-384 hoặc SHA-512; không dùng MD5/SHA-1.
- CDN trả CORS header phù hợp cho request cross-origin.
crossoriginnhất quán giữa preload và phần tử sử dụng.- URL và hash được cập nhật trong cùng pull request/release.
- Không có fallback sang nguồn mutable, không integrity.
- Tài nguyên tải động đã được inventory và kiểm soát riêng.
- Positive test và integrity-mismatch test đều đã chạy.
- Có telemetry phát hiện lỗi load trước khi người dùng báo giao diện hỏng.
Kết luận
Subresource Integrity biến niềm tin “CDN sẽ trả đúng file” thành một phép kiểm tra mật mã ngay trong trình duyệt. Muốn SRI bền vững, hãy ghim version, tính hash từ artifact bất biến, cấu hình CORS đúng và đưa việc cập nhật URL–hash vào pipeline. Kết hợp SRI với HTTPS, CSP và quản trị supply chain sẽ tạo nhiều lớp kiểm soát độc lập thay vì đặt toàn bộ niềm tin vào một URL bên ngoài.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.