Codelab Konfigurasi Keamanan Jaringan Android

1. Pengantar

Sangat umum bagi aplikasi untuk bertukar data melalui internet. Karena aplikasi Anda mungkin berkomunikasi dengan server selain yang dipercaya, Anda perlu berhati-hati saat mengirim dan menerima informasi yang dapat bersifat sensitif dan pribadi.

Yang akan Anda buat

Dalam codelab ini, Anda akan membuat aplikasi yang menampilkan pesan. Setiap pesan akan berisi nama pengirim, pesan teks, dan URL ke "foto profil" mereka. Aplikasi ini akan menampilkan pesan tersebut dengan melakukan hal berikut:

  • Memuat file JSON yang berisi daftar pesan teks dari jaringan.
  • Memuat setiap foto profil dan menampilkannya di samping pesan yang sesuai.

Yang akan Anda pelajari

  • Pentingnya komunikasi jaringan yang aman.
  • Cara menggunakan library Volley untuk membuat permintaan jaringan.
  • Cara menggunakan Konfigurasi Keamanan Jaringan untuk membantu komunikasi jaringan menjadi lebih aman.
  • Cara mengubah beberapa opsi Konfigurasi Keamanan Jaringan lanjutan yang akan berguna selama pengembangan dan pengujian.
  • Menjelajahi salah satu masalah keamanan jaringan yang paling umum dan melihat bagaimana Konfigurasi Keamanan Jaringan dapat membantu mencegahnya.

Yang akan Anda butuhkan

  • Versi terbaru Android Studio
  • Perangkat Android atau emulator yang menjalankan Android 7.0 (API level 24) atau yang lebih tinggi
  • Node.js (atau akses ke server web yang dapat dikonfigurasi)

Jika Anda mengalami masalah (bug kode, kesalahan gramatikal, susunan kata yang tidak jelas, dll.) saat mengerjakan codelab ini, laporkan masalah tersebut melalui link Laporkan kesalahan di pojok kiri bawah codelab.

2. Mempersiapkan

Download Kode

Klik link berikut untuk mendownload semua kode untuk codelab ini:

Ekstrak file ZIP yang didownload. Tindakan ini akan mengekstrak folder root (android-network-secure-config), yang berisi project Android Studio (SecureConfig/) dan beberapa file data yang akan kita gunakan di tahap berikutnya (server/).

Anda juga dapat melihat kode langsung dari GitHub: (Mulai dengan cabang master.)

Kami juga telah menyiapkan cabang dengan kode akhir setelah masing-masing langkah. Jika Anda mengalami masalah, lihat cabang di GitHub, atau clone seluruh repositori: https://github.com/android/codelab-android-network-security-config/branches/all

3. Menjalankan aplikasi

Setelah mengklik ikon "muat", aplikasi ini akan mengakses server jarak jauh untuk memuat daftar pesan, nama, dan URL ke foto profilnya dari file JSON. Selanjutnya, pesan ditampilkan dalam daftar, dan aplikasi memuat gambar dari URL yang direferensikan.

Catatan: Aplikasi yang kita gunakan dalam codelab ini hanya untuk tujuan demo. Hal ini tidak mencakup penanganan error sebanyak yang Anda perlukan di lingkungan produksi.

d9e465c94b420ea1.png

Arsitektur Aplikasi

Aplikasi mengikuti pola MVP, memisahkan penyimpanan data dan akses jaringan (model) dari logika (presenter) dan tampilan (view).

Class MainContract berisi kontrak yang menjelaskan antarmuka antara View dan Presenter:

MainContract.java

/*
 * Copyright 2017 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.networksecurity;

import com.example.networksecurity.model.Post;

/**
 * Contract defining the interface between the View and Presenter.
 */
public interface MainContract {

    interface View {
        /**
         * Sets the presenter for interaction from the View.
         *
         * @param presenter
         */
        void setPresenter(Presenter presenter);

