반응형

이번 시간은 Android Keystore 시스템에 대하여 알아보도록 하겠습니다.

 

#. Android Keystore System

Android Keystore 시스템을 사용하면 암호화 키를 컨테이너에 저장하여 기기에서 추출하기 어렵게 할 수 있습니다. 키 저장소에 키가 저장되면, 키 자료는 내보낼 수 없는 상태로 유지하면서 키를 암호화 작업에 사용할 수 있습니다. 이 시스템에서는 키 사용 시기와 사용 방법을 제한하는 기능도 제공합니다. 예를 들어 키 사용을 위해 사용자 인증을 요구하거나, 특정 암호화 모드에서만 키를 사용하도록 제한할 수 있습니다. 자세한 내용은 보안 기능 섹션을 참조하세요.

 

Keystore 시스템은 Android 4.3(API 수준 18)에서 도입된 Android Keystore 제공자 기능뿐 아니라 KeyChain API에서도 사용됩니다. 이 문서에서는 Android Keystore 제공자의 사용 시기와 사용 방법을 설명합니다.

 

#. 보안 기능

 

Android Keystore 시스템은 키 자료의 무단 사용을 방지합니다. 

첫째, Android Keystore는 애플리케이션 프로세스와 Android 기기 전체에서 키 자료의 추출을 차단하여 Android 기기 외부에서 키 자료의 무단 사용을 줄입니다. 

둘째, Android Keystore는 앱에서 승인된 키 사용처를 지정하도록 하여 앱 프로세스 외부에 적용하는 방식으로 Android 기기에서 키 자료의 무단 사용을 줄입니다.

 

#. 추출 차단

Android Keystore 키의 키 자료 추출을 차단하기 위해 두 가지 보안 조치가 사용됩니다.

키 자료는 애플리케이션 프로세스에 포함되지 않습니다. 애플리케이션에서 Android Keystore 키를 사용하여 암호화 작업을 수행하는 경우, 백그라운드 작업을 통해 서명하거나 확인할 일반 텍스트, 암호 텍스트 및 메시지가 암호화 작업을 수행하는 시스템 프로세스로 공급됩니다. 앱 프로세스가 손상된 경우 공격자가 앱 키를 사용할 수 있지만 Android 기기 외부에서 사용하기 위해 키 자료를 추출할 수는 없습니다.

▶ 키 자료를 Android 기기의 보안 하드웨어(예: TEE(신뢰할 수 있는 실행 환경), SE(보안 요소))에 바인딩할 수 있습니다. 이 기능을 키에 사용하면, 키 자료가 보안 하드웨어 외부에 노출되지 않습니다. Android OS가 손상되거나 공격자가 기기의 내부 저장소를 읽을 수 있는 경우 Android 기기에 있는 모든 앱의 Android Keystore 키를 사용할 수 있지만 기기에서 키를 추출할 수는 없습니다. 이 기능은 기기의 보안 하드웨어에서 키 사용이 승인된 키 알고리즘, 차단 모드, 패딩 스키마, 다이제스트 등의 특정한 조합을 지원하는 경우에만 사용할 수 있습니다. 키에 기능을 사용할 수 있는지 확인하려면 키에 대한 KeyInfo를 가져와 KeyInfo.isInsideSecurityHardware()의 반환 값을 검사합니다.

 

#. 하드웨어 보안 모듈

Android 9(API 수준 28) 이상이 설치되어 실행되는 지원 기기에는 하드웨어 보안 모듈에 상주하는 Keymaster HAL 구현인 StrongBox Keymaster가 있을 수 있습니다. 모듈에 포함된 구성 요소는 다음과 같습니다.

▶ 자체 CPU

▶ 보안 저장소

▶ 순수 난수 생성기

▶ 패키지 변조와 앱의 무단 사이드로드를 방지하는 추가 메커니즘

시스템은 StrongBox Keymaster에 저장된 키를 검사할 때 TEE(신뢰할 수 있는 실행 환경)를 사용하여 키의 무결성을 입증합니다.

저전력 StrongBox 구현을 지원하기 위해 다음과 같은 일부 알고리즘과 키 크기가 지원됩니다.

▶ RSA 2048

▶ AES 128 및 256

▶ ECDSA P-256

▶ HMAC-SHA256(8~64바이트의 키 크기 지원)

▶ Triple DES 168

KeyStore 클래스를 사용하여 키를 생성하거나 가져올 때 setIsStrongBoxBacked() 메서드에 true를 전달하여 StrongBox Keymaster에 키를 저장하도록 지정합니다. 이 메서드는 KeyGenParameterSpec.Builder 클래스 또는 KeyProtection.Builder 클래스에 있습니다.

참고: 키와 관련해서 지정된 알고리즘과 키 크기에 대해 StrongBox Keymaster를 사용할 수 없는 경우 프레임워크에서 StrongBoxUnavailableException이 throw됩니다.

 

#. 키 사용 승인

Android 기기에서 키 무단 사용을 줄이기 위해, Android Keystore에서는 키를 생성하거나 가져올 때 앱에서 승인된 키 사용처를 지정할 수 있습니다. 키를 생성하거나 가져온 후에는 승인을 변경할 수 없습니다. 그런 다음, 키가 사용될 때마다 Android Keystore에서 승인을 실행합니다. 이 기능은 고급 보안 기능이며, 일반적으로 키 생성/가져오기 이후(이전이나 도중은 아님) 애플리케이션 프로세스가 손상되더라도 키 무단 사용으로 이어져서는 안 된다는 요구사항이 있는 경우에만 유용합니다.

지원되는 키 사용 승인은 다음과 같은 카테고리로 구분됩니다.

▶ 암호화: 키 사용이 승인된 키 알고리즘, 작업 또는 용도(암호화, 복호화, 서명, 확인), 패딩 스키마, 차단 모드, 다이제스트

▶ 시간적 유효 기간: 키 사용이 승인된 시간 간격

▶ 사용자 인증: 최근에 사용자가 인증된 경우에만 키를 사용할 수 있습니다. 키 사용을 위한 사용자 인증 요구를 참조하세요

추가적인 보안 조치로, 키 자료가 보안 하드웨어 안에 있는 키의 경우(KeyInfo.isInsideSecurityHardware() 참조) Android 기기에 따라 보안 하드웨어에서 일부 키 사용 승인을 실행할 수 있습니다. 일반적으로 보안 하드웨어는 암호화 승인 및 사용자 인증 승인을 실행합니다. 보안 하드웨어에는 대체로 독립적인 실시간 보안 클록이 없기 때문에 시간적 유효성 간격 승인을 실행할 가능성은 적습니다.

보안 하드웨어에서 키의 사용자 인증 승인을 실행하는지 여부는 KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware()를 사용하여 쿼리 할 수 있습니다.

 

#. KeyChain 또는 AndroidKeystore Provider 중에 선택

시스템 수준의 사용자 인증 정보를 원하는 경우 KeyChain API를 사용합니다. 앱에서 KeyChain API를 통한 사용자 인증 정보 사용을 요청하는 경우, 사용자는 설치된 사용자 인증 정보 중에서 앱이 액세스 할 수 있는 사용자 인증 정보를 시스템 제공 UI를 통해 선택합니다. 이렇게 하면 사용자 동의를 받아 여러 앱이 동일한 사용자 인증 정보 집합을 사용할 수 있습니다.

개별 앱이 전용으로 액세스 할 수 있는 고유한 사용자 인증 정보를 저장할 수 있게 하려면 Android Keystore 제공자를 사용합니다. Android Keystore 제공자를 통해 앱에서 전용으로 사용할 수 있는 사용자 인증 정보를 관리할 수 있을 뿐만 아니라 KeyChain API가 시스템 수준의 사용자 인증 정보에 제공하는 것과 동일한 보안 이점을 얻을 수 있습니다. 이 방법은 사용자 인증 정보를 선택하기 위한 사용자 상호작용이 필요 없습니다.

 

#. Android Keystore Provider 사용

이 기능을 사용하려면 표준 KeyStore 및 KeyPairGenerator 또는 KeyGenerator 클래스와 Android 4.3(API 수준 18)에서 도입된 AndroidKeyStore 제공자를 함께 사용합니다.

AndroidKeyStore는 KeyStore.getInstance(type) 메서드에서 사용하기 위해 KeyStore 유형으로 등록되고, KeyPairGenerator.getInstance(algorithm, provider) 및 KeyGenerator.getInstance(algorithm, provider) 메서드에서 사용하기 위해 제공자로 등록됩니다.

 

#. 새 비공개 키 생성

새 PrivateKey를 생성하려면 자체 서명된 인증서에 사용할 초기 X.509 속성도 지정해야 합니다. 나중에 KeyStore.setKeyEntry를 사용하여 이 인증서를 CA(인증 기관)에서 서명한 인증서로 바꿀 수 있습니다.

키를 생성하려면 KeyPairGenerator와 KeyPairGeneratorSpec을 함께 사용합니다.

    /*
     * Generate a new EC key pair entry in the Android Keystore by
     * using the KeyPairGenerator API. The private key can only be
     * used for signing or verification and only with SHA-256 or
     * SHA-512 as the message digest.
     */
    val kpg: KeyPairGenerator = KeyPairGenerator.getInstance(
            KeyProperties.KEY_ALGORITHM_EC,
            "AndroidKeyStore"
    )
    val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder(
            alias,
            KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
    ).run {
        setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
        build()
    }

    kpg.initialize(parameterSpec)

    val kp = kpg.generateKeyPair()    

 

#. 새 보안 비밀키 생성

키를 생성하려면 KeyGenerator와 KeyGenParameterSpec을 함께 사용합니다.

 

#. 보다 안전하게  암호화된 키 가져오

Android 9(API 수준 28) 이상에서는 ASN.1로 인코딩된 키 형식을 사용하여 암호화된 키를 Keystore로 안전하게 가져올 수 있습니다. 그런 다음, Keymaster가 Keystore의 키를 복호화하므로 키의 내용이 기기의 호스트 메모리에 일반 텍스트로 표시되지 않습니다. 이 프로세스는 추가적인 키 복호화 보안을 제공합니다.

★ 참고: 이 기능은 Keymaster 4 이상과 함께 제공되는 기기에서만 지원됩니다.

암호화된 키를 Keystore로 안전하게 가져오도록 지원하려면 다음 단계를 완료하세요.

▶ PURPOSE_WRAP_KEY 용도로 사용되는 키 쌍을 생성합니다. 이 키 쌍에 증명도 추가하는 것이 좋습니다.

▶ 신뢰할 수 있는 서버나 컴퓨터에서 SecureKeyWrapper에 포함되어야 하는 ASN.1 메시지를 생성합니다.

wrapper에는 다음 스키마가 있습니다.

KeyDescription ::= SEQUENCE {
        keyFormat INTEGER,
        authorizationList AuthorizationList
    }

    SecureKeyWrapper ::= SEQUENCE {
        wrapperFormatVersion INTEGER,
        encryptedTransportKey OCTET_STRING,
        initializationVector OCTET_STRING,
        keyDescription KeyDescription,
        secureKey OCTET_STRING,
        tag OCTET_STRING
    }    

▶ WrappedKeyEntry 객체를 생성하고 ASN.1 메시지를 바이트 배열로 전달합니다.

▶ 이 WrappedKeyEntry 객체를 setEntry() 오버로드에 전달합니다. 이 메서드는 Keystore.Entry 객체를 허용합니다.

 

#. 키 저장소 항목 작업

AndroidKeyStore 제공자 사용은 모든 표준 KeyStore API에서 발생합니다.

 

#. 항목 나열

aliases() 메서드를 호출하여 키 저장소의 항목을 나열합니다.

    /*
     * Load the Android KeyStore instance using the
     * "AndroidKeyStore" provider to list out what entries are
     * currently stored.
     */
    val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply {
        load(null)
    }
    val aliases: Enumeration<String> = ks.aliases()    

 

#. 데이터 서명 및 확인

키 저장소에서 KeyStore.Entry를 가져오고 sign() 등의 Signature API를 사용하여 데이터에 서명합니다.

    /*
     * Use a PrivateKey in the KeyStore to create a signature over
     * some data.
     */
    val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply {
        load(null)
    }
    val entry: KeyStore.Entry = ks.getEntry(alias, null)
    if (entry !is KeyStore.PrivateKeyEntry) {
        Log.w(TAG, "Not an instance of a PrivateKeyEntry")
        return null
    }
    val signature: ByteArray = Signature.getInstance("SHA256withECDSA").run {
        initSign(entry.privateKey)
        update(data)
        sign()
    }    

마찬가지로, verify(byte[]) 메서드를 사용하여 데이터를 확인합니다.

   /*
     * Verify a signature previously made by a PrivateKey in our
     * KeyStore. This uses the X.509 certificate attached to our
     * private key in the KeyStore to validate a previously
     * generated signature.
     */
    val ks = KeyStore.getInstance("AndroidKeyStore").apply {
        load(null)
    }
    val entry = ks.getEntry(alias, null) as? KeyStore.PrivateKeyEntry
    if (entry == null) {
        Log.w(TAG, "Not an instance of a PrivateKeyEntry")
        return false
    }
    val valid: Boolean = Signature.getInstance("SHA256withECDSA").run {
        initVerify(entry.certificate)
        update(data)
        verify(signature)
    }    

 

#. 키 사용을 위한 사용자 인증 도구

