Android

Android Güvenliğini Paketten Çıkarma: 2. Bölüm — Güvenli Olmayan Veri Depolama | tarafından Ed Holloway-George | Haz, 2022

Fotoğraf kredisi: mak

👋 Merhaba ve Android Güvenliğini derinlemesine incelediğimiz bu dizinin ikinci gönderisine hoş geldiniz. Bu seri şu konulara odaklanıyor: En İyi 10 Mobil tarafından belirlenen güvenlik tehditleri Açık Web Uygulama Güvenliği Projesi (OWASP) Vakfıalanımızda lider uygulama güvenliği topluluğu.

Bu gönderiyi kontrol etmeden önce, lütfen sitemde mevcut olan bir önceki ‘Uygunsuz Platform Kullanımı’na göz atın ve ProAndroidDev.

⚠️ Bu serinin eğitim amaçlı olduğunu lütfen unutmayın. sadece. Yalnızca bunu yapma izniniz olan uygulamalarda test etmeyi unutmayın ve hepsinden önemlisi, kötü olma.

Son olarak, bu seriyi beğendiyseniz veya herhangi bir geri bildiriminiz varsa, lütfen bana bir mesaj bırakın. Teşekkürler!

Android Güvenliği serimin bu ikinci yardımında, OWASP tarafından belirlenen 2 numaralı mobil uygulama güvenliği tehdidine, “Güvensiz Veri Depolama”ya göz atacağız.

Veri depolama ve Android söz konusu olduğunda, hemen akla gelebilecek birkaç çözüm var.

Bu blogda, muhtemelen uygulamalarınızda kullanacağınız en yaygın üç yaklaşıma bakacağız:

  1. SharedPreferences
  2. Oda veritabanları
  3. Jetpack’ler DataStore

Uygulama geliştiricileri olarak veri depolama ihtiyacı, karşılaştığımız son derece yaygın bir senaryodur. Ancak, bunun getirdiği güvenlik endişelerini anlamak da önemlidir. Göreceğimiz gibi, kötü niyetli kişilerin cihazda depolanan verilere erişmesi ve bunları tehlikeye atması genellikle önemsizdir.

Ayrıca konuya girmeden önce şunu da belirtmekte fayda var ki, bu en iyi uygulamadır. kaçınmak her türlü hassas veriyi bir cihazda depolamak. Hassas veriler, bir kullanıcının kişisel olarak tanımlanabilir bilgilerini (PII), API anahtarlarınızı veya yanlış ellere geçmesi durumunda ‘tehlikeli’ olabilecek diğer türdeki verileri içerebilir. Her zaman, mümkün olduğunda hassas verilerin uzaktan saklanmasını ve yalnızca gerektiğinde uygulamanız tarafından erişilmesini tavsiye ederim.

Her zaman sadık arkadaşımıza bakarak bir şeyler başlatalım SharedPreferences

bu SharedPreferences API, en başından beri Android Geliştirme’nin temel unsuru olmuştur ve platformda ilk kez API 1’de yer almıştır. Geliştiriciler için verileri bir anahtar/değer çiftinde (KVP) depolamak için denenmiş ve test edilmiş hızlı bir çözümdür, ancak öyle değildir. kusurları olmadan.

Çok basit bir örneğe bakalım:

Arka planda, belirli bir tercih dosyası adı verildiğinden¹, cihazın içinde (gerekirse) bu adla bir XML dosyası oluşturulur. /data/data/{package name}/shared_prefs dosya.

Daha sonra, saklanacak tercihler toplanır ve daha sonra bir iç referans yoluyla erişilir. Map<String, Any?>² daha sonra içeriği XML dosyasına bir TypedXmlSerializerböylece KVP’leri gelecekteki okuma/yazma istekleri için kaydeder.

kullanımı yoluyla adb bir cihazda bu çıktının ne yaptığına bakalım ve görelim. hata ayıklanabilir inşa etmek:

$ adb shell

# Run as your package name
$ run-as dev.spght.example

