Android có các tính năng bảo mật tích hợp giúp giảm đáng kể tần suất và tác động của các vấn đề về bảo mật ứng dụng. Hệ thống này được thiết kế để bạn thường có thể tạo ứng dụng có các quyền mặc định đối với hệ thống và tệp, đồng thời tránh được những quyết định khó khăn về bảo mật.
Các tính năng bảo mật cốt lõi sau đây giúp bạn tạo các ứng dụng an toàn:
- Hộp cát của ứng dụng Android giúp tách biệt dữ liệu ứng dụng của bạn với quá trình thực thi mã của các ứng dụng khác.
- Một khung ứng dụng với các quy trình triển khai mạnh mẽ về chức năng bảo mật thường dùng, chẳng hạn như mật mã học, quyền và cơ chế giao tiếp liên quy trình (IPC) bảo mật.
- Những công nghệ như sắp xếp ngẫu nhiên bố cục không gian địa chỉ (ASLR), không thực thi (NX), ProPolice, safe_iop, OpenBSD
dlmalloc
vàcalloc
cũng như Linuxmmap_min_addr
để giảm thiểu rủi ro liên quan đến các lỗi thường gặp về quản lý bộ nhớ. - Các quyền do người dùng cấp để hạn chế quyền truy cập vào các tính năng của hệ thống và dữ liệu người dùng.
- Các quyền do ứng dụng xác định để kiểm soát dữ liệu ứng dụng trên từng ứng dụng.
Điều quan trọng là bạn phải nắm rõ các phương pháp hay nhất về bảo mật Android trên trang này. Khi làm theo các phương pháp này dưới dạng thói quen lập trình chung, bạn có thể tránh vô tình gây ra các vấn đề bảo mật gây ảnh hưởng xấu đến người dùng.
Xác thực
Xác thực là điều kiện tiên quyết cho nhiều hoạt động bảo mật chính. Để kiểm soát quyền truy cập vào các thành phần được bảo vệ như dữ liệu người dùng, chức năng của ứng dụng và các tài nguyên khác, bạn sẽ cần thêm quy trình xác thực vào ứng dụng Android của mình.
Bạn có thể cải thiện trải nghiệm xác thực của người dùng bằng cách tích hợp ứng dụng của bạn với Trình quản lý thông tin xác thực. Trình quản lý thông tin xác thực là một thư viện Android Jetpack hợp nhất tính năng hỗ trợ API cho hầu hết các phương thức xác thực chính, trong đó có khoá truy cập, mật khẩu và các giải pháp đăng nhập liên kết như Đăng nhập bằng Google.
Để tăng cường hơn nữa độ bảo mật cho ứng dụng, hãy cân nhắc thêm các phương thức xác thực bằng sinh trắc học, chẳng hạn như quét vân tay hoặc nhận dạng khuôn mặt. Các ứng dụng phù hợp để thêm tính năng xác thực bằng sinh trắc học có thể bao gồm các ứng dụng quản lý danh tính, chăm sóc sức khoẻ hoặc tài chính.
Khung tự động điền của Android có thể giúp quy trình đăng ký và đăng nhập diễn ra suôn sẻ, giảm tỷ lệ lỗi và sự phiền hà cho người dùng. Tính năng tự động điền tích hợp với trình quản lý mật khẩu, cho phép người dùng chọn các mật khẩu phức tạp, ngẫu nhiên có thể lưu trữ và truy xuất một cách dễ dàng và an toàn.
Lưu trữ dữ liệu
Mối lo ngại thường gặp nhất về bảo mật của một ứng dụng trên Android là liệu các ứng dụng khác có thể truy cập vào dữ liệu bạn lưu trên thiết bị hay không. Có 3 cách cơ bản để lưu dữ liệu trên thiết bị:
- Bộ nhớ trong
- Bộ nhớ ngoài
- Trình cung cấp nội dung
Các phần sau đây mô tả các vấn đề bảo mật liên quan đến từng phương pháp.
Bộ nhớ trong
Theo mặc định, chỉ ứng dụng của bạn mới có thể truy cập vào các tệp mà bạn tạo trên bộ nhớ trong. Đây là biện pháp do Android triển khai và đủ khả năng bảo vệ hầu hết các ứng dụng.
Tránh các chế độ MODE_WORLD_WRITEABLE
và MODE_WORLD_READABLE
không dùng nữa đối với tệp IPC. Các chế độ đó không giúp giới hạn truy cập dữ liệu đối với các ứng dụng cụ thể cũng như không cung cấp khả năng kiểm soát định dạng dữ liệu. Nếu bạn muốn chia sẻ dữ liệu của mình với các quy trình ứng dụng khác, hãy cân nhắc dùng trình cung cấp nội dung. Công cụ này cung cấp quyền đọc và ghi cho các ứng dụng khác, đồng thời có thể linh động cấp quyền theo từng trường hợp.
Bộ nhớ ngoài
Các tệp được tạo trên bộ nhớ ngoài, chẳng hạn như thẻ SD, có thể đọc và ghi ở mọi nơi. Vì bộ nhớ ngoài có thể bị người dùng xoá cũng như có thể bị bất kỳ ứng dụng nào sửa đổi, nên chỉ nên lưu trữ thông tin không nhạy cảm trên bộ nhớ ngoài.
Thực hiện xác thực dữ liệu đầu vào khi xử lý dữ liệu trên bộ nhớ ngoài giống như với dữ liệu từ bất kỳ nguồn không đáng tin cậy nào. Không lưu trữ các tệp có thể thực thi hoặc tệp lớp trên bộ nhớ ngoài trước khi tải động. Nếu ứng dụng của bạn truy xuất các tệp thực thi trên bộ nhớ ngoài, hãy đảm bảo rằng các tệp đã được ký và xác minh bằng mật mã trước khi tải động.
Trình cung cấp nội dung
Trình cung cấp nội dung đưa ra một cơ chế lưu trữ có cấu trúc có thể bị giới hạn ở ứng dụng của riêng bạn hoặc được xuất để cho phép các ứng dụng khác truy cập. Nếu bạn không định cấp cho các ứng dụng khác quyền truy cập vào ContentProvider
, hãy đánh dấu là android:exported=false
trong tệp kê khai ứng dụng. Nếu không, hãy đặt thuộc tính android:exported
thành true
để cho phép các ứng dụng khác truy cập vào dữ liệu đã lưu trữ.
Khi tạo một ContentProvider
được xuất để các ứng dụng khác dùng, bạn có thể chỉ định một quyền đọc và ghi duy nhất hoặc chỉ định riêng lẻ quyền đọc và quyền ghi. Giới hạn các quyền của bạn ở những người cần phải hoàn thành nhiệm vụ đang thực hiện. Lưu ý rằng việc sau này thêm các quyền để hiển thị chức năng mới thường sẽ dễ dàng hơn so với việc xoá quyền và tác động đến người dùng hiện tại.
Nếu đang sử dụng một trình cung cấp nội dung để chỉ chia sẻ dữ liệu giữa các ứng dụng của mình, bạn nên dùng thuộc tính android:protectionLevel
được đặt thành biện pháp bảo vệ signature
. Quyền chữ ký không yêu cầu người dùng xác nhận, vì vậy, các quyền này mang lại trải nghiệm tốt hơn cho người dùng và quyền truy cập được kiểm soát nhiều hơn vào dữ liệu của trình cung cấp nội dung khi ứng dụng truy cập vào dữ liệu đã ký bằng cùng một khoá.
Trình cung cấp nội dung cũng có thể cung cấp quyền truy cập chi tiết hơn bằng cách khai báo thuộc tính android:grantUriPermissions
, đồng thời sử dụng cờ FLAG_GRANT_READ_URI_PERMISSION
và FLAG_GRANT_WRITE_URI_PERMISSION
trong đối tượng Intent
sẽ kích hoạt thành phần đó. Phạm vi của các quyền này có thể bị giới hạn thêm bởi phần tử <grant-uri-permission>
.
Khi truy cập vào một trình cung cấp nội dung, hãy sử dụng các phương thức truy vấn có tham số, chẳng hạn như query
, update
và delete()
để tránh việc chèn SQL có thể có từ các nguồn không đáng tin cậy. Lưu ý rằng chỉ sử dụng các phương thức có tham số là chưa đủ nếu đối số selection
được tạo bằng cách liên kết dữ liệu người dùng trước khi gửi đối số đó cho phương thức này.
Đừng lầm tưởng rằng quyền ghi có tính an toàn. Quyền ghi cho phép các câu lệnh SQL giúp xác nhận một số dữ liệu bằng cách sử dụng mệnh đề WHERE
linh hoạt và phân tích cú pháp kết quả. Ví dụ: kẻ tấn công có thể thăm dò một số điện thoại cụ thể trong nhật ký cuộc gọi bằng cách chỉ sửa đổi một hàng khi số điện thoại đó đã tồn tại. Nếu dữ liệu của trình cung cấp nội dung có cấu trúc dự đoán được, thì quyền ghi có thể tương đương với việc cung cấp cả quyền đọc và ghi.
Quyền
Vì Android tách riêng các ứng dụng với nhau, nên các ứng dụng nhất định phải dùng chung tài nguyên và dữ liệu. Các ứng dụng thực hiện việc này bằng cách khai báo các quyền cần thiết cho các tính năng bổ sung không do hộp cát cơ bản cung cấp, bao gồm cả quyền sử dụng các tính năng của thiết bị như camera.
Yêu cầu quyền
Giảm thiểu số lượng quyền mà ứng dụng của bạn yêu cầu. Việc hạn chế sử dụng quyền truy cập thông tin nhạy cảm làm giảm nguy cơ vô tình sử dụng sai các quyền đó, cải thiện sự chấp nhận của người dùng và làm cho ứng dụng khó bị tấn công hơn. Nhìn chung, nếu ứng dụng không cần một quyền nhất định để hoạt động thì đừng yêu cầu quyền đó. Hãy tham khảo hướng dẫn về cách đánh giá xem ứng dụng của bạn có cần khai báo quyền hay không.
Nếu có thể, hãy thiết kế ứng dụng của bạn theo cách không yêu cầu bất kỳ quyền nào. Ví dụ: thay vì yêu cầu quyền truy cập vào thông tin thiết bị để tạo một giá trị nhận dạng duy nhất, hãy tạo một UUID cho ứng dụng của bạn. (Tìm hiểu thêm trong phần dữ liệu người dùng). Hoặc thay vì sử dụng bộ nhớ ngoài (yêu cầu quyền), hãy lưu trữ dữ liệu trên bộ nhớ trong.
Ngoài việc yêu cầu quyền, ứng dụng của bạn còn có thể dùng phần tử <permission>
để bảo vệ IPC có tính nhạy cảm về bảo mật và được hiển thị với các ứng dụng khác, chẳng hạn như ContentProvider
. Nhìn chung, nếu có thể thì bạn nên sử dụng các chế độ kiểm soát quyền truy cập ngoài những quyền cần người dùng xác nhận, vì các quyền này có thể khiến người dùng bị nhầm lẫn. Ví dụ: hãy cân nhắc sử dụng cấp độ bảo vệ bằng chữ ký đối với các quyền giao tiếp IPC giữa các ứng dụng do một nhà phát triển cung cấp.
Không làm rò rỉ dữ liệu được bảo vệ bằng quyền. Trường hợp này xảy ra khi ứng dụng của bạn hiển thị dữ liệu qua IPC có sẵn chỉ vì ứng dụng có quyền truy cập vào dữ liệu đó. Các máy khách trên giao diện IPC của ứng dụng có thể không có quyền truy cập vào dữ liệu đó. Thông tin chi tiết hơn về tần suất và những ảnh hưởng có thể xảy ra từ vấn đề này có trong bài nghiên cứu Uỷ quyền lại quyền: Tấn công và phòng vệ, xuất bản tại USENIX.
Định nghĩa về quyền
Xác định tập hợp quyền nhỏ nhất đáp ứng các yêu cầu về bảo mật của bạn. Thông thường, hầu hết các ứng dụng sẽ không tạo một quyền mới, vì những quyền do hệ thống xác định có thể áp dụng cho nhiều trường hợp. Khi thích hợp, hãy kiểm tra quyền truy cập dựa trên các quyền hiện có.
Nếu bạn cần một quyền mới, hãy cân nhắc xem bạn có thể hoàn thành nhiệm vụ của mình ở cấp độ bảo vệ bằng chữ ký hay không. Quyền chữ ký minh bạch đối với người dùng và chỉ cho phép các ứng dụng do cùng một nhà phát triển ký khi ứng dụng thực hiện kiểm tra quyền.
Nếu bạn vẫn cần phải tạo một quyền mới, hãy khai báo quyền đó trong tệp kê khai ứng dụng bằng phần tử <permission>
. Các ứng dụng dùng quyền mới có thể tham chiếu đến quyền này bằng cách thêm một phần tử <uses-permission>
vào tệp kê khai của chúng. Bạn cũng có thể thêm quyền một cách linh động bằng phương thức addPermission()
.
Nếu tạo một quyền có mức độ bảo vệ nguy hiểm, bạn cần cân nhắc một số điểm phức tạp như sau:
- Quyền đó phải có một chuỗi thể hiện rõ ràng cho người dùng biết quyết định bảo mật mà họ cần đưa ra.
- Chuỗi quyền phải được bản địa hoá sang nhiều ngôn ngữ.
- Người dùng có thể chọn không cài đặt ứng dụng vì một quyền gây nhầm lẫn hoặc bị coi là gây rủi ro.
- Các ứng dụng có thể yêu cầu cấp quyền đó khi trình tạo quyền chưa được cài đặt.
Mỗi vấn đề trong số này đều là một thách thức lớn về mặt phi kỹ thuật đối với nhà phát triển như bạn, đồng thời cũng khiến người dùng bị nhầm lẫn. Đó là lý do chúng tôi không khuyến khích việc sử dụng cấp quyền nguy hiểm.
Kết nối mạng
Các giao dịch mạng vốn tiềm ẩn rủi ro về bảo mật, vì các giao dịch này liên quan đến việc truyền dữ liệu có khả năng là riêng tư cho người dùng. Người dùng ngày càng nhận thức được những vấn đề về quyền riêng tư của thiết bị di động, nhất là khi thiết bị thực hiện các giao dịch mạng. Vì vậy, ứng dụng cần phải triển khai mọi phương pháp hay nhất để đảm bảo dữ liệu của người dùng luôn an toàn.
Kết nối mạng IP
Kết nối mạng trên Android không khác biệt đáng kể so với các môi trường khác trên Linux. Yếu tố chính cần xem xét là đảm bảo bạn sử dụng các giao thức thích hợp cho dữ liệu nhạy cảm, chẳng hạn như HttpsURLConnection
cho lưu lượng truy cập web an toàn. Sử dụng HTTPS thay vì HTTP ở bất kỳ nơi nào HTTPS được hỗ trợ trên máy chủ, vì thiết bị di động thường kết nối trên những mạng không được bảo mật, chẳng hạn như điểm phát sóng Wi-Fi công cộng.
Giao tiếp ở cấp cổng được xác thực và mã hoá có thể dễ dàng triển khai bằng cách sử dụng lớp SSLSocket
. Do tần suất mà các thiết bị Android kết nối với mạng không dây không an toàn thông qua Wi-Fi, chúng tôi khuyến khích việc sử dụng kết nối mạng an toàn đối với tất cả các ứng dụng giao tiếp qua mạng.
Một số ứng dụng dùng các cổng mạng localhost để xử lý IPC nhạy cảm. Không dùng phương pháp này vì các ứng dụng khác trên thiết bị có thể truy cập vào những giao diện này. Thay vào đó, hãy sử dụng cơ chế IPC trên Android khi có thể xác thực, chẳng hạn như với Service
. Việc liên kết với địa chỉ IP không cụ thể INADDR_ANY
còn tệ hơn việc sử dụng vòng lặp (loopback) vì bằng cách này, ứng dụng của bạn có thể nhận yêu cầu từ bất kỳ địa chỉ IP nào.
Hãy nhớ là bạn không được tin tưởng dữ liệu tải xuống từ HTTP hoặc các giao thức không an toàn khác, mà cần xác thực dữ liệu đầu vào trong WebView
và mọi phản hồi cho ý định được đưa ra dựa trên HTTP.
Kết nối mạng điện thoại
Giao thức Dịch vụ tin nhắn nhanh (SMS) được thiết kế chủ yếu để phục vụ hoạt động giao tiếp giữa người dùng với nhau và không phù hợp với các ứng dụng muốn chuyển dữ liệu. Do những hạn chế của SMS, bạn nên sử dụng Giải pháp gửi thông báo qua đám mây của Firebase (FCM) và kết nối mạng IP để gửi thông báo dữ liệu từ máy chủ web đến ứng dụng của mình trên thiết bị của người dùng.
Lưu ý rằng SMS không được mã hoá và cũng không được xác thực chặt chẽ trên mạng hoặc thiết bị. Cụ thể, mọi dịch vụ nhận SMS đều phải dự liệu rằng một người dùng có ý đồ xấu có thể đã gửi tin nhắn SMS đó đến ứng dụng của bạn. Đừng dựa vào dữ liệu SMS chưa được xác thực để thực hiện các lệnh nhạy cảm. Ngoài ra, hãy lưu ý rằng SMS có thể bị giả mạo và/hoặc bị chặn trên mạng. Trên chính thiết bị chạy Android, tin nhắn SMS được truyền dưới dạng ý định truyền tin để các ứng dụng khác có quyền READ_SMS
có thể đọc hoặc ghi nhận các tin nhắn đó.
Xác thực dữ liệu đầu vào
Không xác thực dữ liệu đầu vào đầy đủ là một trong những vấn đề bảo mật thường gặp nhất ảnh hưởng đến các ứng dụng, bất kể ứng dụng đó chạy trên nền tảng nào. Android có các biện pháp đối phó ở cấp nền tảng giúp giảm nguy cơ ứng dụng gặp phải vấn đề về xác thực dữ liệu đầu vào. Đồng thời, bạn nên sử dụng các tính năng đó nếu có thể. Ngoài ra, bạn nên sử dụng các ngôn ngữ an toàn về kiểu để giảm khả năng xảy ra sự cố xác thực dữ liệu đầu vào.
Nếu bạn đang sử dụng mã gốc, thì mọi dữ liệu đọc được từ các tệp, nhận được qua mạng hoặc nhận được từ IPC, đều có khả năng gây ra sự cố bảo mật. Các vấn đề thường gặp nhất là tràn vùng đệm, sử dụng sau khi giải phóng bộ nhớ và lỗi sai lệch một đơn vị. Android cung cấp một số công nghệ, chẳng hạn như ASLR và Ngăn chặn thực thi dữ liệu (DEP), giúp giảm khả năng các lỗi nêu trên bị khai thác, nhưng những công nghệ này không giải quyết được vấn đề cơ bản. Bạn có thể ngăn chặn các lỗ hổng này bằng cách xử lý cẩn thận các con trỏ và quản lý vùng đệm.
Các ngôn ngữ động dựa trên chuỗi như JavaScript và SQL cũng gặp phải vấn đề xác thực dữ liệu đầu vào do các ký tự thoát và tính năng chèn tập lệnh.
Nếu bạn đang sử dụng dữ liệu trong các truy vấn được gửi đến cơ sở dữ liệu SQL hoặc trình cung cấp nội dung, thì việc chèn SQL có thể gây ra vấn đề. Cách bảo vệ tốt nhất là sử dụng các truy vấn có tham số, như được thảo luận trong phần về trình cung cấp nội dung. Việc giới hạn ở quyền chỉ đọc hoặc chỉ ghi cũng có thể làm giảm nguy cơ thiệt hại liên quan đến việc chèn SQL.
Nếu bạn không thể sử dụng các tính năng bảo mật được thảo luận trong phần này, hãy nhớ sử dụng định dạng dữ liệu có cấu trúc hợp lý và xác minh rằng dữ liệu tuân thủ định dạng dự kiến. Mặc dù việc chặn các ký tự cụ thể hoặc thực hiện thao tác thay thế ký tự có thể là một chiến lược hiệu quả, nhưng những kỹ thuật này rất dễ gặp lỗi trong thực tế và bạn nên tránh sử dụng những kỹ thuật này khi có thể.
Dữ liệu người dùng
Cách hữu hiệu nhất để bảo mật dữ liệu người dùng tốt nhất chính là giảm thiểu việc sử dụng các API truy cập vào thông tin cá nhân hoặc thông tin nhạy cảm. Nếu bạn có quyền truy cập vào dữ liệu người dùng, hãy tránh lưu trữ hoặc truyền dữ liệu đó nếu có thể. Hãy cân nhắc xem có thể triển khai logic ứng dụng của bạn bằng cách sử dụng hàm băm hoặc dạng dữ liệu không thể đảo ngược hay không. Ví dụ: ứng dụng của bạn có thể sử dụng hàm băm địa chỉ email làm khoá chính để tránh phải truyền hoặc lưu trữ địa chỉ email đó. Điều này giúp giảm nguy cơ vô tình làm lộ dữ liệu cũng như giảm khả năng những kẻ tấn công tìm cách khai thác ứng dụng của bạn.
Xác thực người dùng bất cứ khi nào cần phải truy cập vào dữ liệu riêng tư, đồng thời sử dụng các phương pháp xác thực hiện đại như khoá truy cập và Trình quản lý thông tin xác thực. Nếu ứng dụng của bạn cần truy cập vào thông tin cá nhân, hãy lưu ý rằng một số khu vực tài phán có thể yêu cầu bạn cung cấp chính sách quyền riêng tư, trong đó giải thích việc bạn sử dụng và lưu trữ dữ liệu đó. Hãy làm theo các phương pháp bảo mật hay nhất giúp giảm thiểu quyền truy cập vào dữ liệu người dùng để đơn giản hoá việc tuân thủ.
Ngoài ra, hãy cân nhắc xem ứng dụng của bạn có thể vô tình làm lộ thông tin cá nhân cho các bên khác hay không, chẳng hạn như các thành phần của bên thứ ba cho mục đích quảng cáo hoặc dịch vụ của bên thứ ba mà ứng dụng của bạn dùng. Nếu bạn không biết lý do một thành phần hoặc dịch vụ yêu cầu cung cấp thông tin cá nhân, đừng cung cấp thông tin đó. Nhìn chung, việc giảm quyền truy cập của ứng dụng vào thông tin cá nhân sẽ làm giảm nguy cơ xảy ra các vấn đề trong mảng này.
Nếu ứng dụng của bạn yêu cầu quyền truy cập vào dữ liệu nhạy cảm, hãy đánh giá xem bạn có cần truyền yêu cầu đó đến máy chủ hay không hoặc liệu bạn có thể thực hiện thao tác này trên máy khách hay không. Hãy cân nhắc chạy bất kỳ mã nào có sử dụng dữ liệu nhạy cảm trên máy khách để tránh phải truyền dữ liệu của người dùng. Ngoài ra, hãy đảm bảo rằng bạn không vô tình làm lộ dữ liệu người dùng cho các ứng dụng khác trên thiết bị thông qua IPC quá tuỳ ý, tệp mà bất cứ ai cũng có thể ghi hoặc ổ cắm mạng. IPC quá tuỳ ý là một trường hợp đặc biệt về việc rò rỉ dữ liệu được bảo vệ bằng quyền, được thảo luận trong phần Yêu cầu quyền.
Nếu cần một Giá trị nhận dạng duy nhất trên toàn cầu (GUID), hãy tạo một số lớn, duy nhất và lưu số đó. Không sử dụng giá trị nhận dạng điện thoại như số điện thoại hoặc IMEI, những giá trị này có thể liên kết với thông tin cá nhân. Chủ đề này sẽ được thảo luận chi tiết hơn trên trang trình bày về các phương pháp hay nhất dành cho giá trị nhận dạng duy nhất.
Hãy thận trọng khi ghi vào nhật ký trên thiết bị. Trên Android, nhật ký là một tài nguyên dùng chung và có sẵn cho ứng dụng có quyền READ_LOGS
. Mặc dù dữ liệu nhật ký điện thoại chỉ là tạm thời và bị xoá khi khởi động lại, nhưng việc ghi nhật ký thông tin người dùng không đúng cách có thể vô tình làm rò rỉ dữ liệu người dùng cho các ứng dụng khác. Ngoài việc không ghi nhật ký PII (Thông tin nhận dạng cá nhân), hãy hạn chế sử dụng nhật ký trong các ứng dụng phát hành công khai. Để dễ dàng triển khai việc này, hãy sử dụng cờ gỡ lỗi và lớp Log
tuỳ chỉnh có cấp độ ghi nhật ký có thể dễ dàng định cấu hình.
WebView
Vì WebView
sử dụng nội dung trên web có thể bao gồm HTML và JavaScript, nên việc sử dụng không đúng cách có thể gây ra các vấn đề bảo mật web thường gặp như viết tập lệnh trên nhiều trang web (Chèn JavaScript). Android có một số cơ chế giúp giảm phạm vi của các vấn đề tiềm ẩn này bằng cách giới hạn khả năng của WebView
ở chức năng tối thiểu mà ứng dụng của bạn yêu cầu.
Nếu ứng dụng của bạn không trực tiếp sử dụng JavaScript trong WebView
, đừng gọi setJavaScriptEnabled
. Một số mã mẫu áp dụng phương thức này; nếu bạn dùng lại mã mẫu sử dụng phương thức này trong ứng dụng chính thức, hãy xoá lệnh gọi phương thức đó nếu không cần thiết. Theo mặc định, WebView
không thực thi JavaScript, vì vậy, bạn không thể viết tập lệnh trên nhiều trang web.
Hãy đặc biệt thận trọng khi dùng addJavaScriptInterface()
vì mã này cho phép JavaScript gọi các thao tác thường dành riêng cho các ứng dụng Android. Nếu sử dụng phương thức này, bạn chỉ hiển thị addJavaScriptInterface()
cho các trang web mà mọi dữ liệu đầu vào đều đáng tin cậy. Nếu cho phép dữ liệu đầu vào không đáng tin cậy, thì JavaScript không đáng tin cậy có thể gọi các phương thức Android trong ứng dụng của bạn. Nhìn chung, bạn chỉ nên hiển thị addJavaScriptInterface()
cho JavaScript có trong APK ứng dụng.
Nếu ứng dụng của bạn truy cập vào dữ liệu nhạy cảm bằng WebView
, hãy cân nhắc sử dụng phương thức clearCache()
để xoá mọi tệp được lưu trữ trên thiết bị. Bạn cũng có thể sử dụng các tiêu đề phía máy chủ, chẳng hạn như no-store
để cho biết rằng ứng dụng không nên lưu nội dung cụ thể vào bộ nhớ đệm.
Thiết bị chạy các nền tảng trước phiên bản Android 4.4 (API cấp 19) sử dụng phiên bản webkit
gặp một số vấn đề bảo mật. Để giải quyết vấn đề, nếu ứng dụng của bạn đang chạy trên những thiết bị này, thì phải xác nhận rằng các đối tượng WebView
chỉ hiển thị nội dung đáng tin cậy. Để đảm bảo ứng dụng của bạn không gặp phải các lỗ hổng bảo mật có thể xảy ra trong SSL, hãy sử dụng đối tượng Provider
bảo mật có thể cập nhật như mô tả trong phần Cập nhật trình cung cấp dịch vụ bảo mật để chống khai thác SSL. Nếu ứng dụng của bạn phải kết xuất nội dung từ web mở, hãy cân nhắc việc cung cấp trình kết xuất đồ hoạ riêng để bạn luôn cập nhật các bản vá bảo mật mới nhất cho ứng dụng.
Yêu cầu về thông tin xác thực
Các yêu cầu về thông tin xác thực chính là nhân tố trung gian của các cuộc tấn công. Dưới đây là một số mẹo giúp bạn thực hiện các yêu cầu về thông tin xác thực trong ứng dụng Android một cách an toàn hơn.
Giảm thiểu nguy cơ rò rỉ thông tin xác thực
- Tránh những yêu cầu không cần thiết về thông tin xác thực. Để các cuộc tấn công lừa đảo dễ nhận thấy hơn và khó thành công hơn, hãy giảm thiểu tần suất yêu cầu thông tin xác thực của người dùng. Thay vào đó, hãy sử dụng mã thông báo uỷ quyền và làm mới mã đó. Chỉ yêu cầu lượng thông tin xác thực tối thiểu cần thiết để xác thực và uỷ quyền.
- Lưu trữ thông tin xác thực một cách an toàn. Sử dụng Trình quản lý thông tin xác thực để bật tính năng xác thực không cần mật khẩu bằng khoá truy cập hoặc triển khai quy trình đăng nhập liên kết bằng các giao thức như Đăng nhập bằng Google. Nếu bạn phải sử dụng phương thức xác thực bằng mật khẩu truyền thống, đừng lưu trữ mã nhận dạng người dùng và mật khẩu trên thiết bị này. Thay vào đó, hãy dùng tên người dùng và mật khẩu do người dùng cung cấp để thực hiện bước xác thực ban đầu, rồi sử dụng mã thông báo uỷ quyền ngắn hạn dành riêng cho từng dịch vụ.
- Giới hạn phạm vi của quyền. Không yêu cầu quyền trên phạm vi rộng cho một tác vụ chỉ yêu cầu quyền có phạm vi hẹp hơn.
- Hạn chế mã truy cập. Sử dụng những thao tác dùng mã thông báo ngắn hạn và các lệnh gọi API.
- Giới hạn tốc độ xác thực. Các yêu cầu xác thực/uỷ quyền nhanh, liên tiếp có thể là dấu hiệu của một cuộc tấn công brute force. Hãy giới hạn các tốc độ này ở tần suất hợp lý mà vẫn đem lại trải nghiệm ứng dụng thân thiện với người dùng.
Dùng phương pháp xác thực bảo mật
- Triển khai khoá truy cập. Sử dụng khoá truy cập để nâng cấp mật khẩu một cách an toàn và thân thiện với người dùng hơn.
- Thêm hệ thống nhận dạng sinh trắc học. Cung cấp khả năng xác thực bằng sinh trắc học, chẳng hạn như vân tay hoặc công nghệ nhận dạng khuôn mặt, để tăng cường bảo mật.
- Sử dụng các nhà cung cấp danh tính được liên kết. Trình quản lý thông tin xác thực hỗ trợ các nhà cung cấp dịch vụ xác thực được liên kết, chẳng hạn như Đăng nhập bằng Google.
- Mã hoá nội dung giao tiếp Hãy dùng HTTPS và các công nghệ tương tự để đảm bảo dữ liệu mà ứng dụng của bạn gửi qua mạng được bảo vệ.
Thực hiện quy trình quản lý tài khoản an toàn
- Kết nối với các dịch vụ có thể truy cập được nhiều ứng dụng bằng
AccountManager
. Sử dụng lớpAccountManager
để gọi một dịch vụ trên đám mây và không lưu trữ mật khẩu trên thiết bị. - Sau khi sử dụng
AccountManager
để truy xuấtAccount
, hãy dùngCREATOR
trước khi truyền bất kỳ thông tin xác thực nào để bạn không vô tình truyền thông tin xác thực vào không đúng ứng dụng. - Nếu thông tin xác thực chỉ được các ứng dụng mà bạn tạo dùng, thì bạn có thể xác minh ứng dụng truy cập vào
AccountManager
bằngcheckSignatures
. Ngoài ra, nếu chỉ có một ứng dụng sử dụng thông tin xác thực, thì bạn có thể dùngKeyStore
để lưu trữ.
Luôn cảnh giác
- Luôn cập nhật mã của bạn. Hãy nhớ cập nhật mã nguồn của bạn (kể cả mọi thư viện và phần phụ thuộc của bên thứ ba) để bảo vệ khỏi các lỗ hổng bảo mật mới nhất.
- Giám sát hoạt động đáng ngờ. Tìm kiếm hành vi sử dụng sai mục đích có thể có, chẳng hạn như trường hợp sử dụng sai lệnh uỷ quyền.
- Kiểm tra mã của bạn. Thường xuyên tiến hành kiểm tra bảo mật đối với cơ sở mã của bạn để tìm các vấn đề tiềm ẩn liên quan đến các yêu cầu về thông tin xác thực.
Quản lý khoá API
Khoá API là một thành phần quan trọng của nhiều ứng dụng Android, cho phép các ứng dụng này truy cập vào các dịch vụ bên ngoài và thực hiện các chức năng thiết yếu như kết nối với các dịch vụ liên kết, phương thức xác thực và dịch vụ thời tiết. Tuy nhiên, việc để lộ những khoá nhạy cảm này có thể gây ra hậu quả nghiêm trọng, bao gồm cả rò rỉ dữ liệu, truy cập trái phép và tổn thất tài chính. Để ngăn chặn những hậu quả như vậy, nhà phát triển nên triển khai các chiến lược bảo mật để xử lý khoá API trong suốt quá trình phát triển.
Để tránh sử dụng sai các dịch vụ, khoá API phải được bảo vệ cẩn thận. Để bảo mật cho kết nối giữa ứng dụng và một dịch vụ sử dụng khoá API, bạn cần giữ bảo mật quyền truy cập vào API đó. Khi ứng dụng của bạn được biên dịch và mã nguồn của ứng dụng chứa các khoá API, kẻ tấn công có thể biên dịch ngược ứng dụng và tìm thấy các tài nguyên này.
Phần này dành cho 2 nhóm nhà phát triển Android: những người làm việc với các nhóm phụ trách cơ sở hạ tầng trong quy trình phân phối liên tục và những người triển khai các ứng dụng độc lập trên Cửa hàng Play. Phần này trình bày các phương pháp hay nhất về cách xử lý khoá API để ứng dụng của bạn có thể giao tiếp một cách an toàn với các dịch vụ.
Tạo và lưu trữ
Nhà phát triển nên coi cơ chế lưu trữ khoá API là một thành phần quan trọng giúp bảo vệ dữ liệu và quyền riêng tư của người dùng bằng một phương pháp phòng thủ theo chiều sâu.
Cơ chế lưu trữ khoá mạnh
Để tối ưu hoá khả năng bảo mật cho quy trình quản lý khoá, hãy dùng Kho khoá Android và mã hoá các khoá được lưu trữ bằng một công cụ mạnh mẽ như thư viện Jetpack security-Crypto hoặc Tink Java.
Ví dụ sau đây sử dụng thư viện Jetpack Security-Crypto để tạo các lựa chọn ưu tiên dùng chung được mã hoá.
Kotlin
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val encryptedSharedPreferences = EncryptedSharedPreferences.create(
context,
"secret_shared_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
// use the shared preferences and editor as you normally would
encryptedSharedPreferences.edit()
Java
MasterKey masterKey = new MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
context,
"secret_shared_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
// use the shared preferences and editor as you normally would
SharedPreferences.Editor editor = sharedPreferences.edit();
Loại trừ quyền kiểm soát nguồn
Tuyệt đối không chuyển khoá API vào kho lưu trữ mã nguồn của bạn. Việc thêm khoá API vào mã nguồn dẫn đến nguy cơ làm lộ khoá với kho lưu trữ công khai, mẫu mã được chia sẻ và các tệp vô tình được chia sẻ. Thay vào đó, hãy sử dụng các trình bổ trợ Gradle, chẳng hạn như secrets-gradle-plugin để thao tác với các khoá API trong dự án của bạn.
Khoá dành riêng cho môi trường
Nếu có thể, hãy sử dụng các môi trường riêng biệt cho giai đoạn phát triển, thử nghiệm và phát hành chính thức khoá API. Hãy sử dụng các khoá dành riêng cho môi trường để tách biệt từng môi trường, làm giảm nguy cơ để lộ dữ liệu của hoạt động phát hành chính thức và giúp bạn vô hiệu hoá các khoá bị xâm phạm mà không làm ảnh hưởng đến môi trường phát hành chính thức.
Kiểm soát quyền truy cập và mức sử dụng
Bạn nên dùng các phương pháp khoá API bảo mật để bảo vệ API và người dùng của bạn. Sau đây là cách chuẩn bị khoá để đảm bảo độ bảo mật tối ưu:
- Tạo các khoá duy nhất cho mỗi ứng dụng: Sử dụng các khoá API riêng biệt cho từng ứng dụng để giúp xác định và tách biệt quyền truy cập bị xâm phạm.
- Triển khai các hạn chế về IP: Nếu có thể, hãy giới hạn việc sử dụng khoá API ở các địa chỉ hoặc dải IP cụ thể.
- Giới hạn mức sử dụng khoá ứng dụng di động: Giới hạn mức sử dụng khoá API cho các ứng dụng di động cụ thể bằng cách nhóm các ứng dụng đó với khoá hoặc dùng chứng chỉ ứng dụng.
- Ghi nhật ký và giám sát hoạt động đáng ngờ: Triển khai cơ chế giám sát và ghi nhật ký mức sử dụng API để phát hiện hoạt động đáng ngờ và ngăn chặn nguy cơ sử dụng sai mục đích.
Lưu ý: Dịch vụ của bạn phải cung cấp các tính năng để hạn chế khoá với một gói hoặc nền tảng cụ thể. Ví dụ: API Google Maps giới hạn quyền truy cập vào khoá theo tên gói và khoá ký.
OAuth 2.0 cung cấp một khung cho phép truy cập vào các tài nguyên. Giao thức này xác định các tiêu chuẩn về cách máy khách và máy chủ sẽ tương tác, đồng thời cho phép tiến hành quá trình uỷ quyền an toàn. Bạn có thể sử dụng OAuth 2.0 để hạn chế việc sử dụng khoá API ở một số máy khách cụ thể và xác định phạm vi truy cập để mỗi khoá API chỉ có cấp truy cập tối thiểu cần thiết cho mục đích của khoá API đó.
Xoay vòng và hết hạn khoá
Để giảm nguy cơ bị truy cập trái phép thông qua các lỗ hổng API chưa phát hiện, bạn cần thường xuyên xoay vòng các khoá API. Tiêu chuẩn ISO 27001 xác định một khung tuân thủ về tần suất thực hiện việc xoay vòng khoá. Đối với hầu hết các trường hợp, khoảng thời gian xoay vòng khoá từ 90 ngày đến 6 tháng là đủ. Việc triển khai một hệ thống quản lý khoá mạnh mẽ có thể giúp bạn đơn giản hoá các quy trình này, cải thiện hiệu quả cho nhu cầu xoay vòng và hết hạn khoá.
Các phương pháp chung hay nhất
- Sử dụng SSL/HTTPS: Luôn sử dụng phương thức giao tiếp HTTPS để mã hoá các yêu cầu API.
- Ghim chứng chỉ: Để thêm một lớp bảo mật, bạn có thể cân nhắc việc triển khai tính năng ghim chứng chỉ để kiểm tra xem chứng chỉ nào được coi là hợp lệ.
- Xác thực và dọn dẹp dữ liệu hoạt động đầu vào của người dùng: Xác thực và dọn dẹp dữ liệu hoạt động đầu vào của người dùng để ngăn chặn các cuộc tấn công tiêm mã có thể làm lộ khoá API.
- Làm theo các phương pháp hay nhất về bảo mật: Triển khai các phương pháp chung hay nhất về bảo mật trong quá trình phát triển, bao gồm cả kỹ thuật lập trình an toàn, đánh giá mã và quét lỗ hổng.
- Nắm bắt thông tin: Luôn cập nhật thông tin về các mối đe doạ bảo mật mới nhất và các phương pháp hay nhất về quản lý khoá API.
- Cập nhật SDK: Hãy nhớ cập nhật SDK và thư viện của bạn lên phiên bản mới nhất.
Mật mã học
Ngoài việc cung cấp khả năng tách biệt dữ liệu, hỗ trợ mã hoá toàn bộ hệ thống tệp và cung cấp các kênh liên lạc an toàn, Android còn cung cấp nhiều thuật toán giúp bảo vệ dữ liệu bằng phương thức mã hoá.
Biết được trình cung cấp dịch vụ bảo mật Kiến trúc mã hoá Java (JCA) nào mà phần mềm của bạn sử dụng. Hãy cố gắng dùng cấp độ triển khai cao nhất cho khung có sẵn, có thể hỗ trợ cho trường hợp sử dụng của bạn. Nếu có, hãy sử dụng các trình cung cấp do Google đưa ra theo thứ tự do Google chỉ định.
Nếu bạn cần truy xuất an toàn một tệp từ một vị trí mạng đã biết, thì một URI HTTPS đơn giản có thể là đủ và bạn không cần phải có kiến thức về mã hoá. Nếu bạn cần một đường hầm bảo mật, hãy cân nhắc sử dụng HttpsURLConnection
hoặc SSLSocket
thay vì tự viết giao thức. Nếu bạn sử dụng SSLSocket
, hãy lưu ý rằng việc này sẽ không xác minh tên máy chủ. Xem phần Cảnh báo về việc sử dụng SSLSocket
trực tiếp.
Nếu bạn thấy cần triển khai giao thức của riêng mình, đừng triển khai thuật toán mật mã của riêng bạn. Sử dụng các thuật toán mật mã hiện có, chẳng hạn như việc triển khai AES và RSA được cung cấp trong lớp Cipher
.
Ngoài ra, hãy làm theo các phương pháp hay nhất sau đây:
- Sử dụng AES 256 bit cho mục đích thương mại. (Nếu không có, hãy sử dụng AES 128 bit.)
- Sử dụng khoá công khai có kích thước 224 hoặc 256 bit để mã hoá đường cong elip (EC).
- Biết thời điểm nào nên sử dụng chế độ chặn CBC, CTR hoặc GCM.
- Tránh sử dụng lại IV/bộ đếm ở chế độ CTR. Đảm bảo rằng chúng ngẫu nhiên theo mã hoá.
- Khi dùng tính năng mã hoá, hãy triển khai tính toàn vẹn bằng chế độ CBC hoặc CTR cùng một trong các hàm sau:
- HMAC-SHA1
- HMAC-SHA-256
- HMAC-SHA-512
- Chế độ GCM
Sử dụng hàm tạo số ngẫu nhiên an toàn, SecureRandom
để khởi động bất kỳ khoá mã hoá nào do KeyGenerator
tạo. Việc sử dụng khoá không được tạo bằng hàm tạo số ngẫu nhiên an toàn sẽ làm suy yếu đáng kể sức mạnh của thuật toán và có thể cho phép cuộc tấn công ngoại tuyến.
Nếu bạn cần lưu một khoá để sử dụng nhiều lần, hãy sử dụng một cơ chế, chẳng hạn như KeyStore
. Cơ chế này giúp có thể lưu trữ dài hạn và truy xuất khoá mã hoá.
Giao tiếp liên quy trình
Một số ứng dụng cố gắng triển khai IPC bằng các kỹ thuật Linux truyền thống, chẳng hạn như ổ cắm mạng và tệp dùng chung. Tuy nhiên, thay vào đó, bạn nên sử dụng chức năng hệ thống của Android cho IPC, chẳng hạn như Intent
, Binder
hoặc Messenger
với Service
và BroadcastReceiver
. Cơ chế IPC trên Android cho phép bạn xác minh danh tính của ứng dụng đang kết nối với IPC của bạn và đặt chính sách bảo mật cho từng cơ chế IPC.
Nhiều phần tử bảo mật được dùng chung trên các cơ chế IPC. Nếu cơ chế IPC của bạn không để các ứng dụng khác dùng, hãy đặt thuộc tính android:exported
cho false
trong phần tử tệp kê khai của thành phần, chẳng hạn như cho phần tử <service>
. Điều này hữu ích cho các ứng dụng gồm nhiều quy trình trong cùng một UID hoặc nếu sau này trong quá trình phát triển bạn quyết định rằng mình không thực sự muốn hiển thị chức năng dưới dạng IPC, nhưng bạn không muốn viết lại mã.
Nếu các ứng dụng khác có thể truy cập vào IPC của bạn, thì bạn có thể áp dụng chính sách bảo mật bằng cách dùng phần tử <permission>
. Nếu IPC nằm giữa các ứng dụng của riêng bạn và được ký bằng cùng một khoá, hãy sử dụng quyền cấp signature-level
trong android:protectionLevel
.
Ý định
Đối với các hoạt động và bộ nhận tín hiệu truyền tin, ý định là cơ chế ưu tiên cho IPC không đồng bộ trên Android. Tuỳ thuộc vào yêu cầu về ứng dụng, bạn có thể dùng sendBroadcast
, sendOrderedBroadcast
hoặc một ý định tường minh đối với một thành phần cụ thể của ứng dụng. Vì mục đích bảo mật, bạn nên ưu tiên các ý định tường minh.
Thận trọng: Nếu bạn sử dụng một ý định để liên kết với một **Service**
, hãy dùng một ý định rõ ràng để đảm bảo an toàn cho ứng dụng. Việc sử dụng ý định ngầm ẩn để bắt đầu một dịch vụ sẽ gây ra mối nguy hiểm về bảo mật, vì bạn không thể chắc chắn dịch vụ nào sẽ phản hồi ý định và người dùng không thể biết dịch vụ nào sẽ bắt đầu. Kể từ Android 5.0 (API cấp 21), hệ thống sẽ gửi một ngoại lệ nếu bạn gọi **bindService()**
với ý định ngầm ẩn.
Lưu ý rằng người nhận có thể sử dụng các thông báo truyền tin có thứ tự, vì vậy những thông báo này có thể không được gửi cho tất cả các ứng dụng. Nếu đang gửi một ý định phải được gửi đến một dịch vụ nhận cụ thể, bạn phải sử dụng một ý định tường minh khai báo dịch vụ nhận theo tên.
Người gửi ý định có thể xác minh người nhận có quyền bằng cách chỉ định quyền không rỗng qua lệnh gọi phương thức. Chỉ những ứng dụng có quyền đó mới nhận được ý định. Nếu dữ liệu trong một ý định truyền tin có thể nhạy cảm, hãy cân nhắc áp dụng một quyền để đảm bảo các ứng dụng độc hại sẽ không thể đăng ký nhận các thông báo đó nếu không có các quyền phù hợp. Trong những trường hợp đó, bạn cũng có thể cân nhắc gọi trực tiếp dịch vụ nhận thay vì đưa ra thông báo truyền tin.
Lưu ý: Bộ lọc ý định không phải là tính năng bảo mật. Các thành phần có thể được gọi bằng ý định tường minh và có thể không có dữ liệu phù hợp với bộ lọc ý định. Để xác nhận rằng dữ liệu được định dạng đúng với dịch vụ nhận, dịch vụ hoặc hoạt động được gọi, hãy thực hiện quy trình xác thực dữ liệu đầu vào trong dịch vụ nhận ý định của bạn.
Dịch vụ
Service
thường được sử dụng để cung cấp chức năng cho các ứng dụng khác dùng. Mỗi lớp dịch vụ phải có phần khai báo <service>
tương ứng trong tệp kê khai.
Theo mặc định, không xuất và không gọi được các ứng dụng bằng bất kỳ ứng dụng nào khác. Tuy nhiên, nếu bạn thêm bất kỳ bộ lọc ý định nào vào phần khai báo dịch vụ, thì hệ thống sẽ xuất theo mặc định. Tốt nhất là bạn nên khai báo rõ ràng thuộc tính android:exported
để đảm bảo thuộc tính này hoạt động theo cách bạn mong muốn. Các dịch vụ cũng có thể được bảo vệ bằng thuộc tính android:permission
. Khi làm vậy, các ứng dụng khác cần khai báo phần tử <uses-permission>
tương ứng trong tệp kê khai riêng để có thể bắt đầu, dừng hoặc liên kết với dịch vụ.
Lưu ý: Nếu ứng dụng của bạn nhắm đến Android 5.0 (API cấp 21) trở lên, hãy dùng **JobScheduler**
để thực thi các dịch vụ nền.
Một dịch vụ có thể bảo vệ từng lệnh gọi IPC có thể sử dụng các quyền. Bạn có thể thực hiện việc này bằng cách gọi checkCallingPermission()
trước khi thực thi phương thức triển khai lệnh gọi. Bạn nên sử dụng các quyền khai báo trong tệp kê khai, vì các quyền đó ít khi bị giám sát hơn.
Thận trọng: Đừng nhầm lẫn quyền của máy khách và máy chủ; hãy đảm bảo ứng dụng được gọi có các quyền thích hợp và xác minh rằng bạn cấp các quyền tương tự cho ứng dụng gọi.
Giao diện Binder và Messenger
Sử dụng Binder
hoặc Messenger
là cơ chế ưu tiên cho IPC kiểu RPC trên Android. Hai lớp này cung cấp các giao diện được xác định rõ ràng cho phép xác thực lẫn nhau các điểm cuối, nếu cần.
Bạn nên thiết kế giao diện ứng dụng của mình theo cách không yêu cầu kiểm tra quyền theo giao diện cụ thể. Các đối tượng Binder
và Messenger
không được khai báo trong tệp kê khai ứng dụng. Do vậy, bạn không thể áp dụng quyền khai báo trực tiếp cho những đối tượng đó. Các đối tượng này thường kế thừa những quyền được khai báo trong tệp kê khai ứng dụng cho Service
hoặc Activity
ở nơi triển khai các quyền đó. Nếu đang tạo một giao diện yêu cầu xác thực và/hoặc kiểm soát quyền truy cập, bạn phải thêm các chế độ điều khiển đó dưới dạng mã một cách rõ ràng trong giao diện Binder
hoặc Messenger
.
Nếu bạn đang cung cấp một giao diện yêu cầu kiểm soát quyền truy cập, hãy sử dụng checkCallingPermission()
để xác minh xem phương thức gọi có quyền cần thiết hay không. Điều này đặc biệt quan trọng trước khi thay mặt phương thức gọi truy cập một dịch vụ, vì danh tính của ứng dụng được truyền sang các giao diện khác.
Nếu bạn gọi giao diện do Service
cung cấp, thì lệnh gọi bindService()
có thể không thành công nếu bạn không có quyền truy cập vào dịch vụ đã cho. Nếu cần cho phép một quy trình bên ngoài tương tác với ứng dụng của bạn nhưng không có các quyền cần thiết để thực hiện việc này, thì bạn có thể sử dụng phương thức clearCallingIdentity()
. Phương thức này thực hiện lệnh gọi đến giao diện của ứng dụng như thể ứng dụng đang tự thực hiện lệnh gọi chứ không phải phương thức gọi bên ngoài. Sau này, bạn có thể khôi phục quyền của phương thức gọi bằng phương thức restoreCallingIdentity()
.
Để biết thêm thông tin về cách thực hiện IPC bằng một dịch vụ, hãy xem bài viết Dịch vụ ràng buộc.
Bộ nhận tín hiệu truyền tin
BroadcastReceiver
xử lý tài nguyên không đồng bộ do Intent
khởi tạo.
Theo mặc định, dịch vụ nhận được xuất và có thể được bất kỳ ứng dụng nào khác gọi.
Nếu định dùng BroadcastReceiver
cho các ứng dụng khác, thì bạn nên áp dụng quyền bảo mật cho các dịch vụ nhận bằng cách sử dụng phần tử <receiver>
trong tệp kê khai ứng dụng. Thao tác này ngăn các ứng dụng không có quyền thích hợp gửi ý định đến BroadcastReceiver
.
Bảo mật bằng mã được tải động
Bạn tuyệt đối không nên tải mã từ bên ngoài APK ứng dụng của bạn. Làm như vậy sẽ làm tăng đáng kể khả năng ứng dụng bị xâm phạm do bị chèn mã hoặc can thiệp mã. Điều này cũng làm tăng độ phức tạp của việc quản lý phiên bản và kiểm thử ứng dụng, đồng thời có thể khiến bạn không thể xác minh hành vi của một ứng dụng, vì vậy, ứng dụng này có thể bị cấm trong một số môi trường.
Nếu ứng dụng của bạn tải mã động, thì điều quan trọng nhất cần lưu ý là mã được tải động sẽ chạy với các quyền bảo mật tương tự như APK của ứng dụng. Người dùng đưa ra quyết định cài đặt ứng dụng dựa trên danh tính của bạn và người dùng muốn bạn cung cấp bất kỳ mã nào chạy trong ứng dụng, bao gồm cả mã được tải động.
Nhiều ứng dụng cố tải mã từ các vị trí không an toàn, chẳng hạn như tải xuống từ mạng qua các giao thức chưa mã hoá hoặc từ các vị trí có thể ghi trên toàn cầu, chẳng hạn như bộ nhớ ngoài. Các vị trí này có thể cho phép người nào đó trên mạng sửa đổi nội dung trong khi truyền hoặc một ứng dụng khác trên thiết bị của người dùng sửa đổi nội dung trên thiết bị. Ngược lại, các ứng dụng khác không thể sửa đổi các mô-đun được đưa trực tiếp trong APK của bạn. Điều này luôn đúng cho dù mã là thư viện gốc hay lớp được tải bằng DexClassLoader
.
Bảo mật trong máy ảo
Dalvik là máy ảo (VM) thời gian chạy của Android. Dalvik được tạo riêng cho Android, nhưng nhiều mối lo ngại về mã bảo mật trong các máy ảo khác cũng áp dụng với Android. Nhìn chung, bạn không cần phải lo lắng về các vấn đề bảo mật liên quan đến máy ảo. Ứng dụng của bạn chạy trong môi trường hộp cát bảo mật nên các quy trình khác trên hệ thống không thể truy cập vào mã hoặc dữ liệu riêng tư của bạn.
Nếu bạn muốn biết thêm về vấn đề bảo mật trong máy ảo, hãy tìm hiểu một số tài liệu hiện có về chủ đề này. Sau đây là 2 tài nguyên phổ biến nhất:
Tài liệu này tập trung vào những khía cạnh đặc trưng của Android hoặc khác với các môi trường máy ảo khác. Đối với các nhà phát triển gặp phải vấn đề lập trình máy ảo trong các môi trường khác, có 2 vấn đề rộng có thể khác khi viết ứng dụng cho Android:
- Một số máy ảo, chẳng hạn như thời gian chạy JVM hoặc .NET, đóng vai trò như một ranh giới bảo mật, tách biệt mã với các chức năng cơ bản của hệ điều hành. Trên Android, máy ảo Dalvik không phải là ranh giới bảo mật — hộp cát của ứng dụng được triển khai ở cấp hệ điều hành, vì vậy, Dalvik có thể tương tác với mã gốc trong cùng một ứng dụng mà không có bất kỳ hạn chế bảo mật nào.
- Do bộ nhớ hạn chế trên thiết bị di động, các nhà phát triển thường muốn tạo các ứng dụng theo mô-đun và sử dụng tính năng tải lớp động. Khi thực hiện việc này, hãy xem xét cả nguồn nơi bạn truy xuất logic ứng dụng lẫn nơi bạn lưu trữ logic ứng dụng trên thiết bị. Không sử dụng tính năng tải lớp động từ các nguồn chưa được xác minh, chẳng hạn như các nguồn mạng hoặc bộ nhớ ngoài không bảo mật, vì mã đó có thể bị sửa đổi để bao gồm hành vi độc hại.
Bảo mật trong mã gốc
Nhìn chung, bạn nên sử dụng SDK Android để phát triển ứng dụng thay vì sử dụng mã gốc với Android NDK. Các ứng dụng được tạo bằng mã gốc phức tạp hơn, ít linh hoạt hơn và nhiều khả năng sẽ bao gồm các lỗi gây hỏng bộ nhớ thường gặp như tràn vùng đệm.
Android được tạo bằng nhân hệ điều hành Linux và việc tìm hiểu các phương pháp hay nhất về bảo mật phát triển của Linux sẽ đặc biệt hữu ích nếu bạn đang sử dụng mã gốc. Các phương pháp bảo mật của Linux nằm ngoài phạm vi của tài liệu này, nhưng một trong những tài nguyên phổ biến nhất là cách lập trình bảo mật HOWTO – Tạo phần mềm bảo mật.
Một điểm khác biệt quan trọng giữa Android và hầu hết các môi trường Android là hộp cát của ứng dụng. Trên Android, tất cả ứng dụng đều chạy trong hộp cát của ứng dụng, bao gồm cả những ứng dụng được viết bằng mã gốc. Một cách hay để xem xét vấn đề này cho các nhà phát triển quen thuộc với Linux là biết rằng mỗi ứng dụng đều được cấp một Giá trị nhận dạng người dùng (UID) duy nhất với các quyền rất hạn chế. Vấn đề này sẽ được thảo luận chi tiết hơn trong bài viết Tổng quan về vấn đề bảo mật của Android. Bạn nên nắm rõ các quyền cho ứng dụng ngay cả khi đang dùng mã gốc.