키를 생성하거나 AndroidKeyStore로 가져올 때, 사용자가 인증된 경우에만 키 사용을 승인하도록 지정할 수 있습니다. 사용자는 보안 잠금 화면의 사용자 인증 정보(패턴/PIN/비밀번호, 지문)의 일부를 사용하여 인증됩니다.

이 기능은 고급 보안 기능이며, 일반적으로 키 생성/가져오기 이후(이전이나 도중은 아님) 애플리케이션 프로세스가 손상되더라도 키 사용을 위한 사용자 인증 요구사항이 무시되어서는 안 된다는 요구사항이 있는 경우에만 유용합니다.

사용자가 인증된 경우에만 키 사용을 승인하는 경우, 다음 두 가지 모드 중 하나로 작동하도록 구성됩니다.

▶ 사용자 인증을 통해 일정 기간 동안 키 사용을 승인합니다. 이 모드의 모든 키는 사용자가 보안 잠금 화면의 잠금을 해제하거나 KeyguardManager.createConfirmDeviceCredentialIntent 흐름을 사용하여 보안 잠금 화면 사용자 인증 정보를 확인하는 즉시 사용이 승인됩니다. 승인이 유효한 기간은 키마다 다르며, 키를 생성하거나 가져올 때 setUserAuthenticationValidityDurationSeconds를 사용하여 지정됩니다. 이러한 키는 보안 잠금 화면이 사용 설정된 경우에만 생성하거나 가져올 수 있습니다(KeyguardManager.isDeviceSecure() 참조). 보안 잠금 화면을 사용할 수 없거나(None, Swipe 또는 사용자를 인증하지 않는 기타 모드로 재구성됨) 기기 관리자 등이 강제로 재설정하면 키가 영구적으로 무효화됩니다.

▶ 사용자 인증을 통해 하나의 키와 관련된 특정 암호화 작업을 승인합니다. 이 모드에서는 이러한 키와 관련된 각 작업을 사용자가 개별적으로 승인해야 합니다. 현재, 이러한 승인의 유일한 수단은 지문 인증(FingerprintManager.authenticate)뿐입니다. 최소 하나 이상의 지문이 등록된 경우에만 키를 생성하거나 가져올 수 있습니다(FingerprintManager.hasEnrolledFingerprints 참조). 지문을 새로 등록하거나 모든 지문을 등록 해제하면 키가 영구적으로 무효화됩니다.

 

#. 지원되는 알고리즘

▶ Cipher

▶ KeyGenerator

▶ KeyFactory

▶ KeyPairGenerator

▶ Mac

▶ Signature

▶ SecretKeyFactory

 

#. Cipher

알고리즘 지원 버전(API 수준) 메모
AES/CBC/NoPadding 23 이상  
AES/CBC/PKCS7Padding 23 이상  
AES/CTR/NoPadding 23 이상  
AES/ECB/NoPadding 23 이상  
AES/ECB/PKCS7Padding 23 이상  
AES/GCM/NoPadding 23 이상 12바이트 길이 IV만 지원됩니다.
RSA/ECB/NoPadding 18 이상  
RSA/ECB/PKCS1Padding 18 이상  
RSA/ECB/OAEPWithSHA-1AndMGF1Padding 23 이상  
RSA/ECB/OAEPWithSHA-224AndMGF1Padding 23 이상  
RSA/ECB/OAEPWithSHA-256AndMGF1Padding 23 이상  
RSA/ECB/OAEPWithSHA-384AndMGF1Padding 23 이상  
RSA/ECB/OAEPWithSHA-512AndMGF1Padding 23 이상  
RSA/ECB/OAEPPadding 23 이상  

 

#. KeyGenerator

알고리즘 지원 버전(API 수준) 메모
AES 23 이상 지원되는 크기: 128, 192, 256
HmacSHA1 23 이상
  • 지원되는 크기: 8--1024(포함), 8의 배수여야 함
  • 기본 크기: 160
HmacSHA224 23 이상
  • 지원되는 크기: 8--1024(포함), 8의 배수여야 함
  • 기본 크기: 224
HmacSHA256 23 이상
  • 지원되는 크기: 8--1024(포함), 8의 배수여야 함
  • 기본 크기: 256
HmacSHA384 23 이상
  • 지원되는 크기: 8--1024(포함), 8의 배수여야 함
  • 기본 크기: 384
HmacSHA512 23 이상
  • 지원되는 크기: 8--1024(포함), 8의 배수여야 함
  • 기본 크기: 512

 

#. KeyFactory

알고리즘 지원 버전(API 수준) 메모
EC 23 이상 지원되는 키 사양: KeyInfo(비공개 키 전용), ECPublicKeySpec(공개 키 전용), X509EncodedKeySpec(공개 키 전용)
RSA 23 이상 지원되는 키 사양: KeyInfo(비공개 키 전용), RSAPublicKeySpec(공개 키 전용), X509EncodedKeySpec(공개 키 전용)
 
 
#. Keystore
KeyStore는 KeyPairGenerator  KeyGenerator와 동일한 키 유형을 지원합니다.
 
#. KeyPairGenerator
알고리즘 지원 버전(API 수준) 메모
DSA 19–22  
EC 23 이상
  • 지원되는 크기: 224, 256, 384, 521
  • 지원되는 명명된 곡선: P-224(secp224r1), P-256(secp256r1 및 prime256v1), P-384(secp384r1), P-521(secp521r1)
API 수준 23 이전에는 'RSA' 알고리즘으로 초기화된 KeyPairGeneratorSpec의 KeyPairGenerator를 사용하여 EC 키를 생성할 수 있으며, 키 유형은 setKeyType(String)을 사용하여 'EC'로 설정됩니다. EC 곡선 이름은 이 방법으로 지정할 수 없으며, 요청한 키 크기에 따라 NIST P 곡선이 자동으로 선택됩니다.
RSA 18 이상
  • 지원되는 크기: 512, 768, 1024, 2048, 3072, 4096
  • 지원되는 공개 지수: 3, 65537
  • 기본 공개 지수: 65537
 
#. Mac
알고리즘 지원 버전(API 수준) 메모
HmacSHA1 23 이상  
HmacSHA224 23 이상  
HmacSHA256 23 이상  
HmacSHA384 23 이상  
HmacSHA512 23 이상

 

#. Signature

알고리즘 지원 버전(API 수준) 메모
MD5withRSA 18 이상  
NONEwithECDSA 23 이상  
NONEwithRSA 18 이상  
SHA1withDSA 19–22  
SHA1withECDSA 19 이상  
SHA1withRSA 18 이상  
SHA1withRSA/PSS 23 이상  
SHA224withDSA 20–22  
SHA224withECDSA 20 이상  
SHA224withRSA 20 이상  
SHA224withRSA/PSS 23 이상  
SHA256withDSA 19–22  
SHA256withECDSA 19 이상  
SHA256withRSA 18 이상  
SHA256withRSA/PSS 23 이상  
SHA384withDSA 19–22  
SHA384withECDSA 19 이상  
SHA384withRSA 18 이상  
SHA384withRSA/PSS 23 이상  
SHA512withDSA 19–22  
SHA512withECDSA 19 이상  
SHA512withRSA 18 이상  
SHA512withRSA/PSS 23 이상

 

#. SecretKeyFactory

알고리즘 지원 버전(API 수준) 메모
AES 23 이상 지원되는 키 사양: KeyInfo
HmacSHA1 23 이상 지원되는 키 사양: KeyInfo
HmacSHA224 23 이상 지원되는 키 사양: KeyInfo
HmacSHA256 23 이상 지원되는 키 사양: KeyInfo
HmacSHA384 23 이상 지원되는 키 사양: KeyInfo
HmacSHA512 23 이상 지원되는 키 사양: KeyInfo

 

#. Sample

Android AsymmetricFingerprintDialogAndroid BasicAndroidKeyStore 및 Android ConfirmCredential샘플은 이 페이지에서 설명한 API의 사용 사례를 자세히 보여줍니다.

 

Reference

1. https://developer.android.com/training/articles/keystore?hl=ko

반응형
반응형

이번 포스팅은 Android에서 보다 더 안전하게 데이터를 저장하는 방법에 대해 알아보도록 하겠습니다.

 

Android Jetpack 일부인 Security Library유휴 상태의 데이터를 읽고 쓰는 것과 관련된 보안 모범 사례키 생성 및 검증의 구현을 위해 제공합니다.
라이브러리는 빌더 패턴을 사용하여 다음 보안 레벨에 안전한 기본 설정을 제공합니다.

강력한 암호화와 우수한 성능의 균형을 유지하는 강력한 보안 : 이 보안 수준은 뱅킹 및 채팅 앱과 같은 소비자 앱과 인증서 해지 확인을 수행하는 엔터프라이즈 앱에 적합합니다.

최대 보안 : 이 수준의 보안은 키 액세스를 제공하기 위해 하드웨어 기반 키 저장소 및 사용자 존재가 필요한 앱에 적합합니다. 이 안내서는 Security Library의 권장 보안 구성 SharedPreference 파일에 저장된 암호화된 데이터를 쉽고 안전하게 읽고 쓰는 방법을 보여줍니다.

 
키 관리Security Library는 키 관리를 위해 2부시스템을 사용합니다.
 
파일 또는 SharedPreference를 암호화하기위한 하나 이상의 Key키가 포함 Keyset 입니다. 키셋 자체는SharedPreferences에 저장됩니다.
 
모든 Keyset를 암호화 하는 마스터 키 : 이 키는 Android 키 저장소 시스템을 사용하여 저장됩니다 .

 

다음 소스 코드는 마스터 키를 정의하는 방법을 보여줍니다.

// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

 

#. Library에 포함된 Class

 

Security Library에는 보다 안전한 데이터를 제공하기 위해 다음과 같은 클래스가 포함되어 있습니다.

EncryptedFile

FileInputStream  및 FileOutputStream을 사용자 정의 구현하여 앱에 보다 안전한 스트리밍 읽기 및 쓰기 작업을 제공합니다.

▶ 파일 스트림에서 안전한 읽기 및 쓰기 작업을 제공하기 위해 Security Library는 AEAD (Authenticated Encryption with Associated Data)를 기본을 사용합니다. GitHub GitHub의 Tink 라이브러리 설명서에서 이 기본 요소에 대해 자세히 알아보십시오..

EncryptedSharedPreferences

SharedPreferences  클래스를 감싸고 다음 두 가지 구성 방법을 사용하여 키와 값을 자동으로 암호화합니다.

▶ Key는 암호화되고 적절하게 조회될 수 있도록 결정론적 암호화 알고리즘을 사용하여 암호화합니다

타겟 TTS
/span>

 

▶ Value AES-256 GCM을 사용하여 암호화되며 결정적이지 않습니다.

다음 섹션에서는 이러한 클래스를 사용하여 파일 및 공유 환경 설정으로 공통 작업을 수행하는 방법을 보여줍니다.

 

#. 파일 읽기

 

음 소스 코드는 EncryptedFile을 사용하여 파일의 내용을 보다 안전하게 읽는 방법을 보여줍니다 .

val fileToRead = "my_sensitive_data.txt"
lateinit
var byteStream: ByteArrayOutputStream
val encryptedFile = EncryptedFile.Builder(
   
File(context.getFilesDir(), fileToRead),
    context
,
    masterKeyAlias
,
   
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

try {
    encryptedFile
.openFileInput().use { fileInputStream ->
       
try {
            byteStream
= ByteArrayOutputStream()
           
var nextByte = fileInputStream.read()
           
while (nextByte != -1) {
                byteStream
.write(nextByte)
                nextByte
= fileInputStream.read()
           
}

           
val fileContents = byteStream.toByteArray()

       
} catch (ex: Exception) {
           
// Error occurred opening raw file for reading.
       
} finally {
            fileInputStream
.close()
       
}
   
})
} catch (ex: IOException) {
   
// Error occurred opening encrypted file for reading.
}

 

#. 파일 쓰기

 

다음 소스 코드는 EncryptedFile을 사용하여 파일의 내용을 보다 안전하게 쓰는 방법을 보여줍니다.

val fileToWrite = "my_other_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(
   
File(context.getFilesDir(), fileToWrite),
    context
,
    masterKeyAlias
,
   
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

// Write to a file.
try {
   
val outputStream: FileOutputStream? = encryptedFile.openFileOutput()
    outputStream
?.apply {
        write
("MY SUPER SECRET INFORMATION"
           
.toByteArray(Charset.forName("UTF-8")))
        flush
()
        close
()
   
}
} catch (ex: IOException) {
   
// Error occurred opening file for writing.
}

추가 보안이 필요한 사용 사례의 경우 다음 단계를 완료하십시오.

 KeyGenParameterSpec.Builder를 생성하십시오. Build 객체로 setUserAuthenticationRequired()를 true로 전달하고 0보다 큰 값을 setUserAuthenticationValidityDurationSeconds()로 전달하세요.

사용자에게 createConfirmDeviceCredentialIntent()을 사용하여 자격 증명을 입력하도록 키 사용을 위해 사용자 인증 요청하는 방법에 대해 자세히 알아보십시오 .

★ 참고 : 보안 라이브러리는 BiometricPrompt 암호화 작업 수준에서 지원하지 않습니다.

 확인된 자격 증명 콜백을 가져오기 위해 onActivityResult()를 재정의 하십시오. 자세한 정보 키 사용을 위한 사용자 인증 요구 참조하십시오.

 

#. SharedPreference 편집

 

다음 소스코드는 EncryptedSharedPreferences은 보다 안전한 방식으로 사용자의 SharedPerference를 편집하는 방법을 보여줍니다 .

