programing

애플리케이션에서 개인 API 키를 저장하고 보호하는 모범 사례

css3 2023. 7. 19. 21:31

애플리케이션에서 개인 API 키를 저장하고 보호하는 모범 사례

대부분의 앱 개발자는 일부 타사 라이브러리를 앱에 통합합니다.Dropbox 또는 YouTube와 같은 서비스에 액세스하거나 로깅 충돌을 위한 경우.타사 라이브러리 및 서비스의 수는 엄청나게 많습니다.이러한 라이브러리와 서비스의 대부분은 서비스 인증을 통해 통합됩니다. 대부분의 경우 API 키를 통해 인증됩니다.보안을 위해 서비스는 일반적으로 비밀 키라고도 하는 공용 및 개인 키를 생성합니다.유감스럽게도 서비스에 연결하려면 이 개인 키를 사용하여 인증해야 하므로 응용 프로그램의 일부일 수 있습니다.말할 필요도 없이, 이것은 엄청난 보안 문제에 직면해 있습니다.공개 및 개인 API 키는 몇 분 만에 APK에서 추출할 수 있으며 쉽게 자동화할 수 있습니다.

이와 유사한 것이 있다고 가정하면 비밀 키를 보호하려면 어떻게 해야 합니까?

public class DropboxService  {

    private final static String APP_KEY = "jk433g34hg3";
    private final static String APP_SECRET = "987dwdqwdqw90";
    private final static AccessType ACCESS_TYPE = AccessType.DROPBOX;

    // SOME MORE CODE HERE

}

개인 키를 저장하는 가장 좋고 안전한 방법은 무엇이라고 생각하십니까?난독화, 암호화, 어떻게 생각하십니까?

  1. 컴파일된 응용 프로그램에는 키 문자열뿐 아니라 APP_KEY 및 APP_SECRET이라는 상수 이름이 포함되어 있습니다.이러한 자체 문서화 코드에서 키를 추출하는 것은 예를 들어 표준 Android 도구 dx를 사용하는 것과 같은 사소한 일입니다.

  2. ProGuard를 적용할 수 있습니다.키 문자열은 그대로 유지되지만 상수 이름은 제거됩니다.또한 가능한 한 짧고 의미 없는 이름으로 클래스 및 메서드의 이름을 변경합니다.그런 다음 키를 추출하면 어떤 문자열이 어떤 용도로 사용되는지 파악하는 데 시간이 더 걸립니다.

    ProGuard를 설정하는 것은 걱정만큼 어렵지 않습니다.먼저 project.properties에 나와 있는 ProGuard만 활성화하면 됩니다.타사 라이브러리에 문제가 있는 경우 proguard-project에서 일부 경고를 억제하거나 난독화되지 않도록 방지해야 할 수 있습니다.txt. 예를 들어 다음과 같습니다.

    -dontwarn com.dropbox.**
    -keep class com.dropbox.** { *; }
    

    이것은 무차별적인 접근 방식입니다. 처리된 응용 프로그램이 작동하면 이러한 구성을 세분화할 수 있습니다.

  3. 코드에서 문자열을 수동으로 난독화할 수 있습니다. 예를 들어 Base64 인코딩을 사용하거나 더 복잡한 것을 사용하는 것이 좋습니다. 네이티브 코드도 사용할 수 있습니다.그런 다음 해커는 정적으로 인코딩을 역엔지니어링하거나 적절한 위치에서 디코딩을 동적으로 가로채야 합니다.

  4. ProGuard의 전문 형제인 DexGuard와 같은 상용 난독화기를 적용할 수 있습니다.문자열 및 클래스를 추가로 암호화/난독화할 수 있습니다.그러면 키를 추출하는 데 훨씬 더 많은 시간과 전문 지식이 필요합니다.

  5. 사용자의 서버에서 응용프로그램의 일부를 실행할 수 있습니다.만약 당신이 그곳에 열쇠를 보관할 수 있다면, 그것들은 안전합니다.

