Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Android Security 最前線
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
YANOKURO
March 10, 2017
Technology
2.5k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Android Security 最前線
AndroidNougatで追加されたSecurity関係のAPIの使い方をまとめたものです。
YANOKURO
March 10, 2017
Other Decks in Technology
See All in Technology
それでも、技術なブログを書く理由 #kichijojipm / Why I Still Write Tech Blogs Even Now
shinkufencer
0
1.4k
現場をAIで動かす「フィジカル AI」の組み込み設計の考え方【SORACOM Discovery 2026】
soracom
PRO
0
150
運用を犠牲にせずコストを制御し事業成長を支える B2B SaaS ID管理基盤におけるS3 Tableのログストレージ活用
kaminashi
1
120
AIがコードを書く時代、人間は何を保証するのか———馬場さんと考える、開発者に求められる新しい責任と価値 - TECH PLAY
netmarkjp
0
330
自己解決や回答速度を上げる、サポート業務へのAIの組み込み方【SORACOM Discovery 2026】
soracom
PRO
0
120
AI研修(Day1)【MIXI 26新卒技術研修】
mixi_engineers
PRO
2
2.9k
コンポーネント名には何を含めるべきなのか? / what-should-be-included-in-component-names
airrnot1106
0
200
セキュリティ研修【MIXI 26新卒技術研修】
mixi_engineers
PRO
31
26k
GMOフィナンシャルゲートが挑む、「止まらない」決済インフラ構築の裏側【SORACOM Discovery 2026】
soracom
PRO
0
110
LLMリーダーボードアップデートに向けたAgentic Math_SWEのトレースについて
nejumi
0
160
実践が先生だった— 新卒サーバーエンジニア1年目のリアル
mixi_engineers
PRO
0
210
AI工学特論: MLOps・継続的評価
asei
11
3.1k
Featured
See All Featured
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
190
A Modern Web Designer's Workflow
chriscoyier
698
190k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Amusing Abliteration
ianozsvald
1
240
Building the Perfect Custom Keyboard
takai
2
820
Utilizing Notion as your number one productivity tool
mfonobong
4
490
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.5k
Heart Work Chapter 1 - Part 1
lfama
PRO
8
36k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.7k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
470
Transcript
Android Security ࠷લઢʂ Naoki Yano
ً Ϡϑʔגࣜձࣾ GYAOגࣜձࣾ Android Framework / Application / CTS
/ Driver Engineer Androidྺ 3 ؔ౦ྺ 2
Android Security ࠷લઢʁʁ Android Nougat ʹɺ SecurityपΓͷΞοϓσʔτ͕͍ͬͺ͍ʂʂ ɾUsing Scoped Directory
Access ɾDirect Boot ɾNetwork Security Config ɾKey Attestation ɾAPK Signature Scheme v2 ͍ͭͰ͑ΔΑ͏ʹ ४උ͓ͯ͘͜͠ͱ͕େࣄʂʂ
Android N Security Using Scoped Directory Access Direct Boot Network
Security Config Key Attestation APK Signature Scheme v2
Using Scoped Directory Access Android 6.0 Ҏલɿ ɹɹManifestʹPermissionΛఆٛ + PermissionRequest
ɹɹ֎෦ετϨʔδશͯͷΞΫηεΛڐՄɻ APP/FW Dir root Dir A Dir B Dir C Request Permit
Using Scoped Directory Access Android 7.0ɿ ɹɹΞΫηε͍ͨ͠σΟϨΫτϦͷStorageVolumeΛ࡞͠ɺRequestΛ͛Δɻ ɹɹಛఆͷσΟϨΫτϦͷΞΫηεͷΈڐՄ͢Δɻ APP/FW Dir
root Dir A Dir B Dir C Request Permit
Using Scoped Directory Access ৽نAPI ɾStorageVolume - ಛఆͷϢʔβʔͷڞ༗/֎෦ετϨʔδϘϦϡʔϜʹؔ͢Δใɻ - createAccessIntent()
- ϢʔβʔͷঝೝΛಘͨޙɺඪ४ͷετϨʔδσΟϨΫτϦ·ͨϘϦϡʔϜશମ ͷΞΫηεΛ༩͑ΔͨΊͷΠϯςϯτΛ࡞͢Δɻ - getState() - ετϨʔδϘϦϡʔϜͷঢ়ଶΛऔಘ͢Δɻ
Using Scoped Directory Access ৽نAPI ɾStorageManager ඞཁͳStorageVolumeΛऔಘ͢Δɻ - getPrimaryStorageVolume() -
getStorageVolume(File) - getStorageVolumes()
Using Scoped Directory Access // ΞΫηεݖ͕ඞཁͳstorageVolumeͷऔಘ StorageManager sm = getSystemService(StorageManager.class);
StorageVolume sv = sm.getPrimaryStorageVolume(); // ϢʔβʔঝೝΛಘΔͨΊͷIntentΛੜ Intent i = sv.createAccessIntent(Environment.DIRECTORY_MUSIC); // IntentΛStartActivityForResultͰ͛Δ startActivityForResult(i, REQUEST_CODE);
StorageVolume#createAccessIntent(String) package android.os.storage; public final class StorageVolume implements Parcelable {
… public @Nullable Intent createAccessIntent(String directoryName) { if ((isPrimary() && directoryName == null) || (directoryName != null && !Environment.isStandardDirectory(directoryName))) { return null; } final Intent intent = new Intent(ACTION_OPEN_EXTERNAL_DIRECTORY); intent.putExtra(EXTRA_STORAGE_VOLUME, this); intent.putExtra(EXTRA_DIRECTORY_NAME, directoryName); return intent; }
StorageVolume#createAccessIntent(String) package android.os; public class Environment { public static final
String[] STANDARD_DIRECTORIES = { DIRECTORY_MUSIC, DIRECTORY_PODCASTS, DIRECTORY_RINGTONES, DIRECTORY_ALARMS, DIRECTORY_NOTIFICATIONS, DIRECTORY_PICTURES, DIRECTORY_MOVIES, DIRECTORY_DOWNLOADS, DIRECTORY_DCIM, DIRECTORY_DOCUMENTS };
OpenExternalDirectoryActivity package com.android.documentsui; public class OpenExternalDirectoryActivity extends Activity { …
public void onCreate(Bundle savedInstanceState) { // σΟϨΫτϦ͕ࢦఆ͞Εͯͳ͍߹ɺrootͷݖݶΛऔಘ String directoryName = intent.getStringExtra(EXTRA_DIRECTORY_NAME ); if (directoryName == null) { directoryName = DIRECTORY_ROOT; } //ύʔϛογϣϯऔಘࡁΈͰͳ͍͔֬ೝ final StorageVolume volume = (StorageVolume) storageVolume; if (getScopedAccessPermissionStatus(getApplicationContext(), getCallingPackage(), volume.getUuid(), directoryName) == PERMISSION_NEVER_ASK) { //Ϣʔβ֬ೝDialogදࣔ final int userId = UserHandle.myUserId(); if (!showFragment(this, userId, volume, directoryName)) { }
Using Scoped Directory Access @Override public void onActivityResult(int requestCode, int
resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) { // ̎ճҎ߱μΠΞϩάΛग़͞ͳ͍Α͏ʹઃఆ getActivity().getContentResolver().takePersistableUriPermission(data.getData(), Intent.FLAG_GRANT_READ_URI_PERMISSION | ɹɹɹɹ Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // read, write // data.getData() ʹΞΫηεݖΛಘͨσΟϨΫτϦͷURI͕ೖ͍ͬͯΔ } }
Using Scoped Directory Access ɾײ ɹɹɾσΟϨΫτϦຖʹΞΫηεڐՄΛඞཁͱ͢Δͷɺ ɹɹɹ͏ଆͱͯ҆͠৺Ͱ͖Δɻ ɹɹɾϓϥΠϚϦετϨʔδͱͦΕҎ֎ͰAPIͷ͍ํ͕ ɹɹɹมΘͬͯ͘ΔͷͰҙʂ
Direct Boot Android 6.0 Ҏલɿ ɹɹ͕҉߸Խ͞Ε͍ͯΔ߹ɺطଘͷอଘઌɺ ɹɹϢʔβʔ͕ϩοΫΛղআͨ͠ޙʹ͚ͩ༻Ͱ͖Δɻ APP/FW data/user Boot
Unlock user key
Direct Boot APP/FW user Boot Unlock Android 7.0ɿ ɹɹϩοΫղআ͞Ε͍ͯͳ͍ঢ়ଶͰɺμΠϨΫτϒʔτϞʔυͰಈ࡞͢Δɻ ɹɹ҉߸ԽετϨʔδʹΞΫηεͰ͖Δɻ
user_de hard−backed key user key
Direct Boot ৽نAPI ɾandroid:directBootAware ίϯϙʔωϯτ͕҉߸ԽରԠ͢ΔΑ͏ʹࢦఆ͢Δɻ ɾandroid.intent.action.LOCKED_BOOT_COMPLETED ҉߸ԽετϨʔδ͕༻Մೳʹͳͬͨ͜ͱΛ௨͢Δɻ ɾContext#createDeviceProtectedStorageContext() ҉߸ԽετϨʔδʹΞΫηε͢ΔͨΊͷContextΛੜ͢Δɻ
Direct Boot // ίϯϙʔωϯτ͕҉߸ԽରԠ͢ΔΑ͏ʹFlagΛͨͯΔ <receiver android:name=".BootBroadcastReceiver" android:exported="false" android:directBootAware="true"> <intent-filter> <action
android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
Direct Boot // ProtectedStorageͷอଘ final Context deviceContext = getApplicationContext().createDeviceProtectedStorageContext(); deviceContext.moveSharedPreferencesFrom(context,
PREFERENCES_NAME)); SharedPreferences sp = deviceContext .getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
Direct Boot // LOCKED_BOOT_COMPLETEDΛड͚ͯσʔλΛऔಘ͢Δ public void onReceive(Context context, Intent intent)
{ boolean bootCompleted; String action = intent.getAction(); if (BuildCompat.isAtLeastN()) { bootCompleted = Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action); } else { bootCompleted = Intent.ACTION_BOOT_COMPLETED.equals(action); } if (!bootCompleted) { return; } }
Android 6.0 Ҏલɿ Android 7.0ɿ Direct Boot Android Boot Unlocked
Android Boot Unlocked BOOT_COMPLETED LOCKED_BOOT_COMPLETED USER_UNLOCKED BOOT_COMPLETED
Direct Boot ApplicationInfo ai = getApplicationInfo(); Log.i(TAG, “deviceProtectedDataDir: ” +
ai.deviceProtectedDataDir); # deviceProtectedDataDir: /data/user_de/0/com.yanokuro.directboot
Direct Boot ɾײ ɹɹɾ҉߸ԽετϨʔδͰɺηΩϡϦςΟϨϕϧ͕ ɹɹɹԼ͕ΔͨΊɺԿΛอଘ͢Δ͔ਫ਼͕ࠪඞཁɻ ɹɹɾBOOT_COMPLETE͕ݺΕΔҐஔ͕มΘͬͨΑɻ
Network Security Config Android 7.0ɿ ΧελϜCAূ໌ॻΛ৴པ͢ΔͨΊͷ҆શͰ؆୯ͳAPIͷఏڙɻ σϑΥϧτͰɺϢʔβʔ͕Ճͨ͠CAΛ৴པ͠ͳ͍ɻ
Network Security Config ɾres/xml/network_security_config Λ࡞ ɾmanifestʹه
Network Security Config <?xml version="1.0" encoding="utf-8"?> <manifest ... > <application
... > <meta-data android:name="android.security.net.config" android:resource="@xml/network_security_config" /> </application> </manifest>
Network Security ConfigɹΧελϜͷূ໌ػؔ <?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain>
<trust-anchors> <certificates src="@raw/my_ca"/> </trust-anchors> </domain-config> </network-security-config>
Network Security Configɹূ໌ॻͷఆٛ <trust-anchors> // ΞϓϦ͕͍࣋ͬͯΔCAূ໌ॻΛ༻ <certificates src="@raw/my_ca"/> // γεςϜσϑΥϧτͷCAূ໌ॻΛ༻
<certificates src="system"/> // Ϣʔβ͕Ճͨ͠CAূ໌ॻΛ༻ <certificates src="user"/> </trust-anchors>
Network Security Configɹσόοά༻ debuggable=true <?xml version="1.0" encoding="utf-8"?> <network-security-config> <debug-overrides> <trust-anchors>
<certificates src="@raw/debug_ca"/> </trust-anchors> </debug-overrides> </network-security-config>
Network Security ConfigɹΫϦΞςΩετͷ௨৴Λېࢭ <?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config usesCleartextTraffic="false"> <domain
includeSubdomains="true">secure.example.com</ domain> </domain-config> </network-security-config>
Network Security ConfigɹߏϑΝΠϧ <?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> ... </base-config>
<domain-config> ... </domain-config> <debug-overrides> ... </debug-overrides> </network-security-config>
Network Security ConfigɹAndroid 7.0 default <base-config usesCleartextTraffic="true"> <trust-anchors> <certificates src="system"
/> </trust-anchors> </base-config>
Network Security ConfigɹAndroid 7.0 ະຬ <base-config usesCleartextTraffic="true"> <trust-anchors> <certificates src="system"
/> <certificates src="user" /> </trust-anchors> </base-config>
Network Security Config ɾײ ɹɹɾઃఆΞϓϦ͔ΒCAೖΕΔඞཁ͕ͳ͘ͳͬͯخ͍͠ɻ ɹɹɾ7.0ΑΓલͰ͑Δͱ͍͍ͳɻ
·ͱΊ ͦΕͧΕҙϙΠϯτ͋Δ͕ɺؾΛ͚ͭͯ͑ΑΓη ΩϡΞͳΞϓϦ͕࡞Εͦ͏ɻ ֤ػೳͷಈ͖Λ͔ͬ͠Γཧղͯ͠։ൃ͠·͠ΐ͏ɻ
EOF