val sharedPreferences = EncryptedSharedPreferences
   
.create(
    fileName
,
    masterKeyAlias
,
    context
,
   
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
   
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

val sharedPrefsEditor = sharedPreferences.edit()

 

Reference

1.  https://developer.android.com/topic/security/data

반응형
반응형

Android Security Tips

Android에는 애플리케이션 보안 문제의 빈도와 영향을 크게 줄이는 보안 기능이 내장되어 있습니다. 이 시스템은 사용자가 기본 시스템과 파일 권한으로 앱을 빌드하고 보안과 관련된 까다로운 결정을 피할 수 있도록 설계되었습니다.

 

안전한 앱을 빌드하는 데 도움이 되는 핵심 보안 기능은 다음과 같습니다.

▶ 사용자의 앱 데이터와 코드 실행을 다른 앱으로부터 격리하는 Android 애플리케이션 샌드박스

▶ 암호화, 권한, 안전한 IPC와 같은 일반적인 보안 기능이 강력하게 구현된 애플리케이션 프레임워크

▶ ASLR, NX, ProPolice, safe_iop, OpenBSD dlmalloc, OpenBSD calloc, Linux mmap_min_addr과 같은 기술로 일반적인 메모리 관리 오류와 연관된 위험 완화

▶ 암호화된 파일 시스템으로 분실하거나 도난당한 기기의 데이터 보호

▶ 시스템 기능 및 사용자 데이터에 대한 액세스를 제한하기 위해 사용자가 부여하는 권한

▶ 앱별로 애플리케이션 데이터를 제어하기 위해 애플리케이션에서 정의하는 권한

 

이 문서의 Android 보안 권장사항을 숙지하는 것이 좋습니다. 이러한 권장사항을 일반적인 코딩 습관으로 사용하면 사용자에게 부정적인 영향을 미치는 보안 문제가 발생할 가능성이 줄어듭니다.

 

#. 데이터 저장

Android 애플리케이션의 가장 일반적인 보안 관련 우려사항은 기기에 저장한 데이터에 다른 앱이 액세스 할 수 있는가입니다. 기기에 데이터를 저장하는 기본적인 방법 3가지는 다음과 같습니다.

▶ 내부 저장소

▶ 외부 저장소

▶ 콘텐츠 제공업체

 

다음 단락에서는 각 접근 방식과 관련된 보안 문제를 설명합니다.

 

#. 내부 저장소 사용

기본적으로 내부 저장소에 생성한 파일은 내 앱에서만 액세스할 수 있습니다. Android에는 이러한 보호 장치가 구현되어 있으며, 대부분의 애플리케이션에서는 이 기능으로 충분합니다.

일반적으로 IPC 파일은 특정 애플리케이션에 대한 데이터 액세스를 제한하는 기능을 제공하지 않으며 데이터 형식을 제어하지 않으므로 IPC 파일에는 MODE_WORLD_WRITEABLE 또는 MODE_WORLD_READABLE 모드를 사용하지 않아야 합니다. 데이터를 다른 앱 프로세스와 공유하려면 대신 콘텐츠 제공업체를 사용하는 것이 좋습니다. 콘텐츠 제공업체는 다른 앱에 대한 읽기 및 쓰기 권한을 제공하며 사례별로 권한을 동적으로 부여할 수 있습니다.

민감한 정보의 보안을 강화하려면 애플리케이션에서 직접 액세스 할 수 없는 키를 사용해 로컬 파일을 암호화하세요. 예를 들어 KeyStore에 키를 보관하고, 기기에 저장되지 않는 사용자 비밀번호로 키를 보호할 수 있습니다. 이렇게 하면 사용자의 비밀번호 입력을 모니터링할 수 있는 루트 침해로부터 데이터를 보호할 수는 없지만, 파일 시스템 암호화를 사용하지 않아도 분실한 기기를 보호할 수 있습니다.

 

#. 외부 저장소 사용

SD 카드와 같은 외부 저장소에 생성한 파일은 누구나 읽고 쓸 수 있습니다. 외부 저장소는 사용자가 삭제할 수 있으며, 모든 애플리케이션에서 수정할 수 있으므로, 민감한 정보는 외부 저장소에 저장하면 안 됩니다.

외부 저장소의 데이터를 처리할 때는 신뢰할 수 없는 소스의 데이터와 마찬가지로 입력 유효성 검사를 시행해야 합니다. 실행 파일이나 클래스 파일을 동적으로 로드하기 전에 외부 저장소에 저장하지 않는 것이 좋습니다. 앱이 외부 저장소에서 실행 파일을 가져오는 경우 동적으로 로드하기 전에 파일에 서명하고 암호로 인증해야 합니다.

 

#. 콘텐츠 제공업체 사용

콘텐츠 제공업체는 사용자가 소유한 애플리케이션으로 한정되거나 내보내기를 통해 다른 애플리케이션이 액세스 할 수 있도록 하는 구조화된 저장 메커니즘을 제공합니다. 다른 애플리케이션에 ContentProvider에 대한 액세스 권한을 제공하지 않으려는 경우 애플리케이션 매니페스트에 이 애플리케이션을 android:exported=false로 표시하세요. 권한을 제공하려면 android:exported 속성을 true로 설정하여 다른 앱에서 저장된 데이터에 액세스하도록 허용할 수 있습니다.

다른 애플리케이션에서 사용하도록 내보내는 ContentProvider를 만드는 경우 읽기와 쓰기를 위한 단일 권한을 지정하거나 읽기와 쓰기를 위한 별도의 권한을 지정할 수 있습니다. 현재 작업을 시행하는 데 필요한 권한으로만 권한을 제한하는 것이 좋습니다. 일반적으로 권한을 삭제하여 기존 사용자에게 영향을 주기보다는 나중에 권한을 추가하여 새로운 기능을 노출하는 것이 더 쉽습니다.

내 앱 사이에서만 데이터를 공유하는 데 콘텐츠 제공업체를 사용하는 경우 android:protectionLevel 속성을 signature 보호로 설정하여 사용하는 것이 좋습니다. 서명 권한은 사용자 확인이 필요하지 않으므로, 콘텐츠 제공업체 데이터에 액세스 하는 앱이 동일한 키로 서명될 때 더 나은 사용자 환경이 제공되며 데이터에 대한 액세스 제어가 향상됩니다.

또한 콘텐츠 제공업체는 android:grantUriPermissions 속성을 선언하고 구성요소를 활성화하는 Intent 개체에 FLAG_GRANT_READ_URI_PERMISSION과 FLAG_GRANT_WRITE_URI_PERMISSION 플래그를 사용하여 액세스를 세분화할 수 있습니다. 이러한 권한의 범위는 <grant-uri-permission> 요소로 더 제한할 수 있습니다.

콘텐츠 제공업체에 액세스할 때 query()update()delete()와 같은 매개변수화된 쿼리 메서드를 사용하여 신뢰할 수 없는 소스의 SQL 삽입 가능성을 방지할 수 있습니다. 메서드에 제출하기 전에 사용자 데이터를 연결하여 selection 인수가 빌드된 경우 매개변수화된 메서드를 사용하는 것만으로는 충분하지 않습니다.

쓰기 권한에 대해 잘못된 보안 인식을 가지면 안 됩니다. 쓰기 권한은 창의적인 WHERE 절을 사용하고 결과를 파싱하여 일부 데이터를 확인할 수 있는 SQL 문을 허용합니다. 예를 들어 공격자는 특정 전화번호가 이미 존재하고 있을 때만 행을 수정하여 통화 기록에 해당 전화번호가 존재하는지 찾을 수 있습니다. 콘텐츠 제공업체 데이터에 예측 가능한 구조가 있다면 쓰기 권한은 읽기 및 쓰기 권한을 모두 제공하는 것과 같을 수 있습니다.

 

#. 권한 사용

Android는 애플리케이션을 각각 샌드박스화하므로 애플리케이션에서는 리소스와 데이터를 명시적으로 공유해야 합니다. 이를 위해 애플리케이션에서는 기본 샌드박스에서 제공하지 않는 추가 기능(예: 카메라와 같은 기기 기능에 액세스)을 실행하기 위해 필요한 권한을 선언합니다.

 

#. 권한 요청

앱에서 요청하는 권한의 수를 최소화해야 합니다. 민감한 정보에 대한 액세스 권한을 제한하면 이러한 권한을 오용하는 위험이 감소하여 사용자 채택률을 높이고 공격자에 대한 앱의 취약점을 줄일 수 있습니다. 일반적으로 앱이 기능하는 데 필요한 권한이 아니라면 요청해서는 안 됩니다. 없으면 앱이 실행되지 않는 기능이 있는 경우 매니페스트 파일에 <uses-feature> 요소를 사용해 그 기능을 선언하세요.

어떠한 권한도 요청하지 않도록 애플리케이션을 설계할 수 있다면 그렇게 하는 것이 좋습니다. 예를 들어, 고유 식별자를 생성하기 위해 기기 정보에 대한 액세스를 요청하기보다는 애플리케이션의 GUID를 생성하세요(사용자 데이터 처리에 관한 섹션 참조). 또는 권한이 필요한 외부 저장소를 사용하는 대신 내부 저장소에 데이터를 저장하시기 바랍니다.

권한 요청 외에도 애플리케이션에서 <permission> 요소를 사용해 보안에 민감하고 ContentProvider와 같은 다른 애플리케이션에 노출되는 IPC를 보호할 수 있습니다. 일반적으로 권한은 사용자에게 혼란을 줄 수 있으므로 가능하다면 사용자 확인 권한이 아니라 액세스 제어를 사용하는 것이 좋습니다. 예를 들어 한 명의 개발자가 제공한 애플리케이션 간 IPC 통신의 경우 권한에 서명 보호 수준을 사용해 보시기 바랍니다.

권한 보호된 데이터는 유출하지 마세요. 이러한 유출은 앱이 데이터에 액세스 할 권한이 있을 때만 사용할 수 있는 데이터를 이 IPC를 통해 노출하는 경우에 발생합니다. 앱 IPC 인터페이스의 클라이언트에 이와 동일한 데이터 액세스 권한이 없을 수도 있습니다. 이 문제의 발생 빈도와 잠재적 영향에 대한 자세한 내용은 USENIX에 게시된 권한 재위임: 공격과 방어 연구 논문을 참조하세요.

 

#. 권한 만들기

일반적으로 보안 요구사항을 충족하는 동시에 가능한 한 적은 수의 권한을 정의해야 합니다. 애플리케이션은 주로 시스템 정의 권한이 많은 상황을 해결하기 때문에 새로운 권한을 생성하는 것이 상대적으로 드문 편입니다. 필요한 경우 기존 권한을 사용하여 액세스 검사를 시행하시기 바랍니다.

새 권한을 생성해야 한다면 서명 보호 수준으로 작업할 수 있는지 고려하세요. 서명 권한은 사용자에게 투명하게 공개되며, 권한을 검사하는 애플리케이션과 동일한 개발자가 서명한 애플리케이션에서만 액세스 할 수 있습니다. 그래도 새 권한이 필요한 경우 <permission> 요소를 사용해 앱 매니페스트에 선언합니다. 새 권한을 사용하려는 앱은 각 매니페스트 파일에 <uses-permission> 요소를 추가하여 이 권한을 참조할 수 있습니다. addPermission() 메서드를 사용해 권한을 동적으로 추가할 수도 있습니다.

위험한 보호 수준으로 권한을 생성하는 경우에는 다음과 같은 여러 복잡성을 고려해야 합니다.

▶ 권한에는 사용자에게 필요한 보안 결정을 간결하게 설명하는 문자열이 있어야 합니다.

▶ 이 권한 문자열은 여러 다른 언어로 현지화되어야 합니다.

▶ 사용자는 권한이 혼동을 주거나 위험하다고 인식하는 경우 애플리케이션을 설치하지 않을 수 있습니다.

▶권한 작성자가 설치되지 않은 경우 애플리케이션에서 권한을 요청할 수 있습니다.

이와 같은 각각의 복잡성은 사용자를 혼란스럽게 하고 개발자에게도 기술과 관련되지 않은 상당한 어려움을 줄 수 있으므로 위험한 권한 수준은 사용하지 않는 것이 좋습니다.

 

#. 네트워킹 사용

네트워크 트랜잭션은 사용자의 비공개 데이터를 전송할 가능성이 있으므로 근본적으로 보안에 위협이 됩니다. 사람들은 특히 기기에서 네트워크 트랜잭션을 수행하는 경우 휴대기기의 개인정보 보호 문제를 점차 인식하고 있으므로, 앱에서 항상 사용자의 데이터를 안전하게 유지할 수 있는 방향으로 모든 권장사항을 구현하는 것이 중요합니다.

 

#. IP 네트워킹 사용

Android에서의 네트워킹은 다른 Linux 환경과 크게 다르지 않습니다. 고려해야 할 점은 안전한 웹 트래픽을 위해 민감한 정보에 HttpsURLConnection과 같은 적절한 프로토콜을 사용하는 것입니다. 휴대기기는 공용 Wi-Fi 핫스팟과 같이 안전하지 않은 네트워크에 자주 연결되기 때문에 서버에서 HTTPS가 지원되는 경우에는 항상 HTTP보다 HTTPS를 사용해야 합니다.

인증 및 암호화된 소켓 수준 통신은 SSLSocket 클래스를 사용하여 간단하게 구현할 수 있습니다. Android 기기가 Wi-Fi를 사용하여 안전하지 않은 무선 네트워크에 연결되는 빈도를 고려할 때, 네트워크를 통해 통신하는 모든 애플리케이션에 안전한 네트워크 사용이 적극 권장됩니다.

일부 애플리케이션에서는 민감한 IPC를 처리하는 데 localhost 네트워크를 사용합니다. 이러한 인터페이스는 기기의 다른 애플리케이션에서 액세스할 수 있으므로 이 접근 방식을 사용해서는 안 됩니다. 대신 Service에서와 같이 인증이 가능한 경우 Android IPC 메커니즘을 사용하세요. INADDR_ANY에 결합하면 애플리케이션에서 어디서나 요청을 받을 수 있으므로 루프백 사용보다 좋지 않습니다.

HTTP 또는 기타 안전하지 않은 프로토콜에서 다운로드한 데이터는 신뢰하면 안 됩니다. 여기에는 WebView의 입력 유효성 검사와 HTTP에서 발행한 인텐트에 대한 응답이 포함됩니다.

 

#. 전화 네트워킹 사용

SMS

프로토콜은 주로 사용자 간 통신을 위해 설계되었으며 데이터를 전송하려는 앱에는 적합하지 않습니다. SMS의 제한 사항으로 인해 데이터 메시지를 웹 서버에서 사용자 기기의 앱으로 전송하려면 Google Cloud Messaging(GCM) 및 IP 네트워크를 사용해야 합니다.

SMS는 네트워크나 기기에서 암호화되거나 강력하게 인증되지 않으니 주의해야 합니다. 특히 모든 SMS 수신자는 악의적인 의도를 가진 사용자가 자신의 애플리케이션에 SMS를 전송했을 수도 있다는 사실을 인지해야 합니다. 따라서 인증되지 않은 SMS 데이터에 의존해 민감한 명령어를 실행해서는 안 됩니다. 또한 SMS는 네트워크에서 위장되거나 가로채기 될 수 있으니 주의해야 합니다. Android 지원 기기에서 SMS 메시지는 브로드캐스트 인텐트로 전송되기 때문에 READ_SMS 권한이 있는 다른 애플리케이션에서 읽거나 캡처할 수 있습니다.

 

#. 입력 유효성 검사 시행

충분하지 않은 입력 유효성 검사는 실행 중인 플랫폼과 관계없이 애플리케이션에 영향을 주는 가장 일반적인 보안 문제 중 하나입니다. Android는 애플리케이션이 입력 유효성 검사 문제에 노출되는 것을 줄이는 플랫폼 수준의 대책을 보유하고 있으므로 가능한 한 이러한 기능을 사용해야 합니다. 또한 안전한 형식의 언어를 선택하면 입력 유효성 검사 문제가 발생할 가능성을 줄일 수 있습니다.

네이티브 코드를 사용하면 파일에서 읽거나, 네트워크를 통해 수신되거나, IPC로부터 수신된 데이터에 보안 문제가 발생할 수 있습니다. 가장 일반적인 문제는 버퍼 오버플로우UAF(Use-After-Free)OBO(Off-By-One)입니다. Android에서는 이러한 오류의 악용을 막기 위해 ASLR  및 DEP와 같은 여러 기술을 제공하지만, 근본적인 문제는 해결되지 않습니다. 포인터 처리와 버퍼 관리에 주의하면 이러한 취약점을 방지할 수 있습니다.

자바스크립트 및 SQL과 같은 동적인 문자열 기반 언어 역시 이스케이프 문자 및 스크립트 삽입으로 인해 입력 유효성 검사 문제가 발생할 수 있습니다.

SQL 데이터베이스나 콘텐츠 제공업체에 제출된 쿼리 내에 있는 데이터를 사용하는 경우 SQL 삽입이 문제가 될 수 있습니다. 최선의 방어는 위의 콘텐츠 제공업체 관련 섹션에서 설명한 것처럼 매개변수화된 쿼리를 사용하는 것입니다. 읽기 전용 또는 쓰기 전용으로 권한을 제한해도 SQL 삽입과 관련된 잠재적인 위험을 줄일 수 있습니다.

위의 보안 기능을 사용할 수 없는 경우 잘 구조화된 데이터 형식을 사용하고 데이터가 올바른 형식을 준수하는지 확인해야 합니다. 문자 차단이나 문자 교체가 효과적인 전략이 될 수 있지만 이러한 기술은 실제 적용 시 오류가 발생하기 쉽기 때문에 가능한 한 피해야 합니다.

 

#. 사용자 데이터 처리

일반적으로 사용자 데이터 보안을 위한 최선의 접근 방식은 민감한 정보나 사용자 개인정보에 액세스 하는 API의 사용을 최소화하는 것입니다. 사용자 데이터에 액세스 하지만 그 데이터를 저장하거나 전송하지 않아도 된다면 데이터를 저장하거나 전송하면 안 됩니다. 해시 또는 비가역 형태의 데이터를 사용하여 애플리케이션 로직을 구현할 수 있는 방법이 있는지 고려해 보세요. 예를 들어 애플리케이션에서 이메일 주소의 해시를 기본 키로 사용하여 이메일 주소의 전송이나 저장을 방지할 수도 있습니다. 이렇게 하면 실수로 데이터를 노출할 가능성이 줄어들고 공격자가 애플리케이션 악용을 시도할 가능성도 줄어듭니다.

애플리케이션에서 비밀번호나 사용자 이름과 같은 개인정보에 액세스하는 경우, 관할권에 따라 데이터 사용 및 저장에 대해 설명하는 개인정보처리 방침을 제공해야 할 수 있습니다. 또한 사용자 데이터에 대한 액세스를 최소화하는 보안 권장사항을 따르면 규정 준수를 간소화할 수 있습니다.

애플리케이션이 다른 타사(예: 광고용 타사 구성요소나 애플리케이션에서 사용하는 타사 서비스)에 개인정보를 실수로 노출할 수 있는지도 고려해야 합니다. 구성요소나 서비스에서 개인정보를 요구하는데 그 이유를 모르는 경우 정보를 제공해서는 안 됩니다. 일반적으로 애플리케이션의 개인정보 액세스를 줄이면 여기에서 문제가 일어날 가능성도 줄어듭니다.

앱에서 민감한 정보에 액세스해야 하는 경우 이 정보를 서버에 전송해야 하는지 또는 클라이언트에서 작업을 실행할 수 있는지 평가해야 합니다. 사용자 데이터 전송을 방지하려면 민감한 정보를 사용하는 코드는 클라이언트에서 실행하는 것을 고려해 보세요. 또한 지나치게 관대한 IPC, 누구나 쓸 수 있는 파일, 네트워크 소켓을 통해 기기의 다른 애플리케이션에 사용자 데이터를 실수로 노출하지 않도록 해야 합니다. 지나치게 관대한 IPC는 권한 요청 섹션에서 논의된 것처럼 권한으로 보호되는 데이터 유출의 특수한 사례입니다.

GUID가 필요한 경우 크고 고유한 숫자를 만들어 저장하세요. 전화번호나 IMEI와 같은 전화 식별자는 개인정보와 연결될 수 있으므로 사용하면 안 됩니다. 이 주제는 Android 개발자 블로그에 자세하게 설명되어 있습니다.

기기 내 로그에 쓸 때 주의하세요. Android에서는 로그가 공유 리소스이며 READ_LOGS 권한이 있는 애플리케이션에서 사용할 수 있습니다. 전화 로그 데이터는 일시적이며 재부팅 시 삭제된다고 해도 사용자 정보의 부적절한 기록으로 인해 사용자 데이터를 실수로 다른 애플리케이션에 유출할 수 있습니다. PII 로깅을 하지 않는 것뿐만 아니라 프로덕션 앱에서는 로그 사용을 제한해야 합니다. 이를 간단히 구현하려면 디버그 플래그와 맞춤 Log 클래스를 쉽게 구성할 수 있는 로깅 수준으로 사용하세요.

 

#. WebView 사용

WebView는 HTML과 자바스크립트를 포함할 수 있는 웹 콘텐츠를 사용하기 때문에, 부적절한 사용 시 교차 사이트 스크립팅(자바스크립트 삽입)과 같은 일반적인 웹 보안 문제를 일으킬 수 있습니다. Android에는 WebView의 기능을 애플리케이션에서 필요로 하는 최소한의 기능으로 제한하여 이러한 문제가 발생할 가능성을 줄이는 다양한 메커니즘이 포함되어 있습니다.

애플리케이션이 WebView에서 자바스크립트를 직접 사용하지 않는 경우 setJavaScriptEnabled()를 호출하면 안 됩니다. 일부 샘플 코드에서 이 메서드를 사용하며, 이를 프로덕션 애플리케이션에서 변형하여 활용할 수 있으므로 필요하지 않다면 해당 메서드 호출을 삭제하세요. 기본적으로 WebView는 자바스크립트를 실행하지 않기 때문에 교차 사이트 스크립팅이 불가능합니다.

addJavaScriptInterface()를 사용할 경우 자바스크립트에서 일반적으로 Android 애플리케이션에 예약된 작업을 호출할 수 있기 때문에 특별히 주의해야 합니다. 사용할 때는 모든 입력을 신뢰할 수 있는 웹페이지에만 addJavaScriptInterface()를 노출하세요. 신뢰할 수 없는 입력이 허용되면 신뢰할 수 없는 자바스크립트가 앱에서 Android 메서드를 호출할 수 있습니다. 일반적으로 애플리케이션 APK에 포함된 자바스크립트에만 addJavaScriptInterface()를 노출하는 것이 좋습니다.

애플리케이션에서 WebView를 사용하여 민감한 정보에 액세스하는 경우 로컬에 저장된 파일을 삭제하기 위해 clearCache() 메서드를 사용할 수 있습니다. no-cache와 같은 서버 측 헤더를 사용해 애플리케이션이 특정 콘텐츠를 캐시하면 안 된다는 것을 나타낼 수도 있습니다.

Android 4.4(API 레벨 19) 이전의 플랫폼을 실행하는 기기에서는 다양한 보안 문제가 있는 webkit 버전을 사용합니다. 이를 해결하려면 이러한 기기에서 앱이 실행 중인 경우 WebView 개체가 신뢰할 수 있는 콘텐츠만 표시하는지 확인해야 합니다. 앱에서 SSL의 잠재적 취약점에 노출되지 않도록 하려면 SSL 악용을 차단하기 위한 보안 제공자 업데이트에 설명된 대로 업데이트 가능한 보안 Provider 개체를 사용합니다. 애플리케이션에서 오픈 웹의 콘텐츠를 렌더링해야 하는 경우 최신 보안 패치로 최신 상태를 유지할 수 있도록 자체 렌더러를 제공해 보세요.

 

#. 사용자 인증 정보 처리

피싱 공격을 더 눈에 띄게 하고 성공 가능성을 낮추려면 사용자 인증 정보를 묻는 빈도를 최소화합니다. 그 대신 승인 토큰을 사용하고 새로고침 하세요.

가능한 경우 사용자 이름과 비밀번호를 기기에 저장하면 안 됩니다. 대신 사용자가 제공한 사용자 이름과 비밀번호를 사용하여 초기 인증을 시행한 다음 서비스별 단기 승인 토큰을 사용하세요.

여러 애플리케이션에서 액세스 할 수 있는 서비스는 AccountManager를 사용해 액세스해야 합니다. 가능하면 AccountManager 클래스를 사용해 클라우드 기반 서비스를 호출하며, 기기에 비밀번호를 저장하면 안 됩니다.

AccountManager를 통해 Account를 검색한 후에는 사용자 인증 정보를 실수로 잘못된 애플리케이션에 전달하지 않도록 사용자 인증 정보에 전달하기 전에 CREATOR를 사용합니다.

자신이 만든 애플리케이션에서만 사용자 인증 정보를 사용하는 경우 checkSignature()를 사용해 AccountManager에 액세스 하는 애플리케이션을 확인할 수 있습니다. 또는 하나의 애플리케이션에서만 사용자 인증 정보를 사용하는 경우 KeyStore를 사용하여 저장할 수도 있습니다.

 

#. 암호화 사용

Android에서는 데이터 격리 제공, 전체 파일 시스템 암호화 지원, 안전한 통신 채널 제공 외에도 암호화를 사용하여 데이터를 보호하기 위한 다양한 알고리즘을 제공합니다.

일반적으로 소프트웨어에서 어떤 자바 암호화 아키텍처(JCA) 보안 제공업체를 사용하는지 알아야 합니다. 사용 사례를 지원할 수 있는 기존 프레임워크 구현 중 최고 수준을 사용해 보세요. 해당되는 경우 Google 지원 제공업체를 Google에서 지정한 순서대로 사용하세요. 알려진 위치에서 파일을 안전하게 검색해야 하는 경우 간단한 HTTPS URI로 충분하며 암호화 지식은 필요하지 않습니다. 안전한 터널이 필요한 경우 자체적으로 프로토콜을 작성하는 것보다 HttpsURLConnection 또는 SSLSocket을 사용하는 것이 좋습니다. SSLSocket을 사용하는 경우 호스트 이름 확인을 시행하지 않으니 유의하세요. SSLSocket 직접 사용에 대한 경고를 참조하세요.

자체 프로토콜을 구현해야 하는 경우 암호화 알고리즘을 직접 구현해서는 안 됩니다. Cipher 클래스에 제공되는 AES 및 RSA 구현과 같은 기존 암호화 알고리즘을 사용하세요. 또한 다음 권장사항을 따라야 합니다.

▶ 상업적 목적에는 256비트 AES를 사용합니다 (사용할 수 없는 경우 128비트 AES 사용).

▶ 타원 곡선(EC) 암호화에는 224비트 또는 256비트 공개 키 크기를 사용합니다.

▶ CBC, CTR 또는 GCM 차단 모드를 언제 사용해야 하는지 파악합니다.

▶ CTR 모드에서 IV/카운터를 재사용하면 안 됩니다. 암호가 무작위로 생성되는지 확인해야 합니다.

▶ 암호화를 사용할 때는 다음 함수 중 하나로 CBC 또는 CTR 모드를 사용해 무결성을 구현합니다.

▶ HMAC-SHA1

▶ HMAC-SHA-256

▶ HMAC-SHA-512

▶ GCM 모드

안전한 랜덤 숫자 생성기인 SecureRandom을 사용하여 KeyGenerator에서 생성된 암호화 키를 초기화하세요. 안전한 랜덤 숫자 생성기로 생성되지 않은 키를 사용하면 알고리즘의 강도가 크게 약해지고 오프라인 공격을 허용할 수 있습니다.

반복하여 사용하기 위해 키를 저장해야 한다면 암호화 키의 장기간 보관 및 검색을 위한 메커니즘을 제공하는 KeyStore와 같은 메커니즘을 사용하세요.

 

#. 프로세스 간 통신 사용

일부 앱에서는 네트워크 소켓 및 공유 파일과 같은 기존 Linux 기술을 사용하여 IPC를 구현하려고 합니다. 하지만 Service 및 BroadcastReceiver와 함께 IntentBinder 또는 Messenger와 같은 IPC용 Android 시스템 기능을 대신 사용해야 합니다. Android IPC 메커니즘을 사용하면 IPC에 연결하는 애플리케이션의 ID를 확인하고 각 IPC 메커니즘에 보안 정책을 설정할 수 있습니다.

보안 요소의 상당수는 IPC 메커니즘 간에 공유됩니다. 사용 중인 IPC 메커니즘을 다른 애플리케이션에서 사용하려는 경우가 아니라면 <service> 요소와 같은 구성요소의 매니페스트 요소에 android:exported속성을 false로 설정합니다. 이는 동일한 UID 내 여러 프로세스로 구성된 애플리케이션 또는 개발 막바지에 실제로 이 기능을 IPC로 노출하지 않으려고 했으나 코드를 재작성하지 않으려는 경우에 유용합니다.

다른 애플리케이션에서 IPC에 액세스 할 수 있는 경우 <permission> 요소를 사용해 보안 정책을 적용할 수 있습니다. 동일한 키로 서명된 별도의 자체 앱 간에 IPC가 있는 경우 android:protectionLevel에 signature 수준 권한을 사용하는 것이 좋습니다.

 

#. 인텐트 사용

Activity 및 broadcast receiver에서 인텐트는 Android의 비동기 IPC에 선호되는 메커니즘입니다. 애플리케이션 요구사항에 따라 특정 애플리케이션 구성요소에 sendBroadcast()sendOrderedBroadcast() 또는 명시적 인텐트를 사용할 수 있습니다. 보안을 위해 명시적 인텐트가 선호됩니다.

★ 주의: 인텐트를 사용해 Service에 결합하는 경우 명시적 인텐트를 사용하여 앱이 안전한지 확인하세요. 암시적 인텐트를 사용하여 서비스를 시작하면 어떤 서비스가 인텐트에 응답할지 확신할 수 없고 어떤 서비스가 시작하는지 사용자가 알 수 없으므로 보안 위험이 있습니다. Android 5.0(API 레벨 21)부터는 암시적 인텐트로 bindService()를 호출하면 시스템에서 예외가 발생합니다.

순서가 정해진 브로드캐스트는 수신자가 소비할 수 있으므로 일부 애플리케이션에 전달되지 않을 수 있습니다. 특정 수신자에게 전달되어야 하는 인텐트를 전송하는 경우 이름을 기준으로 수신자를 선언하는 명시적 인텐트를 사용해야 합니다.

인텐트 전송자는 메서드 호출로 Null이 아닌 권한을 지정하여 수신자가 권한을 보유하고 있음을 확인할 수 있습니다. 이 권한이 있는 애플리케이션만 인텐트를 수신합니다. 브로드캐스트 인텐트 내의 데이터가 민감한 정보인 경우 악성 애플리케이션이 적절한 권한 없이 이 메시지를 수신하도록 등록하지 못하게 보장하는 권한 적용을 고려해야 합니다. 이러한 상황에서는 브로드캐스트를 제기하는 대신 수신자를 직접 호출해 보는 것도 좋습니다.

★ 참고: 보안 기능으로 인텐트 필터를 고려해서는 안 됩니다. 구성요소는 명시적 인텐트로 호출될 수 있으며, 구성요소에 인텐트 필터를 준수하는 데이터가 없을 수 있습니다. 호출된 수신자, 서비스 또는 활동에 맞춰 적절하게 형식이 지정되어 있는지 확인하려면 인텐트 수신자에서 입력 유효성 검사를 시행하세요.

 

#. 서비스 사용

Service는 다른 애플리케이션에서 사용할 기능을 제공하는 데 주로 사용됩니다. 각 서비스 클래스에는 해당하는 <service> 선언이 매니페스트 파일에 있어야 합니다.

기본적으로 서비스는 내보낼 수 없으며 다른 애플리케이션에서 호출할 수 없습니다. 하지만 서비스 선언에 인텐트 필터를 추가하는 경우 기본적으로 내보내 집니다. 원하는 대로 작동하게 하려면 android:exported속성을 명시적으로 선언하는 것이 가장 좋습니다. 또한 android:permission 속성을 사용하여 서비스를 보호할 수 있습니다. 이 속성을 사용하면 다른 애플리케이션에서 관련 <uses-permission> 요소를 자체 매니페스트에 선언해야 서비스를 시작 또는 중지하거나 서비스에 결합할 수 있습니다.

★ 참고: 앱에서 Android 5.0(API 레벨 21) 이상을 대상으로 하는 경우 JobScheduler를 사용해 백그라운드 서비스를 실행해야 합니다. JobScheduler에 관한 자세한 내용은 API-reference documentation을 참조하세요.

서비스는 호출 구현을 실행하기 전에 checkCallingPermission()을 호출하여 서비스로의 개별 IPC 호출을 권한으로 보호할 수 있습니다. 매니페스트의 선언적 권한은 실수 가능성이 적으므로 이러한 권한을 사용해야 합니다.

★ 주의: 클라이언트와 서버 권한을 혼동하면 안 됩니다. 호출된 앱에 적절한 권한이 있고 호출하는 앱에 동일한 권한을 부여했는지 확인하세요.

 

#. Binder 및 Messenger 인터페이스 사용

Android에서 RPC 스타일 IPC에는 Binder나 Messenger 사용이 선호됩니다. 이 메커니즘은 필요한 경우 엔드포인트 간의 상호 인증을 가능하게 하는 잘 정의된 인터페이스를 제공합니다.

앱 인터페이스는 인터페이스별 권한 확인이 필요 없는 방식으로 설계해야 합니다. Binder와 Messenger개체는 애플리케이션 매니페스트에서 선언되지 않기 때문에 선언적 권한을 직접 적용할 수 없습니다. 이러한 개체는 대개 권한이 구현된 Service 또는 Activity에 대해 애플리케이션 매니페스트에 선언된 권한을 상속합니다. 인증이나 액세스 제어가 필요한 인터페이스를 만드는 경우 Binder 또는 Messenger 인터페이스에 명시적으로 이러한 제어를 코드로 추가해야 합니다.

액세스를 제어해야 하는 인터페이스를 제공하는 경우 checkCallingPermission()을 사용해 호출자에게 필요한 권한이 있는지 확인합니다. 애플리케이션의 ID가 다른 인터페이스에 전달되므로 호출자를 대신하여 서비스에 액세스 하기 전에 이 과정이 특히 중요합니다. Service에서 제공한 인터페이스를 호출하는 경우 해당 서비스에 액세스 할 권한이 없다면 bindService()를 호출하지 못할 수 있습니다. 자체 애플리케이션에서 로컬로 제공되는 인터페이스를 호출하는 경우 내부 보안 확인을 충족하려면 앱의 권한에서 호출자 권한을 숨기는 clearCallingIdentity() 메서드를 사용하는 것이 유용할 수 있습니다. 나중에 restoreCallingIdentity() 메서드를 사용해 호출자 권한을 복원할 수 있습니다.

서비스로 IPC를 실행하는 방법에 관한 자세한 내용은 바인드된 서비스를 참조하세요.

 

#. Broadcast receiver 사용

BroadcastReceiver는 Intent에서 시작한 비동기식 요청을 처리합니다.

기본적으로 수신자는 내보내 지며 다른 애플리케이션에서 호출할 수 있습니다. 다른 애플리케이션에서 BroadcastReceiver를 사용하려는 경우 애플리케이션 매니페스트에 <receiver> 요소를 사용하여 보안 권한을 수신자에 적용하는 것이 좋습니다. 이렇게 하면 적절한 권한이 없는 애플리케이션이 BroadcastReceiver에 인텐트를 보낼 수 없습니다.

 

#. 동적으로 코드 로드

애플리케이션 APK 외부에서 코드를 로드하지 않는 것이 좋습니다. 외부에서 코드를 로드하면 코드 삽입이나 코드 조작으로 인해 애플리케이션이 손상될 가능성이 크게 높아집니다. 또한 버전 관리와 애플리케이션 테스트가 더욱 복잡해지며, 애플리케이션의 동작을 확인할 수 없으므로 일부 환경에서 금지될 수 있습니다.

애플리케이션에서 코드를 동적으로 로드하는 경우 명심할 가장 중요한 점은, 동적으로 로드되는 코드는 애플리케이션 APK와 동일한 보안 권한을 가지고 실행된다는 점입니다. 사용자는 개발자의 ID에 근거하여 애플리케이션 설치를 결정하며, 동적으로 로드되는 코드를 비롯하여 애플리케이션에서 실행되는 모든 코드를 개발자가 제공하리라 기대합니다.

동적으로 로드하는 코드와 관련된 중대한 보안 위험은 확인 가능한 소스에서 코드가 제공되어야 한다는 것입니다. 모듈이 APK에 직접 포함되어 있으면 다른 애플리케이션에서 모듈을 수정할 수 없습니다. 이는 코드가 네이티브 라이브러리든, DexClassLoader를 사용하여 로드되는 클래스든 마찬가지입니다. 많은 애플리케이션에서는 암호화되지 않은 프로토콜을 통한 네트워크나 외부 저장소와 같이 누구나 쓸 수 있는 위치에서 다운로드된 코드 등 안전하지 않은 위치에서 코드를 로드하려고 시도합니다. 이러한 위치에서는 네트워크 사용자가 전송 중인 콘텐츠를 수정하거나 사용자 기기의 다른 애플리케이션이 기기 콘텐츠를 수정할 수 있습니다.

 

#. 가상 머신의 보안

Dalvik은 Android의 런타임 가상 머신(VM)입니다. Dalvik은 특별히 Android용으로 제작되었지만 다른 가상 머신의 보안 코드와 관련한 우려사항이 Android에도 상당 부분 적용됩니다. 일반적으로는 가상 머신과 관련된 보안 문제는 염려하지 않아도 됩니다. 애플리케이션은 안전한 샌드박스 환경에서 실행되므로 시스템의 다른 프로세스에서 코드나 비공개 데이터에 액세스 할 수 없습니다.

가상 머신 보안에 관해 자세히 알아보려면 이 주제에 관한 기존의 몇 가지 자료를 확인하세요. 다음은 가장 인기 있는 두 가지 리소스입니다.

▶ 자바 보안 설정

▶ 관련 타사 프로젝트

이 문서에서는 Android와 관련이 있거나 기타 VM 환경과는 다른 영역에 대해 주로 다룹니다. 다른 환경에서 VM 프로그래밍을 경험한 개발자의 경우 Android용 앱 작성과 관련하여 크게 두 가지 문제가 있을 수 있습니다.

▶ JVM이나. NET 런타임과 같은 일부 가상 머신은 코드를 기본 운영체제 기능과 분리하는 보안 경계 역할을 합니다. Android의 경우, Dalvik VM은 보안 경계가 아닙니다. 애플리케이션 샌드박스가 OS 수준에서 구현되기 때문에 Dalvik은 보안 제약 없이 동일한 애플리케이션의 네이티브 코드와 상호 운용될 수 있습니다.

▶ 휴대기기의 제한된 저장용량을 고려할 때 개발자는 일반적으로 모듈식 애플리케이션을 빌드하고 동적 클래스 로드를 사용하고자 합니다. 이렇게 하는 경우 애플리케이션 로직을 검색하는 소스와 이를 로컬로 저장하는 위치를 모두 고려하시기 바랍니다. 안전하지 않은 네트워크 소스나 외부 저장소와 같이 확인되지 않은 소스에서는 동적 클래스를 로드하면 안 됩니다. 악의적인 동작을 포함하도록 코드가 수정될 수 있기 때문입니다.

 

#. 네이티브 코드의 보안

일반적으로 애플리케이션 개발에는 Android NDK와 함께 네이티브 코드를 사용하는 것이 아니라 Android SDK를 사용해야 합니다. 네이티브 코드로 빌드된 애플리케이션은 더 복잡하고, 이동성이 떨어지며, 버퍼 오버플로우와 같은 일반적인 메모리 손상 오류가 포함될 가능성이 높습니다.

Android는 Linux 커널을 사용해 빌드되었으며, Linux 개발 보안 권장사항에 익숙하면 네이티브 코드를 사용하는 경우 특히 유용합니다. Linux 보안 권장사항으로는 이 문서의 범위를 벗어나지만, 널리 사용되는 리소스 중 하나인 안전한 프로그래밍 방법 - 안전한 소프트웨어 만들기가 있습니다.

Android와 대부분의 Linux 환경 간의 중요한 차이점은 애플리케이션 샌드박스입니다. Android에서는 네이티브 코드로 작성된 애플리케이션을 비롯한 모든 애플리케이션이 샌드박스에서 실행됩니다. 가장 기본적인 수준에서 Linux에 익숙한 개발자가 이에 대해 생각해 볼 수 있는 좋은 방법은 모든 애플리케이션에 매우 제한된 권한이 있는 고유 UID가 부여된다는 사실을 아는 것입니다. 이 내용은 Android 보안 개요에서 자세히 다루며, 개발자라면 네이티브 코드를 사용하는 경우에도 애플리케이션 권한에 익숙해져야 합니다.

 

원본 링크 : https://developer.android.com/training/articles/security-tips

반응형
반응형

이번 포스팅은 FileProvider를 사용하여 파일 공유하는 방법에 대하여 알아보도록 하겠습니다.


1. FileProvider 란 


ContentProvider는 데이터를 캡슐화하여 다른 응용 프로그램에 제공하는 Android 구성 요소입니다. 여러 응용 프로그램간에 데이터를 공유해야하는 경우에만 필요합니다. 예를 들어 연락처 데이터는 ContentProvider의 하위 클래스 인 ContactsProvider를 사용하여 다른 응용 프로그램과 공유됩니다.

FileProvider는 ContentProvider의 하위 클래스입니다. ContentProvider는 모든 종류의 데이터를 안전하게 공유 할 수있는 구성 요소이지만 FileProvider는 특히 앱의 내부 파일을 공유하는 데 사용됩니다. FileProvider 클래스는 v4 지원 라이브러리의 일부이므로 프로젝트에 포함시켜야합니다.

FileProvider가 작동하도록하려면 다음 세 단계를 수행하십시오.

    ▶ AndroidManifest 파일에서 FileProvider 정의

    ▶ FileProvider가 다른 응용 프로그램과 공유 할 모든 경로가 포함 된 XML 파일을 만듭니다.

    ▶ Intent에 유효한 URI를 번들로 묶어 활성화


2. FileProvider 정의


FileProvider 정의

AndroidManifest 내에서 FileProvider를 정의하려면 다음 속성 및 요소에 익숙해야합니다.

    ▶ android : authorities

    ▶ android : exported

    ▶ android : grantUriPermissions

    ▶ android : name

    ▶ <meta-data> subelement

이들 모두가 매우 친숙해 보인다면 FileProvider를 둘러 보는 방법이 약간 쉬울 것입니다. 그렇지 않으면 각 속성과 그 목적에 대한 자세한 설명을 준비했습니다.

android : authorities

적어도 하나의 고유 권한을 반드시 정의합니다. Android 시스템은 모든 제공자의 목록을 유지하며 권한별로 이를 구분합니다. 권한은 애플리케이션 ID가 Android 애플리케이션을 정의하는 것처럼 FileProvider를 정의합니다.

일반적으로 Android 시스템은 ContentProviders에 특정 URI 체계를 사용합니다. 체계는 content : // <authority> / <path>로 정의 되므로 시스템은 URI의 권한을 ContentProvider의 권한과 일치시켜 어떤 ContentProvider가 요청되는지 알 수 있습니다.


android : exported

이 속성은 이름이 잘못되어 쉽게 오용 될 수 있습니다. 이 속성을 이해하려면 FileProvider를 door가 잠긴 방으로 생각하십시오. 값을 true로 설정하면 기본적으로 모든 사람에게 문이 열립니다. 모든 것이 귀하의 관점에서 작동하지만 다른 모든 앱이 권한을 부여받지 않고 FileProvider를 사용할 수 있기 때문에 방금 큰 보안 문제가 발생했습니다.

이를 통해 우연의 일치로 프로그램하지 말고 항상 코드의 부작용을 인식 할 수 있습니다. 또한 SDK 16 이하의 기본값이 true 이므로 항상이 속성을 정의하십시오 .


android : grantUriPermissions

FileProvider를 잠긴 방으로 계속 생각하면이 속성은 외부 앱에 임시 일회성 키를 제공하는 데 사용됩니다. 이 속성을 사용하면 앱의 내부 저장소를 안전하게 공유 할 수 있습니다. FLAG_GRANT_READ_URI_PERMISSION 또는 FLAG_GRANT_WRITE_URI_PERMISSION을 구성 요소를 활성화하여 앱의 내부 파일을 여는 의도에 추가하기 만하면됩니다. 이 플래그를 사용하려면 해당 값을 true로 설정하십시오 .

<provider> 요소는 <grant-uri-permission> 하위 요소도 가질 수 있습니다. 유일한 차이점은이 속성을 사용하면 앱의 내부 저장소 내에서 무엇이든 공유 할 수 있고 하위 요소를 사용하면 공유 할 특정 데이터 하위 집합을 선택할 수 있다는 것입니다. 하위 요소를 대신 사용하려면 값을 false로 설정하십시오 .

<메타 데이터> 하위 요소

파일 경로 XML 생성

FileProvider를 사용할 때이 하위 요소를 정의해야합니다. FileProvider가 외부 앱과 공유 할 수있는 모든 데이터 경로가 포함 된 XML 파일의 경로를 정의해야합니다.

XML 파일에는 루트로 <paths> 요소가 있어야합니다. <paths> 요소에는 다음 중 하나 일 수있는 하나 이상의 하위 요소가 있어야합니다.

    <files-path />-내부 앱 스토리지, Context # getFilesDir ()

    <cache-path />-내부 앱 캐시 스토리지, Context # getCacheDir ()

    <external-path />-공용 외부 저장소, Environment.getExternalStorageDirectory ()

    <external-files-path />-외부 앱 스토리지, 컨텍스트 #getExternalFilesDir (null)

    <external-cache-path />-외부 앱 캐시 스토리지, 컨텍스트 #getExternalCacheDir ()

그것들은 그들이 정의한 앱의 디렉토리에 따라 다르다는 것을 알았을 것입니다.

각 요소에는 경로와 이름 속성이 있어야합니다. path 속성은 공유하려는 서브 디렉토리를 정의하며 와일드 카드를 지원 하지 않습니다 . name 속성은 보안상의 이유로 사용되며 하위 디렉토리 이름을 해당 값으로 대체합니다.

안드로이드 : 이름

이 값을 android.support.v4.content.FileProvider로 설정했습니다 .

번들 유효 URI

AndroidManifest 파일에 FileProvider를 정의하면 사용할 준비가 된 것입니다. 파일을 공유하려면 인 텐트를 작성하고 유효한 URI를 제공해야합니다. URI는 FileProvider 클래스를 사용하여 생성됩니다.

코드 구현

AndroidManifest.xml

<provider
    android:name="android.support.v4.content.FileProvider"
    android:grantUriPermissions="true"
    android:exported="false"
    android:authorities="${applicationId}">

    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_provider_paths"/>

</provider>

권한을 위해 앱 ID를 사용하고 있습니다. 프로젝트에 여러 가지 특징이 있으며 동시에 장치에 설치할 수 있기 때문입니다. Android 시스템에서는 동일한 FileProvider로 여러 응용 프로그램을 설치할 수 없으므로 각 기능마다 고유 한 권한이 필요합니다.

file_provider_paths.xml

<paths>
    <cache-path name="cache" path="/" />
    <files-path name=”files” path=”/” />
</paths>

이와 같은 경로를 정의함으로써 FileProvider가 앱의 내부 캐시 및 파일 디렉토리에있는 모든 파일을 공유 할 수 있습니다.

FileProvider 사용

// create new Intent
Intent intent = new Intent(Intent.ACTION_VIEW);

// set flag to give temporary permission to external app to use your FileProvider
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

// generate URI, I defined authority as the application ID in the Manifest, the last param is file I want to open
String uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID, file);