결국, 그것은 여러분이 만들어야 하는 경제적인 균형입니다: 키가 얼마나 중요한지, 얼마나 많은 시간이나 소프트웨어를 감당할 수 있는지, 키에 관심이 있는 해커들은 얼마나 정교한지, 그들은 얼마나 많은 시간을 소비하고 싶어하는지, 키가 해킹되기 전에 얼마나 많은 가치가 있는지,성공적인 해커들이 키 등을 배포하는 규모는?키와 같은 작은 정보는 전체 응용프로그램보다 보호하기가 더 어렵습니다.본질적으로, 고객 측의 어떤 것도 깨지지 않지만, 당신은 확실히 기준을 높일 수 있습니다.

(저는 ProGuard 및 DexGuard의 개발자입니다.)

제 생각에는 몇 가지 아이디어가 있습니다. 첫 번째 아이디어만 약간의 보증을 제공합니다.

  1. 인터넷의 일부 서버에 비밀을 보관하고, 필요할 때 그것들을 가져와 사용하세요.사용자가 드롭박스를 사용하려고 하면 사이트에 요청하고 비밀 키를 가져오는 것을 막을 수 없습니다.

  2. 당신의 비밀을 jni 코드에 넣고, 당신의 라이브러리를 더 크고 더 분해하기 어렵게 만들기 위해 몇 가지 변수 코드를 추가하세요.또한 키 문자열을 몇 개의 부분으로 분할하여 다양한 위치에 보관할 수도 있습니다.

  3. 난독화기를 사용하고, 코드 해시된 비밀을 입력한 후 나중에 사용해야 할 때 해제합니다.

  4. 비밀 키를 이미지의 마지막 픽셀로 자산에 넣습니다.그런 다음 필요할 때 코드로 읽으십시오.코드를 난독화하면 코드를 읽을 코드를 숨기는 데 도움이 됩니다.

pk 코드를 읽는 것이 얼마나 쉬운지 간단히 살펴보고 싶다면 APK Analyser를 이용하십시오.

http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/

다른 접근법은 애초에 장치에 비밀을 가지고 있지 않는 것입니다!모바일 API 보안 기술(특히 파트 3)을 참조하십시오.

전통적인 간접 경험을 통해 API 끝점과 앱 인증 서비스 간에 비밀을 공유할 수 있습니다.

클라이언트가 API 호출을 원할 때 앱 인증 서비스에 인증을 요청하고(강력한 원격 증명 기술을 사용하여) 비밀이 서명한 시간 제한(일반적으로 JWT) 토큰을 받습니다.

토큰은 요청에 대해 작업하기 전에 엔드포인트가 서명을 확인할 수 있는 각 API 호출과 함께 전송됩니다.

실제 암호는 장치에 존재하지 않습니다. 실제로 앱은 암호가 유효한지 여부를 전혀 알지 못하며 인증을 요청하고 결과 토큰을 전달합니다.간접적인 이점으로 암호를 변경하려는 경우 사용자가 설치된 앱을 업데이트할 필요 없이 암호를 변경할 수 있습니다.

따라서 여러분이 여러분의 비밀을 보호하고 싶다면, 처음부터 여러분의 앱에 그것을 가지고 있지 않는 것이 꽤 좋은 방법입니다.

이전의 보안되지 않은 방법:

API/비밀 키를 보호하기 위한 3가지 간단한 단계를 수행합니다(오래된 답변).

우리는 Gradle을 사용하여 API 키 또는 Secret 키를 보호할 수 있습니다.

gradle.properties(프로젝트 속성):키를 사용하여 변수를 만듭니다.

GoogleAPIKey = "Your API/Secret Key"

build.gradle (Module: app) : build.gradle에 변수를 설정하여 활동 또는 fragment로 액세스합니다.빌드할 아래 코드 추가{} 유형입니다.

