Danh mục OWASP: MASVS-CODE: Chất lượng mã
Tổng quan
Không hiếm khi thấy các ứng dụng triển khai chức năng cho phép người dùng chuyển dữ liệu hoặc tương tác với các thiết bị khác bằng cách sử dụng giao tiếp tần số vô tuyến (RF) hoặc kết nối có dây. Các công nghệ phổ biến nhất được sử dụng trong Android dành cho mục đích này là Bluetooth cổ điển (Bluetooth BR/EDR), Bluetooth Thấp Năng lượng (BLE), Wi-Fi P2P, NFC và USB.
Các công nghệ này thường được triển khai trong các ứng dụng dự kiến sẽ giao tiếp với các phụ kiện nhà thông minh, thiết bị theo dõi sức khoẻ, ki-ốt phương tiện công cộng, thiết bị thanh toán và các thiết bị khác chạy Android.
Giống như bất kỳ kênh nào khác, hoạt động giao tiếp giữa các máy dễ bị nhằm mục đích xâm phạm ranh giới tin cậy đã thiết lập giữa hai hoặc thiết bị khác. Các kỹ thuật như mạo danh thiết bị có thể được tận dụng bằng người dùng độc hại để có được nhiều cuộc tấn công nhắm vào thông tin của bạn.
Android tạo các API cụ thể để định cấu hình giữa các máy thông tin dành cho nhà phát triển.
Nên sử dụng cẩn thận những API này để tránh bị lỗi khi triển khai giao tiếp các giao thức có thể khiến dữ liệu người dùng hoặc thiết bị bị tiết lộ trái phép bên thứ ba. Trong trường hợp xấu nhất, kẻ tấn công có thể chiếm quyền kiểm soát một hoặc nhiều thiết bị, do đó có toàn quyền truy cập vào nội dung trên thiết bị.
Tác động
Mức độ tác động có thể khác nhau tuỳ theo công nghệ giữa các thiết bị được triển khai trong ứng dụng.
Việc sử dụng hoặc định cấu hình không đúng cách các kênh giao tiếp giữa máy với máy có thể khiến thiết bị của người dùng bị lộ trước các nỗ lực giao tiếp không đáng tin cậy. Điều này có thể khiến thiết bị dễ bị các cuộc tấn công khác như tấn công xen giữa (MiTM), chèn lệnh, DoS hoặc mạo danh.
Rủi ro: Nghe trộm dữ liệu nhạy cảm qua các kênh không dây
Khi triển khai cơ chế giao tiếp giữa máy và máy, hãy cẩn thận nên cân nhắc cả công nghệ sử dụng và loại dữ liệu cần được truyền đi. Kết nối có cáp thực tế lại an toàn hơn cho các nhiệm vụ đó, vì chúng yêu cầu một liên kết thực giữa các thiết bị liên quan, giao thức truyền thông sử dụng các tần số vô tuyến như Bluetooth cổ điển, BLE, NFC và Wi-Fi P2P có thể bị chặn. Kẻ tấn công có thể mạo danh đầu cuối hoặc điểm truy cập liên quan đến việc trao đổi dữ liệu, liên lạc không dây, do đó có được quyền truy cập vào thông tin . Ngoài ra, các ứng dụng độc hại được cài đặt trên thiết bị, nếu được cấp quyền khi bắt đầu chạy dành riêng cho hoạt động giao tiếp, có thể truy xuất dữ liệu được trao đổi giữa các thiết bị bằng cách đọc vùng đệm thông báo hệ thống.
Giải pháp giảm thiểu
Nếu ứng dụng yêu cầu trao đổi dữ liệu nhạy cảm giữa các máy qua các kênh không dây, sau đó là các giải pháp bảo mật lớp ứng dụng, chẳng hạn như mã hoá, cần được triển khai trong mã của ứng dụng. Điều này sẽ giúp ngăn chặn những kẻ tấn công có thể theo dõi kênh liên lạc và truy xuất dữ liệu được trao đổi ở dạng văn bản thô. Để xem thêm tài nguyên, hãy tham khảo Tài liệu về Mật mã học.
Rủi ro: Chèn dữ liệu độc hại không dây
Các kênh giao tiếp không dây giữa máy với máy (Bluetooth cổ điển, BLE, NFC, Wifi P2P) có thể bị can thiệp bằng dữ liệu độc hại. Những kẻ tấn công có đủ kỹ năng có thể xác định giao thức giao tiếp đang sử dụng và can thiệp vào luồng trao đổi dữ liệu, chẳng hạn như bằng cách mạo danh một trong các điểm cuối, gửi tải trọng được tạo riêng. Loại lưu lượng truy cập độc hại này có thể làm giảm chức năng của ứng dụng và trong trường hợp xấu nhất, gây ra hành vi không mong muốn của ứng dụng và thiết bị hoặc dẫn đến các cuộc tấn công như DoS, chèn lệnh hoặc chiếm quyền kiểm soát thiết bị.
Giải pháp giảm thiểu
Android cung cấp cho nhà phát triển các API mạnh mẽ để quản lý giao tiếp giữa các máy, chẳng hạn như Bluetooth cổ điển, BLE, NFC và Wifi P2P. Bạn nên kết hợp các dữ liệu này với một logic xác thực dữ liệu được triển khai cẩn thận để dọn dẹp mọi dữ liệu được trao đổi giữa hai thiết bị.
Giải pháp này phải được triển khai ở cấp ứng dụng và phải bao gồm các bước kiểm tra để xác minh xem dữ liệu có độ dài, định dạng dự kiến và chứa tải trọng hợp lệ mà ứng dụng có thể diễn giải hay không.
Đoạn mã sau đây cho thấy ví dụ về logic xác thực dữ liệu. Điều này được triển khai trên ví dụ dành cho nhà phát triển Android để triển khai tính năng chuyển dữ liệu qua Bluetooth:
Kotlin
class MyThread(private val mmInStream: InputStream, private val handler: Handler) : Thread() {
private val mmBuffer = ByteArray(1024)
override fun run() {
while (true) {
try {
val numBytes = mmInStream.read(mmBuffer)
if (numBytes > 0) {
val data = mmBuffer.copyOf(numBytes)
if (isValidBinaryData(data)) {
val readMsg = handler.obtainMessage(
MessageConstants.MESSAGE_READ, numBytes, -1, data
)
readMsg.sendToTarget()
} else {
Log.w(TAG, "Invalid data received: $data")
}
}
} catch (e: IOException) {
Log.d(TAG, "Input stream was disconnected", e)
break
}
}
}
private fun isValidBinaryData(data: ByteArray): Boolean {
if (// Implement data validation rules here) {
return false
} else {
// Data is in the expected format
return true
}
}
}
Java
public void run() {
mmBuffer = new byte[1024];
int numBytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs.
while (true) {
try {
// Read from the InputStream.
numBytes = mmInStream.read(mmBuffer);
if (numBytes > 0) {
// Handle raw data directly
byte[] data = Arrays.copyOf(mmBuffer, numBytes);
// Validate the data before sending it to the UI activity
if (isValidBinaryData(data)) {
// Data is valid, send it to the UI activity
Message readMsg = handler.obtainMessage(
MessageConstants.MESSAGE_READ, numBytes, -1,
data);
readMsg.sendToTarget();
} else {
// Data is invalid
Log.w(TAG, "Invalid data received: " + data);
}
}
} catch (IOException e) {
Log.d(TAG, "Input stream was disconnected", e);
break;
}
}
}
private boolean isValidBinaryData(byte[] data) {
if (// Implement data validation rules here) {
return false;
} else {
// Data is in the expected format
return true;
}
}
Rủi ro: Chèn dữ liệu độc hại qua USB
Kẻ xấu có thể nhắm đến kết nối USB giữa hai thiết bị muốn chặn thông tin liên lạc. Trong trường hợp này, đường liên kết vật lý cần thiết tạo thành một lớp bảo mật bổ sung vì kẻ tấn công cần có quyền truy cập vào cáp kết nối các thiết bị đầu cuối để có thể nghe trộm bất kỳ thông báo nào. Một vectơ tấn công khác là các thiết bị USB không đáng tin cậy được cắm vào thiết bị một cách cố ý hoặc vô tình.
Nếu ứng dụng lọc thiết bị USB bằng PID/VID để kích hoạt một chức năng cụ thể trong ứng dụng, thì kẻ tấn công có thể can thiệp vào dữ liệu được gửi qua kênh USB bằng cách mạo danh thiết bị hợp lệ. Các cuộc tấn công dạng này có thể cho phép người dùng độc hại gửi tổ hợp phím đến thiết bị hoặc thực thi ứng dụng mà trong trường hợp xấu nhất có thể dẫn đến việc thực thi mã từ xa hoặc phần mềm không mong muốn tải xuống.
Giải pháp giảm thiểu
Bạn nên triển khai logic xác thực cấp ứng dụng. Logic này sẽ lọc dữ liệu được gửi qua USB để kiểm tra xem độ dài, định dạng và nội dung phù hợp với trường hợp sử dụng ứng dụng. Ví dụ: thiết bị theo dõi nhịp tim không được gửi lệnh nhấn phím.
Ngoài ra, khi có thể, bạn nên cân nhắc việc hạn chế số gói USB mà ứng dụng có thể nhận được từ thiết bị USB. Chiến dịch này ngăn chặn các thiết bị độc hại thực hiện các cuộc tấn công như cao su.
Việc xác thực này có thể được thực hiện bằng cách tạo một luồng mới để kiểm tra
nội dung vùng đệm, ví dụ: trên bulkTransfer
:
Kotlin
fun performBulkTransfer() {
// Stores data received from a device to the host in a buffer
val bytesTransferred = connection.bulkTransfer(endpointIn, buffer, buffer.size, 5000)
if (bytesTransferred > 0) {
if (//Checks against buffer content) {
processValidData(buffer)
} else {
handleInvalidData()
}
} else {
handleTransferError()
}
}
Java
public void performBulkTransfer() {
//Stores data received from a device to the host in a buffer
int bytesTransferred = connection.bulkTransfer(endpointIn, buffer, buffer.length, 5000);
if (bytesTransferred > 0) {
if (//Checks against buffer content) {
processValidData(buffer);
} else {
handleInvalidData();
}
} else {
handleTransferError();
}
}
Rủi ro cụ thể
Phần này tổng hợp các rủi ro đòi hỏi chiến lược giảm thiểu không theo chuẩn hoặc được giảm thiểu ở một số cấp độ SDK nhất định và được liệt kê ở đây chỉ để cho đủ.
Rủi ro: Bluetooth – thời gian phát hiện không chính xác
Như đã nêu bật trong tài liệu về Bluetooth dành cho nhà phát triển Android, trong khi
định cấu hình giao diện Bluetooth trong ứng dụng bằng cách sử dụng
Phương thức startActivityForResult(Intent, int)
để bật thiết bị
khả năng được phát hiện và việc đặt EXTRA_DISCOVERABLE_DURATION
thành 0 sẽ
làm cho thiết bị có thể phát hiện được
miễn là ứng dụng đang chạy
trong nền hoặc nền trước. Đối với thông số kỹ thuật Bluetooth cổ điển, các thiết bị có thể phát hiện liên tục phát đi các thông báo phát hiện cụ thể cho phép các thiết bị khác truy xuất dữ liệu thiết bị hoặc kết nối với thiết bị đó. Trong trường hợp như vậy, một bên thứ ba độc hại có thể chặn các thông báo như vậy và kết nối với thiết bị chạy Android. Sau khi kết nối, kẻ tấn công có thể thực hiện thêm các cuộc tấn công khác như đánh cắp dữ liệu, tấn công từ chối dịch vụ (DoS) hoặc chèn lệnh.
Giải pháp giảm thiểu
Không bao giờ đặt EXTRA_DISCOVERABLE_DURATION
thành 0. Nếu
Tham số EXTRA_DISCOVERABLE_DURATION
không được đặt. Theo mặc định, Android sẽ đặt
thiết bị có thể phát hiện được trong 2 phút. Giá trị tối đa có thể đặt cho
Tham số EXTRA_DISCOVERABLE_DURATION
là 2 giờ (7200 giây). Đó là
nên rút ngắn thời lượng có thể tìm thấy thành thời lượng ngắn nhất
tuỳ theo trường hợp sử dụng của ứng dụng.
Rủi ro: NFC – bộ lọc ý định được nhân bản
Ứng dụng độc hại có thể đăng ký bộ lọc ý định để đọc các thẻ NFC cụ thể hoặc Thiết bị có hỗ trợ NFC. Các bộ lọc này có thể sao chép các bộ lọc do ứng dụng hợp pháp xác định, cho phép kẻ tấn công đọc nội dung của dữ liệu NFC đã trao đổi. Cần lưu ý rằng, khi hai hoạt động chỉ định cùng một bộ lọc ý định cho thẻ NFC cụ thể, Trình chọn hoạt động là do đó, người dùng vẫn cần chọn để cuộc tấn công diễn ra thành công. Tuy nhiên, việc kết hợp bộ lọc ý định với tính năng che giấu vẫn có thể xảy ra. Kiểu tấn công này chỉ đáng kể đối với những trường hợp dữ liệu được trao đổi qua NFC có thể được coi là cực kỳ nhạy cảm.
Giải pháp giảm thiểu
Khi triển khai các tính năng đọc NFC trong một ứng dụng, bạn có thể sử dụng bộ lọc ý định cùng với bản ghi ứng dụng Android (AAR). Nhúng Bản ghi AAR bên trong thông báo NDEF sẽ đưa ra sự đảm bảo chắc chắn rằng chỉ ứng dụng hợp lệ và hoạt động xử lý NDEF có liên quan đã được bắt đầu. Thao tác này sẽ ngăn các ứng dụng hoặc hoạt động không mong muốn có mức đọc cao thẻ nhạy cảm hoặc dữ liệu thiết bị được trao đổi qua NFC.
Rủi ro: NFC – thiếu tính năng xác thực thông báo NDEF
Khi một thiết bị chạy Android nhận được dữ liệu từ một thẻ NFC hoặc thiết bị hỗ trợ NFC, hệ thống sẽ tự động kích hoạt ứng dụng hoặc hoạt động cụ thể được định cấu hình để xử lý thông báo NDEF có trong đó. Theo logic được triển khai trong ứng dụng, dữ liệu có trong thẻ hoặc nhận được từ thiết bị, có thể được phân phát đến các hoạt động khác để kích hoạt các thao tác khác, chẳng hạn như mở trang web.
Một ứng dụng thiếu tính năng xác thực nội dung thông báo NDEF có thể cho phép kẻ tấn công sử dụng thiết bị có hỗ trợ NFC hoặc thẻ NFC để chèn phần tải dữ liệu độc hại vào ứng dụng, gây ra hành vi không mong muốn có thể dẫn đến tệp độc hại tải xuống, chèn lệnh hoặc DoS.
Giải pháp giảm thiểu
Trước khi gửi thông báo NDEF nhận được đến bất kỳ thành phần nào khác của ứng dụng, dữ liệu trong đó phải được xác thực để có định dạng dự kiến và chứa thông tin dự kiến. Điều này giúp tránh việc dữ liệu độc hại được truyền đến các thành phần của ứng dụng khác mà không được lọc, giảm nguy cơ hành vi hoặc cuộc tấn công ngoài mong muốn bằng cách sử dụng dữ liệu NFC bị can thiệp.
Đoạn mã sau đây minh hoạ logic xác thực dữ liệu mẫu được triển khai dưới dạng một có thông báo NDEF làm đối số và chỉ mục của nó trong mảng thông báo. Phương thức này được triển khai trên ví dụ dành cho nhà phát triển Android để lấy dữ liệu từ thẻ NFC NDEF đã quét:
Kotlin
//The method takes as input an element from the received NDEF messages array
fun isValidNDEFMessage(messages: Array<NdefMessage>, index: Int): Boolean {
// Checks if the index is out of bounds
if (index < 0 || index >= messages.size) {
return false
}
val ndefMessage = messages[index]
// Retrieves the record from the NDEF message
for (record in ndefMessage.records) {
// Checks if the TNF is TNF_ABSOLUTE_URI (0x03), if the Length Type is 1
if (record.tnf == NdefRecord.TNF_ABSOLUTE_URI && record.type.size == 1) {
// Loads payload in a byte array
val payload = record.payload
// Declares the Magic Number that should be matched inside the payload
val gifMagicNumber = byteArrayOf(0x47, 0x49, 0x46, 0x38, 0x39, 0x61) // GIF89a
// Checks the Payload for the Magic Number
for (i in gifMagicNumber.indices) {
if (payload[i] != gifMagicNumber[i]) {
return false
}
}
// Checks that the Payload length is, at least, the length of the Magic Number + The Descriptor
if (payload.size == 13) {
return true
}
}
}
return false
}
Java
//The method takes as input an element from the received NDEF messages array
public boolean isValidNDEFMessage(NdefMessage[] messages, int index) {
//Checks if the index is out of bounds
if (index < 0 || index >= messages.length) {
return false;
}
NdefMessage ndefMessage = messages[index];
//Retrieve the record from the NDEF message
for (NdefRecord record : ndefMessage.getRecords()) {
//Check if the TNF is TNF_ABSOLUTE_URI (0x03), if the Length Type is 1
if ((record.getTnf() == NdefRecord.TNF_ABSOLUTE_URI) && (record.getType().length == 1)) {
//Loads payload in a byte array
byte[] payload = record.getPayload();
//Declares the Magic Number that should be matched inside the payload
byte[] gifMagicNumber = {0x47, 0x49, 0x46, 0x38, 0x39, 0x61}; // GIF89a
//Checks the Payload for the Magic Number
for (int i = 0; i < gifMagicNumber.length; i++) {
if (payload[i] != gifMagicNumber[i]) {
return false;
}
}
//Checks that the Payload length is, at least, the length of the Magic Number + The Descriptor
if (payload.length == 13) {
return true;
}
}
}
return false;
}
Tài nguyên
- Quyền khi bắt đầu chạy
- Hướng dẫn về khả năng kết nối
- Ví dụ
- Chuyển hàng loạt
- Mật mã học
- Thiết lập Bluetooth
- Cơ sở NFC
- Bản ghi ứng dụng Android
- Thông số kỹ thuật Bluetooth cổ điển