// I am opening a PDF file so I give it a valid MIME type
intent.setDataAndType(uri, "application/pdf");

// validate that the device can open your File!
PackageManager pm = getActivity().getPackageManager();
if (intent.resolveActivity(pm) != null) {
    startActivity(intent);
}

작동 방식을 이해하면 고유 한 FileProvider를 구현하는 것이 매우 간단합니다.

문제의 복잡성은 코드 자체가 아니라 모든 것이 상호 연결되는 방법에 대한 문서와 이해입니다. 이 기사가 자신의 유스 케이스에 FileProvider를 구현하고 공식 문서를 읽기 쉽게 만드는 데 도움이되기를 바랍니다.


https://infinum.co/the-capsized-eight/share-files-using-fileprovider

반응형
반응형

동작 변경사항: 모든 앱

- Android 9(API 레벨 28)에서는 Android 시스템에 많은 변경사항이 도입됩니다. 다음과 같은 동작 변경사항은 Android 9 플랫폼에서 실행되는 모든 앱에 적용되며, 대상으로 하는 API 레벨과는 상관이 없습니다. 모든 개발자는 이러한 변경사항을 검토해야 하며 이를 적절히 지원하도록 앱을 수정해야 합니다.

- API 레벨 28 이상을 대상으로 하는 앱에만 영향을 미치는 변경사항의 경우, 동작 변경사항: API 레벨 28+를 대상으로 하는 앱을 참조하세요.

 