buildTypes.each {
    it.buildConfigField 'String', 'GoogleSecAPIKEY', GoolgeAPIKey
}

앱의 BuildConfig를 통해 Activity/Fragment에서 액세스할 수 있습니다.

BuildConfig.GoogleSecAPIKEY

업데이트:

위의 솔루션은 Git를 통해 커밋할 수 있는 오픈 소스 프로젝트에 도움이 됩니다. (David Rawson과 Riyaz-ali의 의견에 감사드립니다.

Matthew와 Pablo Cegarra의 의견에 따르면, 위의 방법은 안전하지 않으며, 디컴파일러는 누군가가 우리의 비밀 키로 빌드 구성을 볼 수 있도록 허용합니다.

솔루션:

NDK를 사용하여 API 키를 보호할 수 있습니다.네이티브 C/C++ 클래스에 키를 저장하고 Java 클래스에서 키에 액세스할 수 있습니다.

NDK를 사용하여 API 키를 보호하려면 이 블로그를 따르십시오.

Android에서 토큰을 안전하게 저장하는 방법에 대한 후속 조치

@Manohar Reddy 솔루션에 추가하여 Firebase Database 또는 Firebase RemoteConfig(Null 기본값)를 사용할 수 있습니다.

  1. 키 암호화
  2. 파이어베이스 데이터베이스에 저장
  3. 앱을 시작하는 동안 또는 필요할 때마다 가져오기
  4. 키를 해독하여 사용합니다.

이 솔루션의 차이점은 무엇입니까?

  • 화재 기지에 대한 자격 증명 없음
  • Firebase 액세스가 보호되므로 서명된 인증서가 있는 앱만 API 호출 권한을 가집니다.
  • 중간자의 가로채기를 방지하기 위한 암호화/암호화하지만 이미 소방서에 https를 호출했습니다.

앱-비밀 키는 비공개로 유지되어야 하지만 앱을 해제할 때 일부 사용자가 되돌릴 수 있습니다.

숨기지 않을 사람들을 위해, 둘 중 하나를 잠급니다.ProGuard는 비트 연산자를 몇 개 하여 리팩터 있습니다.jk433g34hg3dll.5더 수 :) 3분ㅠㅠㅠㅠㅠㅠㅠ 5~15분 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅠ

가장 좋은 방법은 그대로 유지하는 거야, 임호.

서버측(PC)에 저장해도 키가 해킹되어 출력될 수 있습니다.아마 이게 가장 오래 걸릴까요?어쨌든 그것은 최선의 경우 몇 분 또는 몇 시간의 문제입니다.

일반 사용자는 코드를 압축 해제하지 않습니다.

가능한 한 가지 해결책은 앱에서 데이터를 인코딩하고 런타임에 디코딩을 사용하는 것입니다.나는 또한 당신의 앱의 디컴파일된 소스 코드를 읽고 이해하는 것을 어렵게 만들기 위해 progaud를 사용하는 것을 추천합니다. 예를 들어, 나는 앱에 인코딩된 키를 넣은 다음 실행 시 내 비밀 키를 디코딩하기 위해 앱에서 디코딩 방법을 사용했습니다.