        /**
         * Displays or hides a loading indicator.
         *
         * @param isLoading If true, display a loading indicator, hide it otherwise.
         */
        void setLoadingPosts(boolean isLoading);

        /**
         * Displays a list of posts on screen.
         *
         * @param posts The posts to display. If null or empty, the list should not be shown.
         */
        void setPosts(Post[] posts);

        /**
         * Displays an error message on screen and optionally prints out the error to logcat.
         */
        void showError(String title, String error);

        /**
         * Hides the error message.
         *
         * @see #showError(String, String)
         */
        void hideError();

        /**
         * Displays an empty message and icon.
         *
         * @param showMessage If true, the message is show. If false, the message is hidden
         */
        void showNoPostsMessage(boolean showMessage);
    }

    interface Presenter {
        /**
         * Call to start the application. Sets up initial state.
         */
        void start();

        /**
         * Loads post for display.
         */
        void loadPosts();

        /**
         * An error was encountered during the loading of profile images.
         */
        void onLoadPostImageError(String error, Exception e);
    }

}

Konfigurasi Aplikasi

Untuk tujuan demonstrasi, semua cache jaringan aplikasi ini telah dinonaktifkan. Idealnya, di lingkungan produksi, aplikasi akan menggunakan cache lokal untuk membatasi jumlah permintaan jaringan jarak jauh.

File gradle.properties berisi URL tempat daftar pesan dimuat:

gradle.properties

postsUrl="http://storage.googleapis.com/network-security-conf-codelab.appspot.com/v1/posts.json"

Mem-build dan menjalankan aplikasi

  1. Mulai Android Studio dan buka direktori SecureConfig sebagai project Android.
  2. Klik "jalankan" untuk memulai aplikasi: e15973f44eed7cc2.png

Screenshot dari aplikasi berikut menunjukkan tampilannya di perangkat:

63300e7e262bd161.png

4. Konfigurasi Keamanan Jaringan Dasar

Pada langkah ini, kita akan menyiapkan konfigurasi keamanan jaringan dasar dan mengamati error yang terjadi jika salah satu aturan dalam konfigurasi dilanggar.

Ringkasan

Konfigurasi Keamanan Jaringan memungkinkan aplikasi menyesuaikan setelan keamanan jaringan mereka melalui file konfigurasi deklaratif. Seluruh konfigurasi ada di dalam file XML ini, dan tidak perlu mengubah kode.

Hal ini memungkinkan untuk konfigurasi berikut:

  • Memilih tidak menggunakan traffic cleartext: Menonaktifkan traffic cleartext.
  • Trust anchor khusus: Menentukan Certificate Authority dan sumber yang dipercaya aplikasi.
  • Penggantian khusus debug: Melakukan debug koneksi aman dengan aman tanpa memengaruhi build rilis.
  • Penyematan sertifikat: Membatasi koneksi aman ke sertifikat tertentu.

File ini dapat diatur menurut domain, sehingga setelan keamanan jaringan dapat diterapkan ke semua URL atau hanya untuk domain tertentu.

Konfigurasi Keamanan Jaringan tersedia di Android 7.0 (API level 24) dan yang lebih tinggi.

Membuat file XML Konfigurasi Keamanan Jaringan

Buat file resource xml yang baru dengan nama network_security_config.xml.

Di Android Project Panel di sisi kiri, klik kanan pada res, lalu pilih New > Android resource file.

35db6786b96a6980.png

Tetapkan opsi berikut dan klik OK.

Nama file

network_security_config.xml

Jenis resource

XML

Elemen root

network-security-config

Nama direktori

xml

36ae9e950fe66f1c.png

Buka file xml/network_security_config.xml (jika tidak otomatis terbuka).

Ganti kontennya dengan cuplikan berikut:

res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false" >
    </base-config>
</network-security-config>

Konfigurasi ini berlaku untuk konfigurasi dasar, atau konfigurasi keamanan default aplikasi, serta menonaktifkan semua traffic cleartext.

Mengaktifkan Konfigurasi Keamanan Jaringan