1. 전원 관리



- Android 9에서는 기기 전원 관리를 개선하기 위한 새로운 기능을 소개합니다. 이러한 변경사항은 Android 9 이전에 이미 있는 기능들과 더불어, 가장 필요한 앱에 시스템 리소스가 분배되도록 보장합니다.

- 자세한 내용은 전원 관리를 참조하세요.

 
2. 개인정보 보호정책 변경사항



-  Android 9은 사용자 개인정보 보호를 강화하기 위해 여러 가지 동작 변경사항을 적용합니다. 예를 들어, 백그라운드 앱의 기기 센서 액세스를 제한하고, Wi-Fi 스캔으로 검색되는 정보를 제한하고, 전화 통화, 전화 상태, Wi-Fi 스캔과 관련하여 새로운 권한 규칙과 권한 그룹을 적용합니다.

- 이러한 변경사항은 대상 SDK 버전과 무관하게 Android 9을 실행하는 모든 앱에 영향을 미칩니다.


# 백그라운드에서 센서 액세스 제한

- Android 9에서는 백그라운드 앱이 사용자 입력과 센서 데이터에 액세스하는 능력을 제한합니다. Android 9이 실행되는 기기에서 앱이 백그라운드로 실행 중인 경우, 시스템은 다음과 같은 제한을 앱에 적용합니다.

    * 앱이 마이크나 카메라에 액세스할 수 없습니다.

    * 연속 보고 모드를 사용하는 센서(예: 가속도계 및 자이로스코프)는 이벤트를 수신하지 않습니다.

    * 변경 시 또는 원샷 보고 모드를 사용하는 센서는 이벤트를 수신하지 않습니다.

