반응형

이번 포스팅은 Android Build 오류에 대하여 알아보도록 하겠습니다.


< Error >


android.os.FileUriExposedException: file:///storage/emulated/0/Download/viewData.pdf exposed beyond app through ClipData.Item.getUri()


< Solution>

1. Android 7.0 이상부터 파일 공유 시 API 정책 변경

2. file:// URI 의 직접적인 노출이 아니라 content://URI 로 보내고 이에 대해서 임시 Access 권한을 부여하는 방식으로 변경이 되었습니다.

    아래는 Google Android OS 7.0 공식 문서 입니다.

   (링크 : https://developer.android.com/about/versions/nougat/android-7.0-changes.html#accessibility)


파일 시스템 권한 변경


개인 파일의 보안을 강화하기 위해, Android 7.0 이상을 대상으로 하는 앱의 개인 디렉터리는 액세스가 제한됩니다(0700). 이 설정은 크기 또는 존재 여부와 같은 개인 파일의 메타데이터 유출을 막아줍니다. 이러한 권한 변경은 여러 가지 부작용이 있습니다.

▶ 소유자가 개인 파일의 파일 권한을 더 이상 완화해서는 안 되며, MODE_WORLD_READABLE 및/또는 MODE_WORLD_WRITEABLE을 사용하여 권한을 완화하려고 시도하면 SecurityException이 트리거됩니다.

참고: 아직까지는 이 제한이 완전히 적용되지 않습니다. 앱이 여전히 기본 API 또는 File API를 사용하여 개인 디렉터리에 대한 권한을 수정할 수도 있습니다. 하지만 개인 디렉터리에 대한 권한은 부득이한 경우가 아니라면 완화하지 않는 것이 좋습니다.

▶ 패키지 도메인 외부에서 file:// URI를 전달하면 수신기가 액세스 불가능한 경로로 남아 있을 수 있습니다. 따라서 file:// URI를 전달하려고 시도하면 FileUriExposedException이 트리거됩니다. 개인 파일의 내용을 공유하기 위해 권장되는 방법은 FileProvider를 사용하는 것입니다.

 DownloadManager는 비공개로 저장된 파일을 더 이상 파일 이름별로 공유할 수 없습니다. 레거시 애플리케이션은 COLUMN_LOCAL_FILENAME에 액세스할 때 액세스가 불가능한 경로가 될 수 있습니다. Android 7.0 이상을 대상으로 하는 앱은 COLUMN_LOCAL_FILENAME에 액세스할 때 SecurityException을 트리거합니다. DownloadManager.Request.setDestinationInExternalFilesDir() 또는 DownloadManager.Request.setDestinationInExternalPublicDir()을 사용하여 다운로드위치를 공용 위치로 설정하는 레거시 애플리케이션은 COLUMN_LOCAL_FILENAME에 있는 경로에 여전히 액세스할 수 있지만, 이 메서드는 부득이한 경우가 아니라면 사용하지 않는 것이 좋습니다. DownloadManager에 의해 노출되는 파일에 액세스하는 좋은 방법은 ContentResolver.openFileDescriptor()를 사용하는 것입니다.


      앱 사이의 파일 공유


Android 7.0을 대상으로 하는 앱의 경우, Android 프레임워크는 앱 외부에서 file:// URI의 노출을 금지하는 StrictMode API 정책을 적용합니다. 파일 URI를 포함하는 인텐트가 앱을 떠나면 FileUriExposedException 예외와 함께 앱에 오류가 발생합니다.

애플리케이션 간에 파일을 공유하려면 content:// URI를 보내고 이 URI에 대해 임시 액세스 권한을 부여해야 합니다. 이 권한을 가장 쉽게 부여하는 방법은 FileProvider 클래스를 사용하는 방법입니다. 권한과 파일 공유에 대한 자세한 내용은 파일 공유를 참조하세요.


3. AndroidMenifext.xml를 수정하여 fileprovider를 지정합니다.



<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:permission="android.permission.MANAGE_DOCUMENTS"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_path" />
</provider>


4.  res/xml/file_provider_path.xml 파일을 생성하여 아래와 같이 파일 경로를 지정합니다.


<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />

<files-path
name="files"
path="." />

</paths>


반응형
반응형

이번 포스팅은  Android Build 오류에 대하여 알아보도록 하겠습니다.


< Error >


java.security.KeyStoreException: entries cannot be protected with passwords

     at android.security.keystore.AndroidKeyStoreSpi.engineSetKeyEntry(AndroidKeyStoreSpi.java:308)

     at java.security.KeyStore.setKeyEntry(KeyStore.java:1179)


< Solution > 


setKeyEntry method가 분명히 존재하고 passwords 매개 변수를 사용한다는 사실에도 불구하고 AndroidKeystore 구현은 이를 지원하지 않습니다.

어떤 경우든 장치의 어느 곳에 저장되어 있는 강력한 암호든 약한 암호는 안전하지 않습니다. 이는 특히 소스 코드(일반적으로 소스 코드, not-android Context 포함)에 해당됩니다. 당신의 앱 APK를 손에 넣으면, 몇 가지 훌륭한 APK 분석 도구 중 하나를 사용하여 Class의 constants pool에 액세스할 수 있는데, 이 pool은 일반 텍스트로 되어 있을 것입니다. 아무리 난독화해도 이것을 막을 수 없었고, 심지어 더 어렵게 만들 수도 없습니다. 이것이 아마도 AndroidKeystore 구현이 이것을 허용하지 않는 이유일 것입니다.

안드로이드 장치의 키 저장소 서비스의 전체 포인트(실제로 Unix socket을 통해 대화할 수 있는 별도의 프로세스로 구현됨)는 사용자가 암호를 입력하여 중요한 자료에 대한 액세스를 보호하는 것이므로 Key 쌍이나 다른 비밀 암호를 입력하는 것은 의미가 없습니다. 더 최근의 스마트폰에서는, 이 모든 것이 Hardware에 내장되어 있어, 매우 강력한 보안을 제공합니다.

Apparently despite the fact that the method takes a password parameter, the AndroidKeystoreimplementation does not support this, take a look at line 200 in the source.

In any case, a password, whether strong or weak that is stored anywhere on the device is unsafe. This is especially true of source code (including source code in general, non-android contexts). If I get my hands on your app's APK, I can use one of several excellent APK analysis tools to access the class's constant pool, which will contain the password in plain text. No amount of obfuscation could prevent this, or even make it more difficult. This is perhaps the reason that the AndroidKeystoreimplementation doesn't allow this.

The whole point of the key store service on android device (it's actually implemented as a separate process you can talk to via a unix socket) is to protect access to sensitive material by requiring a users passcode to unlock it, so there's no point in putting a password on your key pairs or other secrets.. In more recent phones, this is all implmented in hardware, which provides very strong security.

참조 링크 : https://stackoverflow.com/questions/27575059/android-entries-cannot-be-protected-with-passwords

반응형
반응형

이번 포스팅은 Android Build 오류에 대하여 알아보도록 하겠습니다.


< Error >


 Unable to add window -- token null is not valid; is your activity running?


< Solution >


1.  Dialog 생성 시 applicationContext를 사용하여 발생하는 오류로 특정 Activity 의 Context를 호출하여 build 하시면 됩니다.


(Before)

val builder = AlertDialog.Builder(ContextThemeWrapper(applicationContext , R.style.AppTheme))


(After)

val builder = AlertDialog.Builder(ContextThemeWrapper(MainActivity@this , R.style.AppTheme))



반응형

+ Recent posts