// "the real string is: "mypassword" "; 
//encoded 2 times with an algorithm or you can encode with other algorithms too
public String getClientSecret() {
    return Utils.decode(Utils
            .decode("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}

보호된 앱의 디컴파일된 소스 코드는 다음과 같습니다.

 public String c()
 {
    return com.myrpoject.mypackage.g.h.a(com.myrpoject.mypackage.g.h.a("Ylhsd1lYTnpkMjl5WkE9PQ=="));
  }

적어도 저에게는 충분히 복잡합니다. 애플리케이션에 값을 저장할 수밖에 없을 때는 이렇게 해야 합니다.물론 우리 모두는 그것이 최선의 방법이 아니라는 것을 알지만 그것은 나에게 효과가 있습니다.

/**
 * @param input
 * @return decoded string
 */
public static String decode(String input) {
    // Receiving side
    String text = "";
    try {
        byte[] data = Decoder.decode(input);
        text = new String(data, "UTF-8");
        return text;
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return "Error";
}

압축 해제된 버전:

 public static String a(String paramString)
  {
    try
    {
      str = new String(a.a(paramString), "UTF-8");
      return str;
    }
    catch (UnsupportedEncodingException localUnsupportedEncodingException)
    {
      while (true)
      {
        localUnsupportedEncodingException.printStackTrace();
        String str = "Error";
      }
    }
  }

그리고 당신은 구글에서 약간의 검색으로 매우 많은 암호화 클래스를 찾을 수 있습니다.

이 예에는 여러 가지 측면이 있습니다.저는 다른 곳에서 명시적으로 다루지 않았다고 생각되는 몇 가지 사항을 언급할 것입니다.

운송 중인 비밀을 보호

가장 먼저 주의해야 할 점은 앱 인증 메커니즘을 사용하여 드롭박스 API에 액세스하려면 키와 비밀을 전송해야 한다는 것입니다.연결은 HTTPS입니다. 즉, TLS 인증서를 알지 못하면 트래픽을 가로챌 수 없습니다.이는 모바일 장치에서 서버로 이동하는 동안 사용자가 패킷을 가로채고 읽는 것을 방지하기 위한 것입니다.일반 사용자에게는 트래픽의 프라이버시를 보장하는 정말 좋은 방법입니다.

그것이 잘하지 못하는 것은 악의적인 사람이 앱을 다운로드하고 트래픽을 검사하는 것을 막는 것입니다.모바일 장치로 들어오고 나가는 모든 트래픽에 대해 중간 사용자 프록시를 사용하는 것은 정말 쉽습니다.이 경우 Dropbox API의 특성상 앱 키와 비밀을 추출하기 위해 코드를 분해하거나 역설계할 필요가 없습니다.

서버에서 수신하는 TLS 인증서가 예상되는 인증서인지 확인하는 작업을 지정할 수 있습니다.이렇게 하면 클라이언트에 검사가 추가되고 트래픽을 가로채기가 더 어려워집니다.이렇게 하면 비행 중인 트래픽을 검사하는 것이 더 어려워지지만, 피닝 검사는 클라이언트에서 수행되므로 피닝 테스트를 비활성화할 수 있습니다.하지만 그것은 그것을 더 어렵게 만듭니다.

휴식 중인 비밀을 보호하는 것.

첫 번째 단계로, 프로가드와 같은 것을 사용하는 것은 비밀이 어디에 보관되어 있는지를 덜 명확하게 만드는 데 도움이 될 것입니다.또한 NDK를 사용하여 키와 비밀을 저장하고 요청을 직접 전송할 수 있으므로 정보를 추출할 수 있는 적절한 기술을 가진 사람의 수가 크게 줄어듭니다.값을 메모리에 직접 저장하지 않음으로써 더 많은 난독화를 달성할 수 있습니다. 다른 답변에서 제안한 대로 값을 암호화하고 사용 직전에 암호를 해독할 수 있습니다.

고급 옵션

이제 앱 어디에나 비밀을 저장하는 것에 대해 편집증적이고 좀 더 포괄적인 솔루션에 투자할 시간과 비용이 있다면 서버에 자격 증명을 저장하는 것을 고려해 볼 수 있습니다.이렇게 하면 서버를 통해 통신해야 하기 때문에 API에 대한 호출 지연 시간이 증가하고 데이터 처리량 증가로 인해 서비스 실행 비용이 증가할 수 있습니다.

그런 다음 서버를 보호하기 위해 서버와 가장 잘 통신하는 방법을 결정해야 합니다.이는 내부 API에서 동일한 문제가 다시 발생하지 않도록 하는 데 중요합니다.제가 할 수 있는 최선의 경험칙은 중간자의 위협 때문에 어떤 비밀도 직접적으로 전달하지 않는 것입니다.대신 암호를 사용하여 트래픽에 서명하고 서버로 전송되는 모든 요청의 무결성을 확인할 수 있습니다.이 작업을 수행하는 한 가지 표준 방법은 암호 키로 지정된 메시지의 HMAC를 계산하는 것입니다.저는 이 분야에서 운영되는 보안 제품을 가지고 있는 회사에서 일하고 있습니다. 이것이 제가 흥미를 느끼는 이유입니다.사실, 여기 제 동료의 블로그 기사가 있습니다. 이 기사의 대부분을 다루고 있습니다.

제가 얼마나 해야 합니까?

이와 같은 보안 조언을 사용하면 누군가 침입하는 것을 얼마나 어렵게 만들고 싶은지에 대한 비용/이익 결정을 내려야 합니다.만약 당신이 수백만 명의 고객을 보호하는 은행이라면, 당신의 예산은 그들의 여가 시간에 앱을 지원하는 사람과 완전히 다릅니다.누군가가 당신의 보안을 깨뜨리는 것을 막는 것은 사실상 불가능하지만, 실제로 모든 종과 휘파람을 필요로 하는 사람은 거의 없으며 몇 가지 기본적인 예방책으로 당신은 먼 길을 갈 수 있습니다.

당신이 비밀키를 보호하기 위해 무엇을 하든 진정한 해결책은 되지 않을 것입니다.개발자가 응용 프로그램을 디컴파일할 수 있다면 키를 보호할 방법이 없으며, 키를 숨기는 것은 단지 모호함에 의한 보안일 뿐이며 코드 난독화도 마찬가지입니다.비밀 키를 보호할 때 문제는 보안 키를 보호하려면 다른 키를 사용해야 하며 해당 키도 보호해야 한다는 것입니다.키로 잠긴 상자에 숨겨진 키를 생각해 보십시오.당신은 방 안에 상자를 놓고 방을 잠급니다.보안할 다른 키가 남아 있습니다.그리고 그 키는 여전히 당신의 애플리케이션 안에서 하드 코딩될 것입니다.

따라서 사용자가 PIN이나 구문을 입력하지 않으면 키를 숨길 수 없습니다.그러나 이를 위해서는 대역 외에서 발생하는 PIN을 관리하기 위한 체계가 있어야 합니다. 즉, 다른 채널을 통해 발생하는 PIN을 관리할 수 있습니다.확실히 구글 API와 같은 서비스의 키를 보호하는 데 실용적이지 않습니다.

가장 안전한 해결책은 키를 서버에 보관하고 해당 키가 필요한 모든 요청을 서버를 통해 라우팅하는 것입니다.이렇게 하면 서버가 안전한 한 키도 서버에서 떠나지 않습니다.물론 이 솔루션에는 성능 비용이 듭니다.

이러한 개인 정보를 유지하는 유일한 진정한 방법은 서버에 보관하고 앱이 서버에 무엇이든 전송하도록 하고 서버가 Dropbox와 상호 작용하도록 하는 것입니다.이렇게 하면 개인 키를 어떤 형식으로도 배포할 수 없습니다.

오래된 게시물이지만, 여전히 충분히 좋습니다..so 라이브러리에 숨기면 좋을 것 같습니다. NDK와 C++를 사용하면 당연히 .so 파일을 16진수 편집기로 볼 수 있지만, 다음과 같이 파일을 압축 해제하는 것이 좋습니다.p

비밀을 간직하고 앱이 시작되면 그것으로부터 그것을 얻으세요, 그것은 웹 서비스를 부르는 것보다 훨씬 낫습니다.

언급URL : https://stackoverflow.com/questions/14570989/best-practice-for-storing-and-protecting-private-api-keys-in-applications