# Show your app's local folders
$ ls
cache code_cache shared_prefs

# Show what is in the shared_prefs folder
$ ls shared_prefs
mySharedPrefFile.xml

# Print out the contents of the file
$ cat shared_prefs/mySharedPrefFile.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="mySecretKey">mySecretValue</string>
</map>

Gördüğünüz gibi, “mySecretKey” tercihi herkesin görebileceği şekilde düz metin olarak saklanır. Ancak, bunu hata ayıklanamayan bir sürüm derlemesinde denemek bir hataya neden olur package not debuggable. Yani, bu güvenli değil mi? Yanlış.

⚠️ Android Yedekleme Sömürüsü

Bu hâlâ bir cihazdaki bir üretim uygulamasının paylaşılan tercihlerine, uygulamanın ‘kötüye kullanımı’ yoluyla erişmek mümkündür. adb backup emretmek. Bu komutun amaçlanan amacı, bir cihazın veya belirli bir uygulamanın arşivinin oluşturulmasına ve daha sonra bir cihaza geri yüklenmesine izin vermektir. adb restoreAncak, yedekleme arşivinin kendisi bir tar Paylaşılan tercih XML dosyaları da dahil olmak üzere özel uygulama verilerinin içeriğini okumak için çıkarılabilen dosya.

Bunu tamamlama süreci, oldukça basittir ve olarak bilinen harici bir aracın kullanılmasıyla gerçekleşir. Android Yedekleme Çıkarıcıbu işlem bir uygulamanın gizli içeriğini son derece kolay bir şekilde verebilir.

# Make a backup file for app 
$ adb backup -noapk -f backup.ab dev.spght.example.prod
WARNING: adb backup is deprecated and may be removed in a future release
Now unlock your device and confirm the backup operation...

# Use ABE to unpack the backup file (12345 is the password as set through the device)
$ java -jar abe.jar unpack backup.ab output.tar 12345
Calculated MK checksum (use UTF-8: true): 739E00581D0B3EB5A17F3E1A43D21F561BA8E8C1CA35C48E636495E9C57EF0A1
31% 63% 67%
4096 bytes written to output.tar.

# Extract the unpacked backup
$ tar xvf output.tar
x apps/dev.spght.example.prod/_manifest
x apps/dev.spght.example.prod/sp/example.xml

# View the extracted shared preference file
$ cat apps/dev.spght.example.prod/sp/example.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="mySecretKey">mySecretValue</string>
</map>

işte! Hata ayıklanamayan bir uygulamanın tercihlerinin içeriğini okuduk.

Bu yöntemin yalnızca aşağıdaki uygulamalardan yararlanmak için kullanılabildiğine dikkat edilmelidir. yapma açıkça ayarlanmış android:allowBackup="false" onların manifest dosyası içinde. Uygulamanızın bir cihaz yükseltmesi sırasında herhangi bir yedekleme yapması gerekmiyorsa, bu olası tehlikeyi önlemek için bildiriminizde bu seçeneği ayarlamanız önemle tavsiye edilir.

Ek olarak, Google kısa süre önce bu güvenlik açığını kabul etti ve Android 12’den beri aşağıdaki kısıtlamaları uyguladı:

Özel uygulama verilerinin korunmasına yardımcı olmak için Android 12, uygulamanın varsayılan davranışını değiştirir. adb backup emretmek. Android 12 (API düzeyi 31) veya sonraki sürümleri hedefleyen uygulamalar için, bir kullanıcı adb backup komutu, uygulama verileri, cihazdan dışa aktarılan diğer sistem verilerinden hariç tutulur.

Bu çok iyi bir haber. Basitçe bir SDK’nın hedeflenmesi yoluyla, hata ayıklanamayan uygulamalarınız, tercihlerinizi gözetleyen hemen hemen herkesten iyi korunmalıdır. Ancak, bunu daha da ileri götürebilir miyiz?

Paylaşılan Tercihleri ​​Şifreleme