Selanjutnya, tambahkan referensi ke konfigurasi aplikasi di file AndroidManifest.xml.

Buka file AndroidManifest.xml dan temukan elemen application di dalamnya.

Pertama, hapus baris yang menetapkan properti android:usesCleartextTraffic="true".

Selanjutnya, tambahkan properti android:networkSecurityConfig ke elemen application di AndroidManifest, dengan merujuk pada resource file XML network_security_config: @xml/network_security_config

Setelah menghapus dan menambahkan dua properti di atas, tag aplikasi pembuka seharusnya terlihat seperti berikut:

AndroidManifest.xml

<application
    android:networkSecurityConfig="@xml/network_security_config"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    android:fullBackupContent="false"
    tools:ignore="GoogleAppIndexingWarning">
    ...

Mengompilasi dan menjalankan aplikasi

Mengompilasi dan menjalankan aplikasi.

Anda akan melihat error - aplikasi ini mencoba memuat data melalui koneksi cleartext!

98d8a173d5293742.png

Dalam logcat, Anda akan melihat error ini:

java.io.IOException: Cleartext HTTP traffic to storage.googleapis.com not permitted

Aplikasi tidak memuat data karena masih dikonfigurasi untuk memuat daftar pesan dari koneksi HTTP yang tidak dienkripsi. URL yang dikonfigurasi di file gradle.properties mengarah ke server HTTP yang tidak menggunakan TLS!

Mari kita ubah URL ini untuk menggunakan server lain dan memuat data melalui koneksi HTTPS yang aman.

Ubah file gradle.properties seperti berikut:

gradle.properties

postsUrl="https://storage.googleapis.com/network-security-conf-codelab.appspot.com/v1/posts.json"

(Perhatikan protokol http s di URL.)

Anda mungkin perlu membuat ulang project agar perubahan ini dapat dipilih. Dari menu, pilih Build > Rebuild.

Jalankan kembali aplikasi. Anda akan melihat pemuatan data sekarang karena permintaan jaringan menggunakan koneksi HTTPS:

63300e7e262bd161.png

5. Masalah Umum: Update sisi server

Konfigurasi Keamanan Jaringan dapat melindungi dari kerentanan saat aplikasi membuat permintaan melalui koneksi yang tidak aman.

Masalah umum lainnya yang Konfigurasi Keamanan Jaringan tangani adalah perubahan sisi server yang memengaruhi URL yang dimuat ke aplikasi Android. Misalnya, di aplikasi kita, bayangkan bahwa server mulai menampilkan URL HTTP yang tidak aman untuk foto profil, bukan URL HTTPS yang aman. Konfigurasi Keamanan Jaringan yang menerapkan koneksi HTTPS kemudian akan memunculkan pengecualian karena persyaratan ini tidak akan terpenuhi pada runtime.

Mengupdate backend aplikasi

Seperti yang mungkin telah Anda ketahui, aplikasi ini terlebih dahulu memuat daftar pesan, masing-masing merujuk URL ke foto profil.

Bayangkan ada perubahan pada data yang digunakan aplikasi, sehingga aplikasi meminta URL gambar yang berbeda. Mari kita simulasikan perubahan ini dengan memodifikasi URL data backend.

Ubah file gradle.properties seperti berikut:

gradle.properties

postsUrl="https://storage.googleapis.com/network-security-conf-codelab.appspot.com/v2/posts.json"

(Perhatikan "v2" pada jalur!)

Anda mungkin perlu membuat ulang project agar perubahan ini dapat dipilih. Dari menu, pilih Build > Rebuild.

Anda dapat mengakses backend "baru" dari browser untuk melihat file JSON yang dimodifikasi. Perhatikan bagaimana semua URL yang direferensikan menggunakan HTTP, bukan HTTPS.

Menjalankan aplikasi dan memeriksa error

Mengompilasi dan menjalankan aplikasi.

Aplikasi memuat pesan, namun gambar tidak dimuat. Periksa pesan error di aplikasi dan di logcat untuk melihat penyebabnya:

a2a98a842e99168d.png

java.io.IOException: Cleartext HTTP traffic to storage.googleapis.com not permitted

Aplikasi masih menggunakan HTTPS untuk mengakses file JSON. Namun, link ke foto profil dalam file JSON menggunakan alamat HTTP, sehingga aplikasi mencoba memuat gambar melalui HTTP (tidak aman).

Melindungi data

Konfigurasi Keamanan Jaringan berhasil mencegah paparan data yang tidak disengaja. Dibandingkan mencoba mengakses data yang tidak aman, aplikasi akan memblokir upaya koneksi.

Bayangkan skenario seperti ini, saat perubahan pada backend tidak cukup diuji sebelum peluncuran. Menerapkan Konfigurasi Keamanan Jaringan ke aplikasi Android dapat menyebabkan terjadinya masalah yang serupa, bahkan setelah rilis aplikasi.

Mengubah backend untuk memperbaiki aplikasi

Ubah URL backend ke versi baru yang telah "diperbaiki". Contoh ini menyimulasikan perbaikan dengan mereferensikan foto profil menggunakan URL HTTPS yang benar.

Ubah URL backend di file gradle.properties dan memuat ulang project:

gradle.properties

postsUrl="https://storage.googleapis.com/network-security-conf-codelab.appspot.com/v3/posts.json"

(Perhatikan v3 pada jalur!)

Jalankan kembali aplikasi. Ini berfungsi sebagaimana mestinya:

63300e7e262bd161.png

6. Konfigurasi khusus domain

Sejauh ini, kita telah menentukan konfigurasi keamanan jaringan di base-config, yang menerapkan konfigurasi ke semua koneksi yang coba dibuat oleh aplikasi.

Anda dapat mengganti konfigurasi ini untuk tujuan tertentu dengan menetapkan elemen domain-config. domain-config mendeklarasikan opsi konfigurasi untuk kumpulan domain tertentu.

Mari update konfigurasi keamanan jaringan di aplikasi kita ke kode berikut:

res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false" />
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">localhost</domain>
    </domain-config>
</network-security-config>

Konfigurasi ini menerapkan base-config ke semua domain, kecuali untuk domain "localhost" dan subdomainnya, tempat diterapkannya konfigurasi yang berbeda.

Di sini, konfigurasi dasar mencegah traffic cleartext untuk semua domain. Tetapi, konfigurasi domain akan mengganti aturan tersebut, memungkinkan aplikasi mengakses localhost menggunakan cleartext.

Menguji menggunakan server HTTP lokal

Setelah aplikasi dapat mengakses localhost menggunakan cleartext, mari kita mulai server web lokal dan uji protokol akses ini.

Ada berbagai alat yang dapat digunakan untuk menghosting server web yang sangat dasar, termasuk Node.JS, Python, dan Perl. Dalam codelab ini, kita akan menggunakan modul Node.JS http-server untuk menyalurkan data untuk aplikasi kita.

  1. Buka terminal dan instal http-server:
npm install http-server -g
  1. Buka direktori tempat Anda memeriksa kode, lalu buka direktori server/:
cd server/
  1. Mulai server web dan salurkan file yang berada di data/direktori:
http-server ./data -p 8080
  1. Buka browser web dan buka http://localhost:8080 untuk memastikan bahwa Anda dapat mengakses file dan melihat file "posts.json":

934e48553bcc48e7.png

  1. Selanjutnya, teruskan port 8080 dari perangkat ke komputer lokal. Jalankan perintah berikut di jendela terminal yang lain:
adb reverse tcp:8080 tcp:8080

Aplikasi Anda kini dapat mengakses "localhost:8080" dari perangkat Android.

  1. Ubah URL yang digunakan untuk memuat data di aplikasi agar mengarah ke server baru di localhost. Ubah file gradle.properties sebagai berikut: (Ingat, Anda mungkin perlu melakukan sinkronisasi project gradle setelah mengubah file ini.)

gradle.properties

