Android에서 액세스 토큰과 비밀을 안전하게 저장하는 방법은 무엇입니까? 하지만 보안 측면이 약간 걱정됩니다.

oAuth를 사용하여 Google에서 메일과 연락처를 가져 오겠습니다. 액세스 토큰과 암호를 얻기 위해 로그인 할 때마다 사용자에게 묻고 싶지 않습니다. 내가 이해 한 바에 따르면 데이터베이스 또는 SharedPreferences. 하지만 보안 측면이 약간 걱정됩니다. 나는 당신이 토큰을 암호화하고 해독 할 수 있다고 읽었지만 공격자가 당신의 apk와 클래스를 디 컴파일하고 암호화 키를 얻는 것은 쉽다.
이러한 토큰을 Android에 안전하게 저장하는 가장 좋은 방법은 무엇입니까?



답변

공유 기본 설정 으로 저장합니다 . 기본적으로 비공개이며 다른 앱은 액세스 할 수 없습니다. 루팅 된 기기에서 사용자가 읽기를 시도하는 일부 앱에 대한 액세스를 명시 적으로 허용하면 앱이이를 사용할 수는 있지만 보호 할 수는 없습니다. 암호화와 관련하여 사용자에게 매번 암호 해독 암호를 입력하도록 요구하거나 (따라서 자격 증명 캐싱 목적을 무효화) 키를 파일에 저장하면 동일한 문제가 발생합니다.

실제 사용자 이름 암호 대신 토큰을 저장하면 몇 가지 이점이 있습니다.

  • 타사 앱은 비밀번호를 알 필요가 없으며 사용자는 비밀번호를 원래 사이트 (Facebook, Twitter, Gmail 등)로만 전송하도록 할 수 있습니다.
  • 누군가 토큰을 훔쳐도 암호를 볼 수 없습니다 (사용자가 다른 사이트에서도 사용할 수 있음).
  • 토큰은 일반적으로 수명이 있으며 특정 시간이 지나면 만료됩니다.
  • 토큰이 손상되었다고 의심되는 경우 토큰을 취소 할 수 있습니다.

답변

AccountManager에 저장할 수 있습니다 . 이 사람들에 따르면 모범 사례로 간주됩니다.

공식적인 정의는 다음과 같습니다.

이 클래스는 사용자 온라인 계정의 중앙 집중식 레지스트리에 대한 액세스를 제공합니다. 사용자는 계정 당 한 번씩 자격 증명 (사용자 이름 및 암호)을 입력하여 애플리케이션이 “원 클릭”승인으로 온라인 리소스에 액세스 할 수 있도록합니다.

AccountManager 사용 방법에 대한 자세한 가이드 :

그러나 결국 AccountManager는 토큰을 일반 텍스트로만 저장합니다. 따라서 AccountManager에 저장하기 전에 암호를 암호화하는 것이 좋습니다. AESCrypt 또는 AESCrypto 와 같은 다양한 암호화 라이브러리를 활용할 수 있습니다.

또 다른 옵션은 Conceal 라이브러리 를 사용하는 것 입니다. Facebook에서는 충분히 안전하고 AccountManager보다 훨씬 사용하기 쉽습니다. 다음은 Conceal을 사용하여 비밀 파일을 저장하는 코드 조각입니다.

byte[] cipherText = crypto.encrypt(plainText);
byte[] plainText = crypto.decrypt(cipherText);

답변

SharedPreferences 보안 위치 자체 가 아닙니다 . 루팅 된 장치에서 우리는 모든 응용 프로그램의 SharedPrefereces xml을 쉽게 읽고 수정할 수 있습니다. 따라서 토큰은 비교적 자주 만료되어야합니다. 그러나 토큰이 매시간 만료 되더라도 SharedPreferences에서 새로운 토큰을 훔칠 수 있습니다. Android KeyStore는 예를 들어 SharedPreferences 또는 데이터베이스에 저장하기 위해 토큰을 암호화하는 데 사용될 암호화 키의 장기 저장 및 검색에 사용해야합니다. 키는 애플리케이션의 프로세스 내에 저장되지 않으므로 손상 되기 가 더 어렵 습니다.

따라서 장소보다 더 관련성이있는 것은 암호화 방식으로 서명 된 단기 JWT 사용, Android KeyStore를 사용하여 암호화, 보안 프로토콜로 전송 등 자체 보안 방법입니다.


답변

  1. Android 스튜디오의 프로젝트 창에서 “Project Files”를 선택하고 프로젝트의 루트 디렉토리에 “keystore.properties”라는 새 파일을 만듭니다.

  1. “keystore.properties”파일을 열고 액세스 토큰과 시크릿을 파일에 저장하십시오.

  1. 이제 모듈의 build.gradle 파일 에서 읽기 액세스 토큰 및 시크릿을 로드 합니다. 그런 다음 코드에서 직접 액세스 할 수 있도록 액세스 토큰 및 시크릿에 대한 BuildConfig 변수를 정의해야합니다. 귀하의 build.gradle는 다음과 같이 보일 수 있습니다 :

    ... ... ...
    
    android {
        compileSdkVersion 26
    
        // Load values from keystore.properties file
        def keystorePropertiesFile = rootProject.file("keystore.properties")
        def keystoreProperties = new Properties()
        keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
    
        defaultConfig {
            applicationId "com.yourdomain.appname"
            minSdkVersion 16
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
            // Create BuildConfig variables
            buildConfigField "String", "ACCESS_TOKEN", keystoreProperties["ACCESS_TOKEN"]
            buildConfigField "String", "SECRET", keystoreProperties["SECRET"]
        }
    }
  2. 다음과 같이 코드에서 액세스 토큰 및 암호를 사용할 수 있습니다.

    String accessToken = BuildConfig.ACCESS_TOKEN;
    String secret = BuildConfig.SECRET;

이렇게하면 프로젝트 내부에 일반 텍스트로 액세스 토큰과 시크릿을 저장할 필요가 없습니다. 따라서 누군가가 APK를 디 컴파일하더라도 외부 파일에서로드 할 때 액세스 토큰과 시크릿을 가져 오지 않습니다.


답변

두 가지 옵션에 따라 액세스 토큰을 보호 할 수 있습니다.

  1. 반전되지 않는 Android 키 저장소에 액세스 토큰을 저장하십시오.
  2. 토큰을 저장하는 일부 계산에 NDK 함수를 사용하고 되돌리기가 매우 어려운 C ++ 코드로 NDK를 사용합니다.