Şu ana kadar PII veya diğer hassas verileri depolamanın tehlikelerini şu ana kadar görebileceğinizi umuyorum. SharedPreferences. Ancak, uygulamanız 31+ API seviyesini hedeflemeyip bir yedekleme stratejisi gerektiriyorsa veya mobil uygulamanızın güvenliği konusunda (haklı olarak) endişe duyuyorsanız, şifrelemek isteyebilirsiniz. hiç verilerin kolayca okunamamasını sağlamak için paylaşılan tercihleriniz içinde kaydettiğiniz veriler.

Bu öyle bir şey değil SharedPreferences kutunun dışında, ama neyse ki Jetpack Güvenliği (JetSec olarak bilinir) bu işlevi, androidx.security:security-crypto geliştiricilere erişim sağlayan bir kitaplık EncryptedSharedPreferences var olanı saran sınıf SharedPreferences API.

Not: Kararlı 1.0.0 sürümü androidx.security:security-crypto API 23+’ı destekler, API 21’e bir arka bağlantı noktası yaklaşan 1.1.0 sürümünün bir parçasıdır ve şu anda erken alfa sürümlerinde³ mevcuttur.

Paylaşılan tercihleri ​​güvence altına almak için JetSec kullanmanın temel bir örneği burada görülebilir

incelemenizi şiddetle tavsiye ederim Google blog gönderisi bu, kitaplığın kendi uygulamanızın güvenlik ihtiyaçları için nasıl kullanılabileceği ve yapılandırılabileceği konusunda daha fazla ayrıntıya girer. Özellikle, JetSec ekibi tarafından vurgulanan ve kriptografik işlemlerin özel bir donanım güvenlik modülünde gerçekleştirilmesini zorlamak veya tercihlere erişilmeden önce kullanıcı kimlik doğrulamasını gerektirmek dahil olmak üzere ekstra güvenlik katmanlarına olanak tanıyan yöntemleri not etmeye değer.

Önemli seçenekler:

userAuthenticationRequired() ve userAuthenticationValiditySeconds() zamana bağlı bir anahtar oluşturmak için kullanılabilir. Zamana bağlı anahtarlar kullanarak yetkilendirme gerektirir BiometricPrompt simetrik anahtarların hem şifrelenmesi hem de şifresinin çözülmesi için.

unlockedDeviceRequired() cihazın kilidi açık değilse anahtar erişiminin gerçekleşmemesini sağlamaya yardımcı olan bir bayrak ayarlar. Bu bayrak Android Pie ve sonraki sürümlerde mevcuttur.

Kullanmak setIsStrongBoxBacked(), kripto işlemlerini daha güçlü ayrı bir çip üzerinde çalıştırmak için. Bunun performans üzerinde hafif bir etkisi vardır, ancak daha güvenlidir. Android Pie veya sonraki sürümleri çalıştıran bazı cihazlarda kullanılabilir.

Ama bu aslında perde arkasında nasıl çalışıyor? JetSec tarafından kullanılan şifreleme, Google’ın tink kütüphanesi, endüstri lideri kripto algoritmaları sağlayan ve geliştiricilerin kriptografi gerçekleştirirken en iyi uygulamaları takip etmelerine yardımcı olan açık kaynaklı bir projedir. Olarak EncryptedSharedPreferences sadece bir uygulamasıdır SharedPreferencesTink’i dahili olarak kullanabilir ve tercihleri ​​işlerken Tink’in işlevselliğini sağlayabilir.

JetSec kullanarak XML çıktısına bir göz atalım

✨ Çok daha iyi!

Şimdi, büyük miktarda yapılandırılmış veriyi depolamak için Android ekosisteminde popüler bir seçim olan Room veritabanlarına bakalım. Room, SQLite veritabanı motoru üzerinde bir soyutlama katmanıdır ve geliştiricilerin kolayca tablolar oluşturmasına, sorgular yazmasına ve veritabanları için standart CRUD işlemlerini otomatik olarak sihirli bir şekilde ele almasına olanak tanır.

