Android 애플리케이션 개발 시 자체 서명된 인증서 사용

5515 단어 androidsslnginx
저는 최근에 Android에서 모바일 애플리케이션을 개발하는 방법을 배우기 시작했습니다. RiseUp에 합류하기 전에는 주로 백엔드 작업을 해왔지만 지난 2년 동안 웹 개발을 좋아하게 되었고 모바일 개발은 자연스러운 다음 단계처럼 보였습니다.

처음 3주는 굉장했습니다! Google은 시작하기 위해 수행할 수 있는 놀라운 실습 자습서 세트를 만들었습니다. 그러나 실제 시나리오로 내 기술을 테스트하고 싶었고 Android에서 로그인 흐름을 구현하기로 결정했습니다. 흐름 자체는 그다지 흥미롭지 않으므로 자세한 내용은 다루지 않겠습니다. 중요한 것은 로컬(dev) 환경에서 Nginx를 사용하여 모든 요청을 백엔드 서비스로 보낸다는 것입니다. Nginx는 API 호출을 올바른 서비스로 라우팅할 뿐만 아니라 SSL 종료도 담당합니다. 이렇게 하면 백엔드 서비스가 자체적으로 SSL 종료에 간섭하는 것을 방지할 수 있습니다.

우리 로컬 Nginx는 포트 9090을 수신하므로 다음과 같은 것이 꽤 잘 작동해야 한다고 생각했습니다*:

val loginApiService = Retrofit.Builder()
.baseUrl("https://localhost:9090")
.create(LoginApiService::class.java)                                

val token = loginApiService.authenticate(..)


* 코드를 간결하게 하기 위해 코드를 단순화했습니다.

그러나 응용 프로그램을 실행할 때 다음 오류가 발생했습니다.

java.net.ConnectException: Failed to connect to localhost/127.0.0.1:9090


뭐라고??? 음… 분명히 모바일 장치의 localhost는 장치 자체입니다. 그것은 실제로 의미가 있습니다.

문제 1번 - localhost에 대한 호출을 내 노트북으로 전달



내가 정말로 원했던 것은 localhost에 대한 모든 호출이 장치가 아닌 내 랩탑으로 이동해야 한다는 것입니다. adb 구조에!

Android 디버그 브리지(adb)는 모바일 장치(가상 또는 물리적)와 통신하는 데 도움이 되는 CLI 도구입니다. 양조를 사용하여 쉽게 설치할 수 있습니다.

brew install android-platform-tools


여기에는 모든 장치의 모든 통화를 랩톱으로 전달할 수 있는 멋진 명령reverse이 있습니다. 이것이 수행되는 방법입니다.

adb reverse tcp:9090 tcp:9090


이것은 기본적으로 포트 9090의 모든 TCP 호출이 랩톱의 포트 9090으로 전달되어야 함을 장치에 알려줍니다.

문제 해결됨! 그래서 나는 내 응용 프로그램을 다시 실행했고 이번에는 다음과 같은 결과를 얻었습니다.

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.


문제 2번 - 장치에 자체 서명된 인증서를 신뢰하도록 지시



로컬 Nginx는 자체 서명된 SSL 인증서를 사용합니다. openssl 명령으로 생성되었습니다. 이것은 웹 개발에 훌륭하게 작동했으며 지금까지 실제 문제가 없었습니다.

Android(및 iOS) 기기를 사용하는 경우 해당 인증서를 신뢰하도록 기기에 지시해야 합니다. 여기에는 두 단계가 있습니다.

1단계 - 장치에 CA 인증서 설치



먼저 자체 서명된 인증서의 루트 CA를 신뢰하도록 장치에 지시해야 합니다. 불행하게도 openssl를 사용하여 인증서를 생성할 때 실제로는 루트 CA가 없습니다. 그래서 먼저 그것을 바꿀 필요가 있었습니다.

인터넷을 검색하여 mkcert이라는 훌륭한 도구를 찾았습니다. mkcert는 로컬에서 신뢰할 수 있는 개발 인증서를 만들기 위한 간단한 도구입니다.
mkcert를 사용할 때 Android 장치에서 기대하는 것과 정확히 일치하는 PEM 인코딩 CA 인증서도 받습니다. 해당 인증서를 찾으려면 다음을 실행할 수 있습니다.

 echo "$(mkcert -CAROOT)/rootCA.pem"


인증서를 기기에 복사합니다. 이제 장치에서 _CA 인증서 _ 설정 화면을 열고 지침에 따라 복사한 인증서를 설치합니다.

2단계 - 사용자가 추가한 CA를 신뢰하도록 애플리케이션에 지시



기본적으로 Android 애플리케이션은 사용자가 추가한 CA를 신뢰하지 않습니다. 인증서를 신뢰하도록 하려면 res/xml라는 새 파일을 network_security_config에 다음 내용으로 만들어야 합니다.

<network-security-config>
    <debug-overrides>
        <trust-anchors>
            <!-- Trust preinstalled CAs -->
            <certificates src="system" />
            <!-- Additionally trust user added CAs -->
            <certificates src="user" />
        </trust-anchors>
    </debug-overrides>
</network-security-config>


디버그 모드에서만 사용자가 추가한 인증서를 신뢰한다는 점에 유의하십시오. 릴리스된 애플리케이션은 제대로 서명된 SSL 인증서에 대해 작동해야 합니다.

이제 AndroidManifest 파일에 구성 파일을 추가합니다.

<application   
...
android:networkSecurityConfig="@xml/network_security_config"
...
/>


그게 다야! 🎉

추신 이것은 물리적 장치와 가상 장치 모두에서 잘 작동합니다.

요약하면 Android 애플리케이션이 자체 서명된 인증서를 사용하여 랩탑의 HTTP 서버에 연결할 수 있도록 하려면 다음을 수행해야 합니다.
  • adb를 사용하여 모든 호출을 localhost
  • 로 전달합니다.
  • 루트 CA 인증서를 생성하고 장치에 설치합니다
  • .
  • 사용자가 추가한 CA를 신뢰하도록 애플리케이션에 지시
  • 좋은 웹페이지 즐겨찾기