- Android 9이 실행되는 기기에서 앱이 센서 이벤트를 감지해야 하는 경우, 포그라운드 서비스를 사용하세요.



# 통화 로그 액세스 제한

- Android 9에서는 CALL_LOG 권한 그룹을 도입하고 READ_CALL_LOG, WRITE_CALL_LOG 및PROCESS_OUTGOING_CALLS 권한을 이 그룹으로 이동합니다. 이전의 Android 버전에서 이 권한들은PHONE 권한 그룹에 위치했습니다.

- 이 CALL_LOG 권한 그룹은 사용자가 앱에서 전화 통화 기록을 보고 전화번호를 식별하는 등과 같이 전화 통화와 관련된 민감한 정보에 액세스하는 데 필요한 강화된 제어 능력과 가시성을 제공합니다.

- 앱에서 통화 로그에 액세스해야 하거나 발신 통화를 처리해야 할 경우 CALL_LOG 권한 그룹으로부터 명시적으로 이 권한을 요청해야 합니다. 그렇지 않으면 SecurityException이 발생합니다.

[참고] 이런 권한은 그룹이 변경되어 런타임에 부여되므로 사용자가 앱에서 전화 통화 기록 정보에 액세스하지 못하도록 거부할 수 있습니다. 이 경우 앱이 정보에 액세스하지 못하더라도 이를 적절히 처리할 수 있어야 합니다.

- 앱이 이미 런타임 권한 모범 사례를 준수하고 있다면 권한 그룹의 변경을 처리할 수 있습니다.



# 전화번호 액세스 제한

- Android 9에서 실행되는 앱은 사용 사례에 필요한 다른 권한 외에도 먼저 READ_CALL_LOG 권한을 얻어야 전화번호 또는 전화 상태를 읽을 수 있습니다.

- 수신 및 발신 통화와 관련된 전화번호는 수신 전화 및 발신 전화 등에 대한 전화 상태 브로드캐스트 에서 확인할 수 있고 PhoneStateListener 클래스에서 액세스할 수 있습니다. 그러나 READ_CALL_LOG 권한이 없으면 PHONE_STATE_CHANGED 브로드캐스트와 PhoneStateListener를 통해 제공되는 전화번호 필드가 비어 있습니다.

