Viblo Code
0

Giao tiếp an toàn với server từ ứng dụng Android với Certificate Pinning

Bảo mật và quyền riêng tư là một số nhiệm vụ khó khăn nhất đối với bất kỳ nhà phát triển Android nào và điều đó là hiển nhiên vì Android là nền tảng mã nguồn mở và mọi người đều biết cách hoạt động của nó. Trong bài viết này, chúng ta sẽ đề cập đến giao tiếp an toàn trong Android, chủ yếu giữa máy khách và máy chủ.

Giới thiệu

Hiện tại, kiến trúc phổ biến nhất của các dịch vụ web là REST dựa trên HTTP. Phương pháp bảo vệ tốt nhất cho mô hình giao tiếp này là tiêu chuẩn TLS / SSL. Nó có thể được kết hợp với giao thức HTTP để tạo ra một biến thể được mã hóa gọi là HTTPS. HTTPS đảm bảo giao tiếp an toàn, được mã hóa giữa ứng dụng và máy chủ.

Vấn đề

Các nhà phát triển thường triển khai các cuộc gọi mạng qua HTTPS, nhưng không đúng cách. Điều này có thể được giải quyết bằng cách thay thế tên giao thức từ HTTP thành HTTPS trong URL. Điều này sẽ cung cấp bảo mật ở một mức độ nhất định bằng cách bật mã hóa TLS / SSL theo mặc định (chỉ khi máy chủ hỗ trợ). Tuy nhiên, điều này không đủ tốt để giữ an toàn cho dữ liệu của bạn. Chỉ cần thay thế giao thức sẽ cho phép mã hóa, nhưng ứng dụng sẽ tin cậy mọi chứng chỉ do máy chủ cấp. Điều này có nghĩa là hacker có thể tạo chứng chỉ giả. Sau đó, các chứng chỉ sẽ cho phép tin tặc đánh chặn thông tin liên lạc được mã hóa, được gọi là một cuộc tấn công man-in-the-middle. Đó là lý do chính tại sao bạn nên dành nhiều thời gian và nỗ lực hơn để triển khai cấu hình HTTPS một cách chính xác.

Giải pháp

Để tránh mối đe dọa này, chúng ta nên thực hiện ghim chứng chỉ. Để làm điều này, chúng tôi cần một chứng chỉ máy chủ có fingerprint. Chúng tôi sẽ so sánh chứng chỉ máy chủ từ xa với dấu vân tay trong khi thực hiện kết nối. Nếu chúng giống hệt nhau thì đó là một kết nối an toàn, nếu không, bạn không nên chuyển dữ liệu vì kết nối bị xâm phạm. Có ba cách để triển khai ghim chứng chỉ trong Android:

  1. Network security configuration.
  2. TrustManager.
  3. OkHttp and certificate pinning.

Network Security Configuration

Đây là một trong những cách dễ nhất và là cách nguyên bản để thực hiện certificate pinning trong Android. Không giống như hai phương pháp còn lại, cấu hình này không yêu cầu mã hóa nhưng cấu hình bảo mật mạng có một lỗ hổng: nó chỉ hỗ trợ Android N trở lên. Tính năng cấu hình bảo mật mạng cho phép các ứng dụng tùy chỉnh cài đặt bảo mật mạng của chúng trong một tệp cấu hình khai báo, an toàn mà không cần sửa đổi mã ứng dụng. Các cài đặt này có thể được định cấu hình cho các domain cụ thể và một ứng dụng cụ thể. Cấu hình bảo mật mạng sử dụng tệp XML phải được tạo trong thư mục res/xml và chúng tôi cần khai báo tệp XML này trong manifest như được hiển thị bên dưới:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application       
android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>

Giờ chúng ta đã biết cách tạo tệp bảo mật mạng, đã đến lúc định cấu hình tệp đó. Ở đây, chúng ta có hai thẻ chính, <base-config> và <domain-config>. <base-config> được sử dụng để khai báo những thứ hoặc cấu hình sẽ được áp dụng cho toàn bộ ứng dụng, bất kể miền nào giữ kết nối. Mặt khác, <domain-config> được sử dụng để định cấu hình các quy tắc cụ thể cho chỉ một số miền nhất định mà bạn chọn. Hãy xem:

 <?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config  cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
  
   <domain-config>
        <domain includeSubdomains="true">secure.example.com</domain>
        <trust-anchors>
            <certificates src="@raw/crtf"/>
        </trust-anchors>
   </domain-config>
</network-security-config>

Ở đây, chúng ta đã sử dụng thẻ <base-config> để vô hiệu hóa lưu lượng văn bản rõ ràng, có nghĩa là chỉ các cuộc gọi dịch vụ HTTPS sẽ xảy ra trong toàn bộ ứng dụng và cũng đề cập đến việc sử dụng chứng chỉ hệ thống cho mạng. Tuy nhiên, đến với <domain-config>, chúng tôi đã đề cập đến một miền cụ thể và định cấu hình các quy tắc nhất định cho nó, chẳng hạn như chỉ sử dụng tệp chứng chỉ trong thư mục res / raw để tạo kết nối mạng với “secure.example.com” miền. Giờ chúng ta đã biết cách sử dụng chứng chỉ, đã đến lúc chúng ta sử dụng tính năng ghim chứng chỉ. Ở đây, chúng tôi sử dụng thẻ