postsUrl="http://localhost:8080/posts.json"
  1. Jalankan aplikasi dan verifikasi bahwa data dimuat dari komputer lokal. Anda dapat mencoba mengubah file data/posts.json dan memuat ulang aplikasi untuk mengonfirmasi bahwa konfigurasi baru berfungsi sebagaimana mestinya.

63300e7e262bd161.png

Selain - konfigurasi domain

Opsi konfigurasi yang berlaku untuk domain tertentu ditentukan di elemen domain-config. Elemen ini dapat berisi beberapa entri domain yang menentukan tempat aturan domain-config harus diterapkan. Jika beberapa elemen domain-config berisi entri domain yang serupa, Konfigurasi Keamanan Jaringan akan memilih konfigurasi yang akan diterapkan ke URL yang diberikan berdasarkan jumlah karakter yang cocok. Konfigurasi yang berisi entri domain yang cocok dengan karakter terbanyak (secara berurutan) dengan URL digunakan.

Konfigurasi domain dapat berlaku untuk beberapa domain dan mungkin juga disertai subdomain.

Contoh berikut menunjukkan Konfigurasi Keamanan Jaringan yang berisi beberapa domain. (Kami tidak mengubah aplikasi, ini hanya contoh!)

<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">secure.example.com</domain>
        <domain includeSubdomains="true">cdn.example.com</domain>
        <trust-anchors>
            <certificates src="@raw/trusted_roots"/>
        </trust-anchors>
    </domain-config>
</network-security-config>

Untuk detail selengkapnya, lihat definisi format file konfigurasi.

7. Penggantian debug

Saat mengembangkan dan menguji aplikasi yang didesain untuk membuat permintaan melalui HTTPS, Anda mungkin perlu menghubungkannya ke server web lokal atau lingkungan pengujian, seperti yang kita lakukan pada langkah sebelumnya.

Dibandingkan menambahkan penggunaan penuh untuk mengizinkan traffic cleartext untuk kasus penggunaan ini atau mengubah kode, opsi debug-override di Konfigurasi Keamanan Jaringan memungkinkan Anda menetapkan opsi keamanan yang hanya berlaku saat aplikasi berjalan dalam mode debug; yaitu, saat android:debuggable adalah true. Tindakan ini secara signifikan lebih aman dibandingkan menggunakan kode kondisional karena definisi khusus debug-nya yang eksplisit. Play Store juga mencegah aplikasi yang dapat di-debug dapat diupload, sehingga opsi ini menjadi lebih aman.

Mengaktifkan SSL di server web lokal

Sebelumnya, kita memulai server web lokal yang menyalurkan data melalui HTTP pada port 8080. Sekarang kita akan membuat sertifikat SSL yang ditandatangani sendiri dan menggunakannya untuk menyalurkan data melalui HTTPS:

  1. Buat sertifikat dengan mengubah ke direktori server/ di jendela terminal, lalu dengan menjalankan perintah berikut: (Jika Anda masih menjalankan server http, Anda dapat menghentikannya sekarang dengan menekan [CTRL] + [C].)
# Run these commands from inside the server/ directory!

# Create a certificate authority
openssl genrsa -out root-ca.privkey.pem 2048
# Sign the certificate authority
openssl req -x509 -new -nodes -days 100 -key root-ca.privkey.pem -out root-ca.cert.pem -subj "/C=US/O=Debug certificate/CN=localhost" -extensions v3_ca -config openssl_config.txt
# create DER format crt for Android
openssl x509 -outform der -in root-ca.cert.pem -out debug_certificate.crt

Tindakan ini akan menghasilkan otoritas sertifikat, menandatanganinya, dan menghasilkan sertifikat dalam format DER yang diperlukan Android.

  1. Jalankan server web dengan HTTPS, menggunakan sertifikat yang baru dibuat:
http-server ./data --ssl --cert root-ca.cert.pem --key root-ca.privkey.pem

Memperbarui URL backend

Mengubah aplikasi untuk mengakses server localhost melalui HTTPS.

Ubah file gradle.properties:

gradle.properties

postsUrl="https://localhost:8080/posts.json"

Mengompilasi dan menjalankan aplikasi.

Aplikasi akan gagal dengan error karena sertifikat server tidak valid:

3bcce1390e354724.png

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

Aplikasi tidak dapat mengakses server web karena server menggunakan sertifikat yang ditandatangani sendiri yang tidak dipercaya sebagai bagian dari sistem. Dibandingkan menonaktifkan HTTPS, kita akan menambahkan sertifikat yang ditandatangani sendiri ini untuk domain localhost pada langkah berikutnya.

Merujuk certificate authority khusus

Server web kini menyalurkan data menggunakan certificate authority (CA) yang ditandatangani sendiri yang tidak diterima oleh perangkat apa pun secara default. Jika mengakses server dari browser, Anda akan melihat peringatan keamanan: https://localhost:8080

898b69ea4fe9bc21.png

Berikutnya, kita akan menggunakan opsi debug-overrides di konfigurasi keamanan jaringan untuk mengizinkan certificate authority khusus ini hanya untuk domain localhost:

  1. Ubah file xml/network_security_config.xml sehingga berisi hal berikut:

res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false" />
    <debug-overrides>
        <trust-anchors>
            <!-- Trust a debug certificate in addition to the system certificates -->
            <certificates src="system" />
            <certificates src="@raw/debug_certificate" />
        </trust-anchors>
    </debug-overrides>
</network-security-config>

Konfigurasi ini menonaktifkan traffic jaringan cleartext dan, untuk build debug*,* mengaktifkan certificate authority yang disediakan sistem, serta file sertifikat yang disimpan di direktori res/raw.

Catatan: Konfigurasi debug secara implisit menambahkan <certificates src="system" />, sehingga aplikasi akan tetap berfungsi tanpanya. Kami telah menambahkannya untuk menunjukkan cara menambahkannya di konfigurasi lanjutan.

  1. Selanjutnya, salin file "debug_certificate.crt" dari direktori server/ ke direktori resource res/raw aplikasi di Android Studio. Anda juga dapat menarik lalu melepas file ke lokasi yang benar di Android Studio.

Anda mungkin harus membuat direktori ini terlebih dahulu jika tidak ada.

Dari server/direktori, Anda dapat menjalankan perintah berikut untuk melakukannya. Jika tidak, gunakan file manager atau Android Studio untuk membuat folder dan menyalin file ke lokasi yang benar:

mkdir  ../SecureConfig/app/src/main/res/raw/
cp debug_certificate.crt ../SecureConfig/app/src/main/res/raw/

Android Studio sekarang akan mencantumkan file debug_certificate.crt di bawah app/res/raw:

c3111ae17558e167.png

Menjalankan aplikasi

Mengompilasi dan menjalankan aplikasi. Aplikasi kini mengakses server web lokal kami melalui HTTPS menggunakan sertifikat debug yang ditandatangani sendiri.

Jika Anda mengalami error, periksa output logcat dengan cermat dan pastikan Anda telah memulai ulang http-server dengan opsi command line baru. Periksa juga apakah file debug_certificate.crt berada di lokasi yang benar (res/raw/debug_certificate.crt).

63300e7e262bd161.png

8. Pelajari Lebih Lanjut

Konfigurasi Keamanan Jaringan mendukung banyak fitur lanjutan lainnya, termasuk yang berikut:

Saat menggunakan fitur tersebut, periksa dokumentasi untuk detail tentang praktik terbaik serta batasannya.

Buat aplikasi Anda lebih aman!

Sebagai bagian dari codelab ini, Anda telah mempelajari cara menggunakan Konfigurasi Keamanan Jaringan untuk meningkatkan keamanan aplikasi Android. Pikirkan bagaimana aplikasi Anda dapat memanfaatkan fitur tersebut dan bagaimana Anda dapat memanfaatkan konfigurasi debug yang lebih stabil untuk pengujian dan pengembangan.

Pelajari Lebih Lanjut