- 전화 상태에서 전화번호를 읽으려면 사용 사례에 따라 필요한 권한을 요청하도록 앱을 업데이트하십시오.

    * PHONE_STATE인텐트 액션에서 전화번호를 읽으려면 READ_CALL_LOG 권한과READ_PHONE_STATE 권한이 모두 필요합니다.

    * onCallStateChanged()에서 전화번호를 읽으려면 READ_CALL_LOG 권한만 필요합니다.READ_PHONE_STATE 권한은 필요 없습니다.


# Wi-Fi 위치 및 연결 정보 액세스 제한

- Android 9은 이전 버전보다 앱이 Wi-Fi를 스캔하는 데 필요한 권한 요구사항이 엄격해졌습니다. 자세한 내용은 Wi-Fi 스캔 제한을 참조하세요.

- 유사한 제한이 getConnectionInfo() 메서드에도 적용됩니다. 이 메서드는 현재 Wi-Fi 위치를 설명하는 WifiInfo 객체를 반환합니다. 호출하는 앱에 다음과 같은 권한이 있을 경우 이 객체의 메소드만 사용하여 SSID 및 BSSID 값을 검색할 수 있습니다.

    * ACCESS_FINE_LOCATION 또는 ACCESS_COARSE_LOCATION

    * ACCESS_WIFI_STATE

- SSID 또는 BSSID를 검색하려면 기기에서 위치 서비스가 활성화되어 있어야 합니다(Settings > Location 아래).


# Wi-Fi 서비스 메서드에서 정보 삭제

- Android 9에서 다음 이벤트와 브로드캐스트는 사용자 위치 또는 개인 식별 데이터와 관련된 정보를 수신하지 않습니다.

    * WifiManager의 getScanResults() 와 getConnectionInfo() 메서드.

    * WifiP2pManager의 discoverServices() 와 addServiceRequest() 메서드.

    * NETWORK_STATE_CHANGED_ACTION 브로드캐스트.

- Wi-Fi의 NETWORK_STATE_CHANGED_ACTION 시스템 브로드캐스트에는 SSID(이전의 EXTRA_SSID), BSSID (이전의 EXTRA_BSSID) 또는 연결 정보(이전의 EXTRA_NETWORK_INFO)가 포함되지 않습니다. 앱에 이 정보가 필요하면 대신 getConnectionInfo()를 호출하세요.


# 기기 위치 설정에 따라 전화 정보 제공


- 사용자가 Android 9이 실행되는 기기에서 기기 위치를 비활성화했다면 다음의 메서드는 결과를 제공하지 않습니다.

    * getAllCellInfo()

    * listen()

    * getCellLocation()

    * getNeighboringCellInfo()         

                                 

3. 비 SDK 인터페이스 사용에 대한 제한



- 앱 안정성과 호환성을 보장하기 위해 플랫폼에서는 일부 비 SDK 메서드와 필드의 사용을 제한합니다. 이러한 제한은 리플렉션을 통해 이들 메서드와 필드에 직접 액세스를 시도하든 아니면 JNI를 사용하든 간에 모두 적용됩니다. Android 9에서는 앱이 이러한 제한된 인터페이스에 계속해서 액세스할 수 있으며, 플랫폼에서는 관심을 끌기 위해 알림 메시지와 로그 항목을 사용합니다. 이러한 알림 메시지가 앱에 나타나는 경우에는, 제한된 인터페이스가 아닌 다른 구현 전략을 추진하는 것이 중요합니다. 대체 전략이 현실성이 없다고 느끼는 경우에는, 해당 제한을 재고하도록 요청하기 위해 버그를 제출할 수도 있습니다.

- 비 SDK 인터페이스에 대한 제한 에는 더욱 중요한 정보가 들어 있습니다. 앱이 제대로 작동하도록 보장하려면 이 제한을 검토해야 합니다.

 

4. 보안 동작 변경사항



# 기기 보안 변경사항

- Android 9은 앱의 대상 버전과는 무관하게 앱의 보안을 개선하는 여러 가지 기능을 추가합니다.



TLS 구현 변경사항

- Android 9에서는 다음과 같이 시스템의 TLS 구현이 여러 차례 변경되었습니다.

    * SSLSocket의 인스턴스가 생성되는 동안 연결에 실패할 경우, 시스템에서 NullPointerException 대신 IOException을 발생시킵니다.

    * 어떤 close_notify 경고가 발생하더라도 SSLEngine 클래스가 이를 깔끔하게 처리합니다.

- Android 앱에서 안전한 웹 요청을 하는 자세한 방법은 HTTPS 예시를 참조하세요.


더욱 엄격해진 SECCOMP 필터

- Android 9에서는 앱에 사용 가능한 시스템 호출을 더욱 엄격히 제한합니다. 이 동작은 Android 8.0(API 레벨 26)에 포함된 SECCOMP 필터의 확장 프로그램입니다.

- 참고: 이 변경사항은 권한을 가진 syscall을 사용하는 앱에만 영향을 미칩니다.


# 암호화 변경사항

- Android 9에서는 암호화 알고리즘의 구현과 처리에 여러 가지 변화가 있습니다.

매개변수 및 알고리즘의 Conscrypt 구현

- Android 9은 Conscrypt에서 알고리즘 매개변수의 추가적인 구현을 제공합니다. 이들 매개변수에는 AES, DESEDE, OAEP 및 EC가 포함됩니다. 이러한 매개변수의 Bouncy Castle 버전과 다수의 알고리즘이 Android 9에서 지원이 중단되었습니다.

- 참고: Conscrypt의 EC 매개변수 구현에서는 명명된 곡선만 지원합니다.

- Android 8.1(API 레벨 27) 이하를 대상으로 하는 앱의 경우, 지원 중단된 알고리즘 중 하나의 Bouncy Castle 구현을 요청하면 경고가 표시됩니다. 그러나 Android 9을 대상으로 하는 경우에는 이러한 요청은 각각 NoSuchAlgorithmException을 발생시킵니다.


# 기타 변경사항

- Android 9에서는 암호화와 관련된 여러 가지 변경사항이 도입됩니다.

  PBE 키를 사용하는 경우, Bouncy Castle이 초기화 벡터(IV)를 예상하는 데 앱이 이것을 제공하지 않으면 경고가 표시됩니다.

    * Conscrypt의 ARC4 암호화 구현에서는 ARC4/ECB/NoPadding 또는 ARC4/NONE/NoPadding을 지정할 수 있습니다.

    * Crypto JCA(Java Cryptography Architecture) 제공자는 제거되었습니다. 그 결과, 앱이  SecureRandom.getInstance("SHA1PRNG", "Crypto")를 호출하면 NoSuchProviderException 이 발생합니다.

    * 앱이 키 구조보다 더 큰 버퍼로부터 RSA 키를 파싱하는 경우, 더 이상 예외가 발생하지 않습니다.

- Android 암호화 기능의 사용 방법에 대한 자세한 내용은 암호화를 참조하세요.


# Android 보안 암호화된 파일은 더 이상 지원되지 않음

- Android 9에서는 Android 보안 암호화 파일(ASEC)에 대한 지원이 완전히 제거됩니다.

- Android 2.2 (API 레벨 8)에서 Android는 SD 카드의 앱 기능을 지원하기 위해 ASEC를 도입했습니다. Android 6.0(API 레벨 23)에서 플랫폼은 개발자가 ASEC 대신 사용할 수 있는 어댑터블 스토리지 기기 기술을 도입했습니다.

 
5. ICU 라이브러리에 대한 업데이트



- Android 9은 ICU 라이브러리의 버전 60을 사용합니다. Android 8.0(API 레벨 26)과 Android 8.1(API 레벨 27)은 ICU 58을 사용합니다.

- ICU는 android.icu package 아래에 공개 API를 제공하는 데 사용하고 내부적으로 Android 플랫폼에서 국제화 지원에 사용합니다. 예를 들어, java.util, java.text 및 android.text.format에서 Android 클래스를 구현하는 데 사용됩니다.

- ICU 60 업데이트에는 ICU 59 및 ICU 60 출시 노트에 설명된 것과 같이 Emoji 5.0 데이터 지원 및 개선된 날짜/시간 형식 등의 사소하면서도 유용한 변경사항이 다수 포함되어 있습니다.

- 이 업데이트에서 특기할 만한 변경사항은 다음과 같습니다.

    * 플랫폼에서 시간대를 처리하는 방식이 변경되었습니다.

* 플랫폼에서 GMT 및 UTC를 더욱 잘 처리하며, UTC는 더 이상 GMT와 동의어가 아닙니다. 이제 ICU는 GMT 및 UTC에 변환된 시간대 이름을 제공합니다. 이러한 변경은 "GMT", "Etc/GMT", "UTC", "Etc/UTC" 및 "Zulu"와 같은 시간대의 android.icu 서식 및 파싱 동작에 영향을 미칩니다.

* 이제 java.text.SimpleDateFormat에서 ICU를 사용하여 UTC /GMT에 표시 이름을 제공합니다. 즉,

    * zzzz 서식은 많은 로케일에 대해 현지화된 긴 문자열을 생성합니다. 이전에는 UTC에 대해 "UTC"를 생성했고 GMT에 대해 "GMT+00:00"와 같은 문자열을 생성했습니다.

    * zzzz 파싱은 "Universal Coordinated Time" 및 "Greenwich Mean Time"과 같은 문자열을 인식합니다.

    * 모든 언어에서 zzzz의 출력이 "UTC" 또는 "GMT+00:00"이라고 가정하는 경우, 앱에서 호환성 문제가 발생할 수도 있습니다.

java.text.DateFormatSymbols.getZoneStrings()의 동작이 다음과 같이 변경되었습니다.

    * 이제 UTC 및 GMT에서 SimpleDateFormat와 같은 긴 이름을 가집니다. UTC 시간대의 DST 변형 시간대 이름(예: "UTC", "Etc/UTC" 및 "Zulu")은 GMT+00:00이 됩니다. 사용 가능한 이름이 없는 경우 이 이름은 하드코딩된 문자열인 UTC 대신 표준 대체 이름이 됩니다.


   * 일부 시간대 ID는 다른 시간대의 동의어로 올바르게 인식되므로, Android는 오래된 시간대 ID에 대한 문자열을 찾습니다(예: Eire). 이전에는 이 문제를 해결할 수 없었습니다.

* 아시아/하노이 시간대는 더 이상 인식되지 않습니다. 이 때문에java.util.TimeZones.getAvailableIds()는 이 값을 반환하지 않으며java.util.TimeZone.getTimeZone()은 이를 인식하지 못합니다. 이 동작은 기존 android.icu 동작과 일치합니다.

android.icu.text.NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String) 메서드의 경우 합법적 통화 텍스트를 파싱할 때에도ParseException이 발생할 수 있습니다. 이 문제를 피하려면 스타일의 통화 텍스트에 NumberFormat.parseCurrency를사용하세요. 이 메서드는 Android 7.0(API 레벨 24) 이후 버전에서PLURALCURRENCYSTYLE 사용할 수 있습니다.


6. Android 테스트 변경사항



- Android 9에서는 Android Test 프레임워크의 라이브러리와 클래스 구조에 여러 변경사항이 도입되었습니다. 이런 변경사항은 개발자가 프레임워크 지원 공개 API를 사용하는 데 도움을 주지만 타사 라이브러리나 맞춤 로직을 사용하여 테스트를 빌드하고 실행할 때 더욱 유연성을 발휘할 수 있게 합니다.

# 프레임워크에서 라이브러리 제거

- Android 9에서는 JUnit 기반 클래스를 android.test.base, android.test.runner, android.test.mock의 세 가지 라이브러리로 재구성했습니다. 이러한 변경으로 인해 프로젝트 종속성과 가장 잘 호환되는 JUnit 버전에 대해 테스트를 실행할 수 있게 되었습니다. 이 JUnit 버전은 android.jar가 제공하는 버전과 다를 수 있습니다.

- JUnit 기반 클래스가 이러한 라이브러리로 구성된 방식과 테스트 작성 및 실행을 위해 앱 프로젝트를 준비하는 방법에 대한 자세한 정보는 Android Test를 위한 프로젝트 설정을 참조하세요.

# 테스트 모음 빌드 변경사항

- TestSuiteBuilder 클래스의 addRequirements() 메서드가 제거되었고 TestSuiteBuilder 클래스가 지원 중단되었습니다. addRequirements() 메서드는 유형이 숨겨진 API인 인수를 개발자가 제공해야 하며, 이 API가 무효화됩니다.


 7. Java UTF 디코더



- UTF-8은 Android의 기본 문자 집합입니다. UTF-8 바이트 시퀀스는 String 생성자(예: String(byte[] bytes))에 의해 디코딩될 수 있습니다.

- Android 9의 UTF-8 디코더는 이전 버전보다 더욱 엄격하게 Unicode 표준 을 준수합니다. 변경사항에는 다음 내용이 포함됩니다.

    * 비최단(non-shortest) 형식의 UTF-8(예: <C0, AF>)은 잘못된 형식으로 간주됩니다.

    * 대리(surrogate) 형식의 UTF-8(예: U+D800..U+DFFF)는 잘못된 형식으로 간주됩니다.

    * 최대 서브파트는 단일 U+FFFD로 대체됩니다. 예를 들어, 바이트 시퀀스 "41 C0 AF 41 F4 80 80 41"에서 최대 서브파트는 "C0," "AF" 및 "F4 80 80"입니다. "F4 80 80"은 "F4 80 80 80"의 초기 서브시퀀스가 될 수 있지만, "C0"은 올바른 형식의 코드 단위 시퀀스의 초기 서브시퀀스가 될 수 없습니다. 따라서 출력은 "A\ufffd\ufffdA\ufffdA"여야 합니다.

    * 수정된 UTF-8 / CESU-8 시퀀스를 Android 9 이상에서 디코딩하려면DataInputStream.readUTF() 메서드나 NewStringUTF() JNI 메서드를 사용하세요.

 