Oda belgelerinin temel kurulumunu kullanma örnekbir üretim uygulamasının çok basit bir veritabanı oluşturduğunu varsayalım: insecure-database kullanıcı kimliği, adı ve soyadı gibi kullanıcı verilerini içeren. Elbette, yanlışlıkla paylaşmak istemeyeceğiniz bir şey.

Paylaşılan tercihlerle daha önce keşfettiğimiz gibi, Android yedekleme işlemi, özel uygulama verilerini çıkarmak için bir kez daha kullanılabilir. Daha önce kullandığımız işlemin aynısını takiben, bir uygulamanın Room SQLite veritabanları şurada bulunabilir: {package name}/db.

kullanma sqlite3 komut satırında veritabanını inceleyebilir, tabloları listeleyebilir ve içindekileri içeren tablo verilerini gösterebiliriz.

$ sqlite3 insecure-database

sqlite> .tables
User android_metadata room_master_table

sqlite> .schema User
CREATE TABLE `User` (`uid` INTEGER NOT NULL, `first_name` TEXT, `last_name` TEXT, PRIMARY KEY(`uid`));

sqlite> SELECT * FROM User LIMIT 5;
1653992407422|First|Last
1653992407614|First|Last
1653992407658|First|Last
1653992407685|First|Last
1653992407686|First|Last

Bir uygulama herhangi bir hassas veriyi uygun şifreleme olmadan bir veritabanında depoluyorsa, (tıpkı paylaşılan tercihler gibi) düz metin olarak incelenebilir. Boo 👎

Şifreleme Odası

Peki, bunu nasıl düzeltebiliriz? Neyse ki tanınmış (ve güvenilir) SQLCipher projesi sağlar Android Kitaplığı veritabanı dosyalarının şeffaf 256-bit AES şifrelemesini desteklemek için.

Bu, aracılığıyla bir bağımlılık olarak eklenebilir net.zetetic:android-database-sqlcipher:{latest version}. Ancak, Room örneğinizi oluştururken SQLCipher kullanmak için, oluşturucuya SQLCipher’ın SupportSQLiteOpenHelper.Factoryuygun şekilde adlandırılmış SupportFactory.

Sahne arkasında, başlatma sırasında SQLCipher, bir benzersiz veritabanı dosyasının AES şifreleme/şifre çözme anahtarı. Bu, SQLCipher içinde daha ayrıntılı olarak açıklanmaktadır. dokümanlar ve aşağıda yorumlanmıştır.

Bir parola ile başlatıldığında SQLCipher, PBKDF2-HMAC-SHA512 kullanarak anahtar verileri türetir. Her veritabanı, dosyanın ilk 16 baytında benzersiz bir rastgele tuz ile başlatılır. Bu tuz, anahtar türetme için kullanılır ve aynı parola kullanılarak iki veritabanı oluşturulsa bile, aynı şifreleme anahtarına sahip olmamalarını sağlar. Varsayılan yapılandırma, anahtar türetme için 256.000 yineleme kullanır.

Bunun beklendiği gibi çalıştığını doğrulamak için yükleyebiliriz sqlcipher⁴ ve güvenli veritabanını açın. kullanma PRAGMA key kodunuzda sağlanan aynı parolayla, veritabanının şifresini çözmek ve içeriği bir kez daha düz metin olarak okumak mümkündür.

$ sqlcipher secure-database

sqlite> .tables
Error: file is not a database

sqlite> PRAGMA key = 'password';
ok

sqlite> .tables
User room_master_table

sqlite> SELECT * FROM User LIMIT 5;
1653992407422|First|Last
1653992407614|First|Last
1653992407658|First|Last
1653992407685|First|Last
1653992407686|First|Last

işte. Bir kez daha, verilerimizi minimum geliştirme çabasıyla güvenli bir şekilde sakladığımızı görüyoruz!