để định cấu hình chứng chỉ với một mã pin cụ thể như hình bên dưới.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">sampleexample.com</domain>
        <pin-set expiration="2018-01-01">
            <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
            <!-- backup pin -->
            <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

TrustManager

Đây là một trong những phương pháp lâu đời nhất để triển khai ghim chứng chỉ trong Android. TrustManager chịu trách nhiệm quyết định xem ứng dụng có nên cho phép thông tin xác thực do server cung cấp hay không. Kỹ thuật này là từ gói javax.net.ssl và chúng tôi đã sử dụng nó ở đây để triển khai certificate pinning.

Bước 1

Thêm tệp chứng chỉ của bạn trong thư mục res / raw. Sẽ tốt hơn nếu chứng chỉ ở định dạng PEM hoặc DER mà không có bất kỳ dòng chú thích nào trong đó.

Bước 2

Khởi tạo KeyStore với chứng chỉ như hình dưới đây:

val resource_stream = resources.openRawResource(R.raw.cert)
val key_store_type = KeyStore.getDefaultType()
val key_store = KeyStore.getInstance(key_store_type)

key_store.load(resource_stream, null)

Bước 3

Bây giờ chúng ta đã có phiên bản chứng chỉ, đã đến lúc khởi tạo TrustManager.

val trust_manager_algorithm = TrustManagerFactory.getDefaultAlgorithm()
val trust_manager_factory = TrustManagerFactory.getInstance(trust_manager_algorithm)

trust_manager_factory.init(keyStore)

Tạo phiên bản TrustManager

Bước 4 Bây giờ chúng ta đã có chứng chỉ và các phiên bản trình quản lý tin cậy, hãy hoàn thành bước cuối cùng bằng cách tạo ngữ cảnh SSL với giao thức TLS và sau đó tạo kết nối SSL an toàn với TrustManager.

val ssl_context = SSLContext.getInstance("TLS")
ssl_context.init(null, trust_manager_factory.trustManagers, null)
val url = URL("http://www.secureexample.com/")
val url_connection = url.openConnection() as HttpsURLConnection
url_connection.sslSocketFactory = ssl_context.socketFactory

OkHttp and Certificate Pinning

OkHttp là một thư viện mạng rất nổi tiếng của Square. Retrofit sử dụng OkHttp để kết nối mạng. Nhóm Okhttp đã làm cho việc thực hiện ghim chứng chỉ rất đơn giản. Đầu tiên, chúng ta cần tạo một phiên bản trình ghim chứng chỉ từ trình tạo OkHttp CertificatePinner chuyên dụng và sau đó chúng tôi thêm miền và tệp tham chiếu tương ứng vào nó. Cuối cùng, thêm trình tạo vào máy khách OkHttp. Hãy xem:

val certificatePinner = CertificatePinner.Builder()
       .add(
               "www.secureexample.com",
               "sha256/7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y="
       ).build()

val okHttpClient = OkHttpClient.Builder()
       .certificatePinner(certificatePinner)
       .build()

Chúng ta cũng có thể thêm nhiều dấu vân tay vào builder. Điều này sẽ hữu ích để thêm dấu vân tay bổ sung nếu dấu vân tay hiện tại sắp hết hạn. Chúng tôi cũng có thể nhập các tệp chứng chỉ vào thư mục tài nguyên, như được hiển thị trong trường hợp TrustManager. Bây giờ, bạn cần viết thủ công một lớp sẽ trích xuất dấu vân tay từ tệp. Bạn cũng có thể sử dụng Peer certificate extractor để trích xuất dấu vân tay. Bạn chắc chắn không nên để fingerprints tĩnh trong code. Đặt chúng trong tệp Gradle dưới dạng build-config field.

Sơ lược về chứng chỉ

Có gần 138 cơ quan cấp chứng chỉ được hệ sinh thái Android chấp nhận và số lượng tăng lên mỗi ngày. Bạn có thể thêm chứng chỉ tự ký, lá, trung cấp hoặc gốc của mình. Hãy để tôi giải thích thêm một chút về các chứng chỉ này để bạn có thể hiểu rõ chúng là gì.

Leaf Certificate

Bằng cách sử dụng Leaf Certificate, bạn đang đảm bảo 100% rằng đây chính xác là chứng chỉ của bạn và bạn đang thiết lập một kết nối an toàn. Chứng chỉ lá có thời gian hết hạn rất ngắn, vì vậy bạn cần đẩy bản cập nhật cho ứng dụng của mình để đảm bảo kết nối. Chúng tôi rất khuyến khích sử dụng các khóa dự phòng.

Intermediate Certificate

Bằng cách sử dụng chứng chỉ trung gian, bạn phụ thuộc vào tổ chức phát hành chứng chỉ trung gian. Phương pháp này có một lợi thế. Miễn là bạn gắn bó với cùng một nhà cung cấp chứng chỉ, thì mọi thay đổi đối với Leaf Certificate của bạn sẽ hoạt động mà không cần phải cập nhật ứng dụng của bạn. Việc sử dụng chứng chỉ trung gian chỉ an toàn khi nhà cung cấp của bạn đáng tin cậy.

Root Certificate

Bằng cách sử dụng chứng chỉ gốc, bạn phụ thuộc vào tất cả các chứng chỉ trung gian đã được tổ chức phát hành chứng chỉ gốc phê duyệt. Nếu bất kỳ chứng chỉ trung gian nào bị xâm phạm thì có khả năng ứng dụng của bạn bị tin tặc bẻ khóa.


All Rights Reserved