8.  인증서를 사용하여 호스트 이름 확인



- RFC 2818에서는 인증서와 도메인 이름을 일치시키기 위한 두 가지 방법에 대해 설명합니다. 즉, subjectAltName(SAN) 확장 내에 있는 이름을 사용하거나 SAN 확장이 없는 경우 commonName(CN)으로 대체됩니다.

- 그러나 CN으로의 대체는 RFC 2818에서 지원이 중단되었습니다. 이러한 이유로 Android에서는 더 이상 CN을 사용하여 대체할 수 없습니다. 호스트 이름을 확인하기 위해 서버는 일치하는 SAN이 포함된 인증서를 제공해야 합니다. 호스트 이름과 일치하지 않는 SAN이 포함된 인증서는 더 이상 신뢰할 수 없습니다.

 

9. 네트워크 주소 조회 시 네트워크 위반이 발생할 수 있음



- 이름 확인을 요구하는 네트워크 주소 조회에는 네트워크 I/O가 포함될 수 있으며 그러므로 이 조회는 차단 작업으로 간주됩니다. 메인 스레드의 차단 작업은 일시 중지나 버벅거림 현상을 유발할 수 있습니다.

- StrictMode 클래스는 개발자가 코드에서 문제를 감지하도록 도와주는 개발 도구입니다.

- Android 9 이상에서 StrictMode는 이름 확인을 요구하는 네트워크 주소 조회로부터 발생하는 네트워크 위반을 감지합니다.

- StrictMode를 활성화한 상태로 앱을 내보내서는 안 됩니다. 그렇게 할 경우 네트워크 위반을 감지하는 정책을 가져오기 위해 NetworkOnMainThreadException 또는 detectNetwork() 메서드를 사용할 때, 앱에서 detectAll()과 같은 새로운 예외가 발생할 수 있습니다.

- 숫자 IP 주소 확인은 차단 작업으로 간주되지 않습니다. 숫자 IP 주소 확인은 Android 9 이전 버전과 동일하게 작동합니다.

 
10. 소켓 태그 지정



- Android 9보다 낮은 플랫폼 버전에서 setThreadStatsTag() 메서드를 사용하여 소켓에 태그를 다는 경우, 바인더 IPC를 ParcelFileDescriptor 컨테이너와 함께 사용하여 또 다른 프로세스로 전송될 때 이 소켓의 태그가 해제됩니다.

- Android 9 이상에서는 바인더 IPC를 사용하여 또 다른 프로세스로 전송될 때 소켓 태그가 유지됩니다. 이러한 변경은 네트워크 트래픽 통계에 영향을 미칠 수 있습니다(예: queryDetailsForUidTag() 메서드 사용 시).

- 다른 프로세스로 전송한 소켓의 태그를 제거하는 이전 버전의 동작을 유지하고 싶다면 소켓을 전송하기 전에untagSocket()를 호출하세요.

 

11. 소켓에서 사용 가능한 바이트 크기가 보고됨


- shutdownInput() 메서드를 호출한 다음 available() 메서드를 호출하면 0이 반환됩니다.

 

12. VPN에 대해 더욱 상세한 네트워크 성능 보고



- Android 8.1(API 레벨 28) 이하에서 NetworkCapabilities 클래스는 VPNS에 대해 제한된 정보들(예:TRANSPORT_VPN) 보고하고, NET_CAPABILITY_NOT_VPN을 생략했습니다. 정보가 제한되어 있어서 VPN을 사용하면 앱 사용자에게 요금이 발생하는지 확인하기 어려웠습니다. 예를 들어,NET_CAPABILITY_NOT_METERED 체크를 통해 기본 네트워크가 데이터 통신 네트워크인지 여부를 판별할 수 없었습니다.

- Android 9 이상에서는 VPN이 setUnderlyingNetworks() 메서드를 호출할 때 Android 시스템이 기본 네트워크의 전송 및 성능을 병합하고 그 결과를 VPN 네트워크의 유효한 네트워크 성능으로 반환합니다.

- Android 9 이상에서는 NET_CAPABILITY_NOT_METERED를 이미 체크한 앱은 VPN 네트워크와 기본 네트워크의 네트워크 성능 정보를 수신합니다.

 

13. xt_qtaguid 폴더의 파일을 더 이상 앱에 사용할 수 없음



- Android 9부터는 앱이 /proc/net/xt_qtaguid 폴더에 있는 파일을 직접 읽을 수 없게 됩니다. 그 이유는 이러한 파일이 전혀 없는 일부 기기와의 일관성을 유지하기 위해서입니다.

- 이러한 파일을 사용하는 공개 API(예: TrafficStats 및 NetworkStatsManager)는 계속 의도한 대로 작동합니다. 그러나 qtaguid_tagSocket()와 같은 지원되지 않는 cutils 함수는 다른 기기에서 의도한 대로 작동하지 않거나 '전혀' 작동하지 않을 수도 있습니다.

 

14. FLAG_ACTIVITY_NEW_TASK 요구사항이 이제 적용됨



- Android 9에서는 인텐트 플래그 FLAG_ACTIVITY_NEW_TASK를 전달하지 않을 경우 비 액티비티 컨텍스트에서 액티비티를 시작할 수 없습니다. 이 플래그를 전달하지 않고 액티비티를 시작하려고 하면 액티비티가 시작되지 않고, 시스템이 로그에 메시지를 출력합니다.

- 참고: 플래그 요구사항은 언제나 의도된 동작이며, Android 7.0(API 레벨 24) 이전 버전부터 적용되었습니다. Android 7.0의 버그로 인해 플래그 요구사항이 적용되지 않았습니다.

 

15. 화면 회전 변경사항



- Android 9부터 세로 회전 모드가 상당히 변경됩니다. Android 8.0(API 레벨 26)에서 사용자는 Quick Settings 타일이나 Display 설정을 사용하여 자동 회전 및 세로 회전 모드를 서로 전환할 수 있습니다. 세로 모드는 이름이 회전 잠금으로 변경되었고 이 모드는 자동 회전이 꺼진 경우 활성화됩니다. 자동 회전 모드에는 변화가 없습니다.

- 기기가 회전 잠금 모드에 있는 경우, 사용자가 맨 위에 보이는 Activity에 의해 지원되는 회전으로 화면을 잠글 수 있습니다. Activity가 항상 세로 모드로 렌더링될 것이라고 가정해서는 안됩니다. 자동 회전 모드에서 맨 위 Activity가 다중 회전으로 렌더링될 수 있다면, 이와 동일한 옵션을 회전 잠금 모드에서도 사용할 수 있어야 합니다. 단, Activity의 screenOrientation 설정에 따라 일부 예외가 있습니다(아래 표 참조).

- 특정 방향을 요청하는 Activity(예: screenOrientation=landscape)는 사용자 잠금 기본 설정을 무시하고 Android 8.0에서와 동일하게 동작합니다.

- Android 매니페스트에서는 Activity 레벨에서 화면 방향 기본 설정을 설정할 수 있고, setRequestedOrientation()에서는 프로그래밍 방식으로 설정할 수 있습니다.

- 회전 잠금 모드가 작동하기 위해서는, Activity 회전 처리 시에 WindowManager가 사용하는 사용자 회전 기본 설정을 설정해야 합니다. 다음과 같은 경우 사용자 회전 기본 설정이 바뀔 수도 있습니다. 기기의 자연스러운 회전으로 돌아가려는 경향이 있습니다. 일반적으로, 전화 폼팩터 기기에서 그 방향은 세로입니다.

사용자가 회전 제안을 수락하는 경우, 이 제안으로 회전 기본 설정이 변경됩니다.

사용자가 강제 세로 모드 앱으로 전환하는 경우, 세로 모드로 회전 기본 설정이 변경됩니다.

- 다음 표에 일반적인 화면 방향에 대한 회전 동작이 요약되어 있습니다.



16. Apache HTTP 클라이언트 지원 중단은 비표준 ClassLoader가 있는 앱에 영향을 미침



- Android 6.0에서는 Apache HTTP 클라이언트에 대한 지원이 제거되었습니다. 이 변경사항은 Android 9 이상을 대상으로 하지 않는 앱에는 대부분 적용되지 않습니다. 그러나 Android 9 이상을 대상으로 하지 않더라도 비표준 ClassLoader 구조를 사용하는 일부 앱에는 적용될 수 있습니다.

- 명시적으로 시스템 ClassLoader에 권한을 위협하는 비표준 ClassLoader를 사용하는 앱은 영향을 받을 수 있습니다. 대신 이러한 앱은 org.apache.http.*에서 클래스를 찾을 때 앱 ClassLoader에 권한을 위임해야 합니다. 시스템 ClassLoader에 권한을 위임하면 Android 9 이상에서 NoClassDefFoundError가 발생하며 앱이 작동하지 않습니다. 시스템 ClassLoader에서 이 클래스를 알지 못하기 때문입니다. 앞으로 이와 비슷한 문제를 예방하려면 앱이 시스템 ClassLoader에 직접 액세스하지 말고 주로 앱 ClassLoader를 통해 클래스를 로드해야 합니다.

 

17. 카메라 나열



- Android 9 기기에서 실행되는 앱은 getCameraIdList()를 호출하면 모든 이용 가능한 카메라를 찾아낼 수 있습니다. 기기에 후방 카메라나 전방 카메라 하나만 있는 것으로 가정하지 말아야 합니다.

- 예를 들어 앱에 전방 및 후방 카메라 전환 버튼이 있을 경우 선택해야 할 전방 또는 후방 카메라가 2개 이상일 수 있습니다. 카메라 목록을 보고, 각 카메라의 특성을 살펴서 사용자에게 어느 카메라를 노출할지 결정해야 합니다.




출처 : https://developer.android.com/about/versions/pie/android-9.0-changes-all?hl=ko

반응형
반응형

이번 시간은 Android Support Library를 대체하는 AndroidX에 대하여 알아보도록 하겠습니다

AndroidX 개요


- AndroidX는 Android팀이 Jetpack 내에서 라이브러리를 개발, 테스트, 패키지화, 버전 및 릴리스하기 위해 사용하는 오픈 소스 프로젝트입니다 .

- AndroidX는 원래 Android Support Library 를 크게 개선한 것입니다Support Library와 마찬가지로 AndroidX는 Android OS와 별도로 배송되며, Android Release 전반에 걸쳐 이전 버전과의 호환성을 제공합니다. AndroidX는 기능 패리티 및 새 라이브러리를 제공하여 Android Support Library를 완전히 대체합니다. 또한 AndroidX에는 다음과 같은 기능이 포함되어 있습니다.

▶ AndroidX의 모든 패키지는 androidx 문자열로 시작하는 일관된 네임 스페이스가 있습니다. 그리고 Android Support Library 패키지는 해당 androidx.*패키지로 매핑되었습니다모든 이전 클래스와 Build artifact를 새 클래스에 완전히 매핑하려면 Package Refactoring 페이지를 참조하십시오.

▶ Android Support Library와 달리 AndroidX 패키지는 별도로 유지 관리되고 업데이트됩니다. androidx패키지는 version 1.0.0부터 시작하는 엄격한  Semantic versioning 사용합니다. 그리고 프로젝트에서 AndroidX 라이브러리를 독립적으로 업데이트 할 수 있습니다.

▶모든 새로운 Android Support Library 개발은 AndroidX 라이브러리에서 이루어 질 것 입니다. 여기에는 원래 Support Library artifact 유지 보수 및 새로운 Jetpack 구성 요소 도입이 포함됩니다.


AndroidX 사용

- 기존 프로젝트를 이전하는 방법 AndroidX 로 이전을 참조하십시오 .

- 새 프로젝트에서 AndroidX를 사용하려면 컴파일 SDK를 Android 9.0 (API 레벨 28) 이상으로 설정하고 gradle.properties파일에서 Android Gradle 플러그인 flag를 true로 설정해야 합니다 .

 android.useAndroidX: 값을 true로 설정하면 Android 플러그인은 Android Support Library 대신 적절한 AndroidX 라이브러리를 사용합니다. 플래그가 지정되지 않은 경우 값은 기본적으로 false입니다.

▶ android.enableJetifier: 값을 true로 설정하면 Android 플러그인은 이 자동으로 바이너리를 다시 작성하여 AndroidX를 프로젝트에서 사용하도록 기존 Third-party 라이브러리를 자동으로 마이그레이션 합니다. 플래그가 지정되지 않은 경우 값은 기본적으로 false입니다.


AndroidX 참조

- AndroidX의 모든 패키지와 클래스는 AndroidX 참조 섹션에서 찾을 수 있습니다 .


Additional Resource

- Jetpack 구성 요소는 AndroidX 라이브러리의 일부분입니다. Jetpack 홈페이지에서 구성 요소에 대해 자세히 알아보십시오 .

- Andriod Support Library에서 AndroidX로 Package Refactoring하는 자세한 내용은 블로그 게시물을 참조하십시오 .


출처 : https://developer.android.com/jetpack/androidx


반응형

+ Recent posts