Trả lời nhanh: Keystore Android là file chứa khóa dùng để ký ứng dụng, và cửa hàng dùng chữ ký đó để xác nhận bản cập nhật đúng là của bạn. Hệ quả cần khắc cốt: mất keystore nghĩa là không bao giờ cập nhật được ứng dụng đó nữa, phải phát hành như ứng dụng mới và mất toàn bộ người dùng cũ. Ba việc bắt buộc: để ngoài repo, sao lưu ở ít nhất hai nơi, và mật khẩu cất trong nơi quản lý bí mật chứ không ghi trong file cấu hình.
Đây là một trong số ít sai lầm trong nghề lập trình di động không có đường cứu. Code mất thì viết lại, máy chủ hỏng thì dựng lại, nhưng keystore mất thì ứng dụng của bạn coi như dừng ở phiên bản cuối cùng đã phát hành. Bài này nói cách tạo, cất và dùng cho đúng ngay từ đầu.
Tạo keystore đúng cách
keytool -genkey -v -keystore ~/khoa/ung-dung-cua-toi.jks -keyalg RSA -keysize 2048 -validity 10000 -alias phat-hanhBa tham số cần chú ý. Thời hạn nên đặt rất dài, con số mười nghìn ngày là khoảng hai bảy năm, vì khóa hết hạn giữa vòng đời ứng dụng là rắc rối không cần thiết. Bí danh nên đặt tên có nghĩa vì bạn sẽ phải gõ lại nó trong cấu hình build. Đường dẫn phải nằm ngoài thư mục dự án, ngay từ lệnh tạo, để không có cơ hội lỡ tay thêm vào Git.
Lệnh sẽ hỏi mật khẩu cho kho khóa và thông tin định danh. Mật khẩu hãy sinh ngẫu nhiên và lưu ngay vào trình quản lý mật khẩu, đừng đặt một mật khẩu dễ nhớ với ý định ghi lại sau.
Cất ở đâu
Ba nơi, và bạn cần ít nhất hai:
- Trình quản lý bí mật của công ty, nơi đã có kiểm soát ai được xem gì. Đây nên là bản chính.
- Bản sao mã hóa trên kho lưu trữ riêng, tách biệt với máy chủ build. Mã hóa trước khi đưa lên, đừng dựa vào việc kho đó là riêng tư.
- Bản in hoặc bản lưu ngoại tuyến cất ở nơi vật lý an toàn, dành cho tình huống xấu nhất.
Điều quan trọng không kém việc sao lưu: thử khôi phục định kỳ. Mỗi sáu tháng, lấy bản sao ra và thử ký một bản dựng thử. Rất nhiều bản sao lưu chỉ lộ ra là hỏng vào đúng lúc người ta cần tới nó.
Với mật khẩu, đừng cất cùng chỗ với file khóa. Hai thứ tách nhau thì một nơi bị lộ vẫn chưa đủ để ký bản giả mạo.
Cấu hình cho máy build
Không bao giờ ghi mật khẩu vào file trong repo. Cách đúng là đọc từ biến môi trường:
// android/app/build.gradlesigningConfigs { release { storeFile file(System.getenv("DUONG_DAN_KEYSTORE")) storePassword System.getenv("MAT_KHAU_KHO") keyAlias System.getenv("BI_DANH_KHOA") keyPassword System.getenv("MAT_KHAU_KHOA") }}Trên máy build tự dựng, đặt file khóa trong thư mục nhà của tài khoản chạy build với quyền chỉ tài khoản đó đọc được:
chmod 600 ~/khoa/ung-dung-cua-toi.jksNguyên tắc giảm rủi ro đáng làm với đội đông người: chỉ luồng phát hành mới chạm tới khóa thật. Các bản dựng hằng ngày cho đội kiểm thử dùng khóa gỡ lỗi là đủ, nhờ vậy khóa thật chỉ được dùng vài lần mỗi tháng và trên đúng một máy. Cách chia luồng build nằm ở bài runner cho CI mobile.
Phương án để cửa hàng giữ khóa
Google Play có cơ chế nhận khóa ký gốc do cửa hàng quản lý. Khi đó bạn ký bản nộp bằng một khóa riêng của mình, còn cửa hàng ký lại bản phát tới người dùng bằng khóa gốc mà họ giữ.
Lợi: mất khóa của bạn thì vẫn có đường yêu cầu đặt lại, không còn là sự cố không cứu được. Bản phát tới máy người dùng cũng được tối ưu theo từng thiết bị.
Cân nhắc: khóa gốc nằm ở phía cửa hàng, và với ứng dụng phát hành trên nhiều kênh ngoài cửa hàng thì bạn phải tính thêm cách xử lý chữ ký cho các kênh đó.
Với phần lớn ứng dụng phát hành qua cửa hàng, đây là lựa chọn giảm rủi ro rõ rệt và đáng bật. Nhưng đừng vì thế mà lơi phần sao lưu khóa nộp của chính bạn, vì mất nó thì bạn vẫn phải qua quy trình xin đặt lại và quy trình đó tốn thời gian.
Ba sai lầm thấy nhiều nhất
Keystore nằm trong repo. Thường do người mới thêm cả thư mục vào Git cho tiện. Kể cả repo riêng tư cũng không được, vì ai có quyền đọc mã nguồn đều có luôn khóa, và lịch sử Git thì rất khó xóa sạch. Hãy thêm mẫu loại trừ ngay từ lúc tạo dự án.
Chỉ một người biết mật khẩu. Người đó nghỉ việc hoặc mất máy là cả đội kẹt. Mật khẩu phải nằm trong hệ thống quản lý bí mật của công ty, có ít nhất hai người truy cập được.
Không sao lưu vì nghĩ máy build đã là bản lưu. Máy build hỏng ổ đĩa là mất cả. Máy build không bao giờ được coi là nơi lưu trữ, nó chỉ là nơi dùng.
Nếu bạn đang ở tình huống đã lỡ đưa keystore vào repo, đừng chỉ xóa file rồi commit. File vẫn nằm trong lịch sử. Cách xử lý đúng là coi khóa đó như đã lộ: tạo khóa mới và, nếu ứng dụng đã phát hành, dùng quy trình đặt lại khóa của cửa hàng.
Bảng sai lầm về khóa ký và mức nghiêm trọng
| Sai lầm | Hậu quả | Mức nghiêm trọng |
|---|---|---|
| Đưa tệp khóa vào kho mã nguồn | Ai đọc được kho là ký được ứng dụng giả danh bạn | Rất nghiêm trọng |
| Chỉ có một bản khóa, không sao lưu | Mất là không cập nhật được ứng dụng đã phát hành | Không sửa được |
| Ghi mật khẩu khóa trong tệp cấu hình đưa lên kho | Cùng hậu quả với sai lầm thứ nhất | Rất nghiêm trọng |
Nói rõ hậu quả của sai lầm thứ hai: mất tệp khóa nghĩa là mọi người đã cài ứng dụng của bạn sẽ không nhận được bản cập nhật nào nữa. Bạn phải phát hành lại như một ứng dụng hoàn toàn mới, dưới tên gói khác, và mất toàn bộ người dùng cũ cùng mọi đánh giá. Không có cách khôi phục.
Cất ở đâu cho đúng
- Bản chính: trong kho bí mật của công ty, có phân quyền và có nhật ký truy cập.
- Bản sao thứ hai: ở nơi vật lý khác, ví dụ ổ mã hóa cất trong két.
- Mật khẩu khóa lưu tách khỏi tệp khóa, để lộ một thứ chưa đủ dùng.
- Ghi lại ai có quyền truy cập, và rà soát khi nhân sự thay đổi.
- Trên máy dựng tự động: nạp từ kho bí mật lúc chạy, và xóa tệp sau khi dựng xong.
Kiểm nhanh xem đã lộ chưa
# Quet kho ma nguonfind . -name "*.jks" -o -name "*.keystore" -o -name "*.p12" | grep -v node_modgrep -rn "storePassword\|keyPassword\|storeFile" --include="*.properties" --include="*.gradle" . # Neu tim thay trong kho: coi nhu DA LO# Xoa dong do khong du, lich su kho van giu ban cu# Phai tao khoa moi, va voi ung dung da phat hanh thi khong doi duoc # Dat vao danh sach loai tru ngay tu daucat >> .gitignore <<'EOF'*.jks*.keystore*.p12key.propertieslocal.propertiesEOFGiao khóa cuối cho cửa hàng giữ, nên hay không
Cửa hàng ứng dụng có phương án cho phép họ giữ khóa ký cuối cùng, còn bạn chỉ giữ một khóa tải lên. Ưu điểm lớn nhất: nếu mất khóa tải lên, bạn xin cấp lại được, và ứng dụng vẫn cập nhật bình thường. Đây là phương án nên chọn với ứng dụng mới, vì nó loại bỏ rủi ro mất khóa vĩnh viễn. Đổi lại, bạn phụ thuộc vào cửa hàng cho việc ký cuối cùng.
Câu hỏi thường gặp
Mất keystore thì làm sao?
Nếu bạn đã bật cơ chế để cửa hàng giữ khóa gốc thì có đường yêu cầu đặt lại khóa nộp. Nếu không, bạn không cập nhật được ứng dụng cũ nữa và phải phát hành ứng dụng mới, mất toàn bộ lượt cài và đánh giá đã có.
Có nên dùng chung một keystore cho nhiều ứng dụng?
Được về mặt kỹ thuật và giúp quản lý gọn hơn, nhưng rủi ro tập trung: lộ một lần là ảnh hưởng tất cả. Với vài ứng dụng thì dùng chung chấp nhận được, với danh mục lớn nên tách theo nhóm sản phẩm.
Khóa gỡ lỗi và khóa phát hành khác nhau thế nào?
Khóa gỡ lỗi do công cụ tự tạo, dùng để cài thử lên máy, không nộp cửa hàng được. Khóa phát hành do bạn tạo và giữ, là thứ cửa hàng dùng để xác nhận danh tính bản cập nhật.
Đặt keystore trên máy build có an toàn không?
An toàn nếu máy đó chỉ chạy luồng phát hành, tài khoản chạy build có quyền tối thiểu, và không cho repo công khai chạy trên máy đó. Bản chính vẫn phải nằm ở nơi quản lý bí mật, máy build chỉ là nơi dùng.