Son olarak, bakalım Bilgi deposu Android ekosisteminde veri depolamanın görece yeni üyesi. Tercihlerin eşzamansız olarak okunmasını veya yazılmasını sağlamak için Kotlin’deki ilk yaklaşımı ve eşyordamların kullanımı, onu modern Android geliştirme için çekici bir seçenek haline getiriyor. Bununla birlikte, bir kez daha, aracılığıyla okunmaya karşı potansiyel olarak savunmasızdır. adb backup yöntem 😬

Başka bir basit örnek alalım

Yedekleme yöntemini kullanarak, ayıklandıktan sonra verilerimizi içinde buluruz. datastore/insecure-data-store.preferences_pb. Bu dosya ilk bakışta biraz tuhaf görünebilir, ancak Google’ın protobuf kitaplığını⁵ kullanarak dosyanın içeriğini inceleyebilir ve kaydedilen tercihleri ​​okuyabiliriz.

$ hexdump -C insecure-data-store.preferences_pb
00000000 0a 1d 0a 0c 65 78 61 6d 70 6c 65 5f 70 72 65 66 |....example_pref|
00000010 12 0d 2a 0b 4d 79 20 31 73 74 20 50 72 65 66 0a |..*.My 1st Pref.|
00000020 1f 0a 0e 65 78 61 6d 70 6c 65 5f 70 72 65 66 5f |...example_pref_|
00000030 32 12 0d 2a 0b 4d 79 20 32 6e 64 20 50 72 65 66 |2..*.My 2nd Pref|
00000040

$ protoc --decode_raw < insecure-data-store.preferences_pb
1 {
1: "example_pref"
2 {
5: "My 1st Pref"
}
}
1 {
1: "example_pref_2"
2 {
5: "My 2nd Pref"
}
}

😅 Yani bu noktada daha ne bekliyorduk ki!

DataStore’u Şifreleme

Yazma tarihi itibariyle elimizde hiçbir resmi destek DataStore veya JetSec kitaplığından şifreleme için, ancak beklememiz uzun sürmeyebilir 👀

Bu arada, açık kaynaklı bir çözüm var şifreli veri deposuDataStore’u saran ve Google’ın tink kütüphanesi JetSec’inkine benzer şekilde EncryptedSharedPreferences. Ancak, bu kitaplık iyi bilinen bir güvenilir kuruluş tarafından değil, bir kişi tarafından korunduğundan, lütfen bunu projelerinizde yalnızca son derece dikkatli kullanın.

Umarız çok yakında resmi bir çözüm görürüz!

Bu serideki sonraki gönderilerde, Mobil için OWASP Top 10 hakkında daha fazlasını keşfedeceğiz. Sıradaki #3 Güvensiz İletişim.

Her zamanki gibi okuduğunuz için teşekkürler! Umarım bu gönderiyi ilginç bulmuşsunuzdur, lütfen herhangi bir geri bildirim ile bana tweet atmaktan çekinmeyin. @Sp4ghettiKodu ve alkışlamayı, beğenmeyi, tweet atmayı, paylaşmayı, yıldız atmayı vb. unutmayın.

Daha fazla okuma

Dipnotlar

[1] bu getPreferences(int mode) içindeki yöntem Activity varsayılan olarak dosya adı olarak aktivitenin adını kullanır

[2] uygulanması SharedPreferences Java’da, yani Map<String, Object> gerçek yazım mı

[3] gibi göründüğünü belirtmekte fayda var. androidx.security:security-crypto-ktx:1.1.0-alpha03 API 21’in minimum sürümünü doğru şekilde desteklemiyor ve API 23+ sürümünde kalıyor – Bunun için bir hata raporu oluşturdum burada

[4] kullanma brew install sqlcipher macOS’ta – diğer işletim sistemi yükleme yöntemlerini çevrimiçi olarak kontrol edin

[5] kullanma brew install protobuf macOS’ta – diğer işletim sistemi yükleme yöntemlerini çevrimiçi olarak kontrol edin

İlgili Makaleler

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.

Başa dön tuşu