머리말
최근에 HTTP와 관련된 문제를 해결해야하므로 Android 플랫폼 HTTPS의 사용을 배우는 데 시간을 보냈으며 동시에 HTTPS의 몇 가지 원칙을 읽습니다.
HTTPS 원리
HTTPS (Hyper Transfer Protocol Secure)는 SSL/TLS를 기반으로 한 HTTP입니다. HTTPS 프로토콜은 HTTP 프로토콜을 기반으로하며 SSL/TLS 핸드 셰이크 및 데이터 암호화 전송을 추가 하는데도 애플리케이션 계층 프로토콜에 속합니다. 따라서 HTTPS 프로토콜을 연구하는 원리는 마지막으로 SSL/TLS 프로토콜을 연구하는 것입니다.
SSL/TLS 프로토콜 효과
SSL/TLS가없는 HTTP 커뮤니케이션은 암호화 된 커뮤니케이션이 아닙니다.
1. 도청 위험 : 제 3자는 의사 소통 내용에 대해 배울 수 있습니다.
2. 변조 위험 : 제 3자는 알림 내용을 수정할 수 있습니다.
3. 위험을 선포합니다 : 제 3자는 의사 소통에 참여하는 다른 사람들의 정체성 인 척 할 수 있습니다.
SSL/TLS 프로토콜은이 세 가지 위험을 해결하도록 설계되었습니다.
1. 모든 정보는 암호화 된 전송이며 제 3자는 도청 할 수 없습니다.
2. 일단 조작 된 메커니즘이 있습니다.
3. 신원이 가장하는 것을 방지하기 위해 ID 인증서가 장착되어 있습니다.
기본 작동 프로세스
SSL/TLS 프로토콜의 기본 아이디어는 공개 키 암호화 방법을 사용하는 것입니다 , 자체 개인 키로 해독 될 것입니다. 그러나 여기서는 두 가지 문제에 대한 해결책을 이해해야합니다.
1. 공개 키가 변조되지 않도록하는 방법은 무엇입니까?
해결책 : 공개 키를 디지털 인증서에 넣습니다. 인증서가 신뢰할 수있는 한 공개 키는 신뢰할 수 있습니다.
2. 공개 키 암호화의 양이 너무 큽니다. 시간 소비를 줄이는 방법은 무엇입니까?
솔루션 : 각 대화, 클라이언트 및 서버 측면 정보를 암호화하기 위해 "세션 키"(세션 키)를 생성합니다. "대화 키"는 대칭 암호화이므로 작동 속도가 매우 빠르며 서버 공개 키는 "대화 키"자체를 암호화하는 데만 사용되므로 암호화 된 작업의 시간 소비가 줄어 듭니다.
따라서 SSL/TLS 프로토콜의 기본 프로세스는 다음과 같습니다.
1. 클라이언트가 서버에 요청하고 공개 키를 확인합니다.
2. 양 당사자는 "대화 키"를 협상하고 생성합니다.
3. 양 당사자는 "대화 키"를 사용하여 암호화 된 의사 소통을 수행합니다.
위의 과정에서 처음 두 천은 "핸드 셰이크 단계"라고도합니다.
악수 단계의 상세한 과정
"핸드 케이크 단계"에는 4 가지 커뮤니케이션이 포함됩니다.
클라이언트는 요청을 발행했습니다 (ClientHello)
우선 클라이언트 (일반적으로 브라우저)는 암호화 된 통신 요청을 서버에 보냅니다. 이는 ClientHello 요청이라고합니다. 이 단계에서 클라이언트는 주로 서버에 다음 정보를 제공합니다.
1. TLS 1.0 버전과 같은 지원되는 프로토콜 버전
2. 클라이언트가 생성 한 임의 숫자는 나중에 "대화 키"를 생성하는 데 사용됩니다.
3. RSA 공개 키 암호화와 같은 지원 가능한 암호화 방법.
4. 지원 압축 방법.
클라이언트가 보낸 정보에는 서버의 도메인 이름이 포함되어 있지 않습니다. 다시 말해, 이론 서버에는 하나의 웹 사이트 만 포함 할 수 있습니다. 그렇지 않으면 어떤 웹 사이트가 고객에게 제공하는지는 확실하지 않습니다. 이것이 서버에 일반적으로 하나의 디지털 인증서 만있는 이유입니다.
ServerHello
서버가 클라이언트 요청을받은 후 ServerHello라는 클라이언트에 응답했습니다. 서버의 응답에는 다음 컨텐츠가 포함됩니다.
1. TLS 1.0 버전과 같은 암호화 된 통신 프로토콜 버전을 확인하십시오. 브라우저가 서버에서 지원하는 버전과 일치하지 않으면 서버는 암호화 된 통신을 종료합니다.
2. 서버에서 생성 된 임의의 숫자는 나중에 "대화 키"를 생성하는 데 사용됩니다.
3. RSA 공개 키 암호화와 같은 사용 된 암호화 방법을 확인하십시오.
4. 서버 인증서.
위의 정보 외에도 서버가 클라이언트의 신원을 확인 해야하는 경우 다른 요청이 포함되어 클라이언트에게 "클라이언트 인증서"를 제공하도록 요청합니다. 예를 들어, 금융 기관은 종종 인증 된 고객 만 자체 네트워크에 연결할 수 있으며 고객 인증서가 포함 된 공식 고객에게 USB 키를 제공합니다.
클라이언트가 클라이언트에 응답 한 후 서버 응답을 수신 한 후 서버 인증서는 먼저 서버를 확인합니다. 신뢰할 수있는 기관에서 인증서를 발행하지 않았거나 인증서의 도메인 이름이 실제 도메인 이름과 일치하지 않거나 인증서가 만료 된 경우 방문자에게 경고를 표시하고 선택에서 계속 통신할지 여부가 표시됩니다. .
인증서에 문제가없는 경우 클라이언트는 인증서에서 공개 키를 꺼냅니다. 그런 다음 다음 세 메시지를 서버로 보냅니다.
1. 임의의 숫자. 서버의 임의 수는 탭을 방지하기 위해 암호화됩니다.
2. 코드 변경 알림으로, 후속 정보는 양 당사자가 합의한 암호화 방법과 키와 함께 전송 될 것임을 나타냅니다.
3. 클라이언트 핸드 셰이크는 통지를 종료하여 클라이언트의 악수 단계가 종료되었음을 나타냅니다. 이 항목은 일반적으로 이전에 전송 된 모든 내용의 해시 값입니다.
위의 첫 번째 임의 숫자는 전체 핸드 셰이크 단계에서 "프리 마스터 키"라고도하는 세 번째 임의의 숫자입니다. 이를 통해 클라이언트와 서버는 동시에 3 개의 랜덤 숫자를 가지고 있으며, 두 당사자는 세션에 사용 된 동일한 "세션 키"를 생성하기 위해 미리 동의 한 암호화 방법을 사용합니다.
서버의 최종 응답 서버가 클라이언트로부터 세 번째 임의 번호 프리 마스터 키를 수신 한 후 생성 된 세션에 사용 된 "세션 키"를 계산합니다. 그런 다음 다음 정보를 고객에게 보내십시오.
1. 코드 변경 알림으로, 후속 정보는 양 당사자가 합의한 암호화 방법과 키와 함께 전송 될 것임을 나타냅니다.
2. 서버 핸드 셰이크는 통지를 종료하여 서버의 핸드 셰이크 단계가 종료되었음을 나타냅니다. 이 항목은 또한 클라이언트 확인에 사용되는 모든 이전 내용의 해시 값입니다.
악수 끝
이 시점에서 전체 핸드 셰이크 단계가 끝났습니다. 다음으로 클라이언트와 서버는 일반적인 HTTP 프로토콜을 사용하지만 "세션 키"암호화 컨텐츠를 사용하는 암호화 된 통신에 들어갑니다.
서버는 Nginx를 기반으로 HTTPS 가상 사이트를 구축했습니다
이전 기사는 서버 측에서 SSL 인증서를 생성하고 Nginx를 기반으로 HTTPS 서버를 빌드하는 방법에 대해 자세히 소개했습니다. 링크 : Nginx는 HTTPS 서버를 구축합니다.
HTTPS 통신의 안드로이드 구현
여러 가지 이유로 httpclicent 클래스를 사용하여 Android가 HTTPS 연결을 구축하는 방법을 설명하십시오. 코드 데모는 다음과 같습니다.
MainActivity.java
Com.example.Pache.httpresponse import java.io.httpstatus; client.httpclient; android.widget.widget.widget.textview; super.oncreate (savedinstancestate) setContentView (r.layout.Activity_Main); ) {runhttpsconnecti on ();}}); httpstask.getstatus () == Statushed) {httpstst ask = new createhtpsconntask (); sbuffer = @override protected void doinbackground (void) {httpurirequest request = new httpppost (https_example_url); ; if (httpresponse! = null) {statusline statusline = httpresponse.getStatusline (); (http response.getentity (). "utf-8"; (예외 {https ", e.getMessage ()} {reader! = null () {reader.close (); ) {log.e ( "https", e.getMessage ()); 마침내 {} return null;} @override void onpostExecute (void result) {컨텍스트보기 .settext (sbuffer .toString ());}}}}
httputils.java
com.example.photocrop; httpversion; conn.scheme.scheme; .apache.basichtpparams; httpprotocolparams; newttppara ms (); istry (); etfactory (), 80) schreg.register ( "https", sslsocketfactory. getSocketConnectionManager connmgr = params, schreg); ) {basichtpparams = httpprotocals.http_1_1); iSter (새로운 계획) "http", plainsocketsocketsocketfactory (), 80); 새로운 체계 ( "https", mysslsocketfactory.getsocketfactory (), 443); Reture new defaulttpclient (connmgr, params); httpclient getspect (context context) {basichttpparams params = httpprotocolparams. s, true); schemeregistry schreg = new schemeregistry (); "HTTP", plainsocketfactory.getSocketFactory (Context, 443); }}
Activity_Main.xml
<linearlayout xmlns : android = "http://schemas.android.com/apk/res/android"xmlns : thool = "http://schemas.android.com"android : lay out_width = "match_parent"android : layout_height = "match_pareat"Android : 오리엔테이션 = "수직"> <버튼 안드로이드 : id = "@+id/create_button"android : layout_ "match_ parent"id : layout_height = "wrap_content"Android : "@String/hello_world"Android : textsize = "16SP" /> <TextView Android : id = "@+id /content_textView"Android : layout_width = "match_parent"Android : layout_height = "Wra P_Content"Android : "Center"Android : textsize = "16sp" / /> </ linearLayout>
Android는 defaulthttpclient를 사용하여 https 연결을 추가해야합니다.
Schreg.register (new scheme ( "https", sslsocketfactory.getSocketFactory (), 443);
https의 지원에 참여하면 "https://www.google.com.hk"와 같은 HTTPS 연결을 효과적으로 설정할 수 있지만 Nginx가 구축 한 HTTPS 서버를 기반으로 액세스 할 수는 없습니다. 시스템에서 사용하지 않으면 시스템에서 사용하지 않습니다.
사용자 정의 인증서를 사용하고 확인 된 HTTPS 연결 방법을 무시하십시오.
인증서를 해결하는 방법은 시스템에 의해 인식되지 않습니다. 시스템 검증을 건너 뛰는 것입니다. 시스템 검증을 건너 뛰려면 더 이상 시스템 표준 SSL SocketFactory를 사용할 수 없습니다. 그런 다음이 사용자 정의 SSL SocketFactory에서 확인을 건너려면 모든 검증, 즉 신뢰할 수있는 모든 검증을 무시하는 TrustManager를 사용자 정의해야합니다.
com.example.porime java.net.socket.scur java.security.security. java.security .xl.x509trustmanager; import org.apache.http.sslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslslcontex EmentException, keystorexception, uncoververableKexception {Super (TrustStore); new x509trustmanager () {@override public x509certified [] geta cceptedisssuers () {return null;} @override public void checkservertrusted (x509certified [] authtype) throws {} @epuall public void checkclittrusted [x509certified [] 체인, string auxttype. ) 인증서 {}}; (소켓 소켓, 문자열 포트, 부울 autoclose), unknownhostexception {return sslcontext.getSocketfactory () (소켓, 호스트, 포트, autoclose); )); 신뢰할 수 있습니다 (NULL, null);
동시에 구축 한 SSLSocket으로 변경하려면 DefaultTtPclient의 레지스터 메소드를 수정해야합니다.
공공 httpclient getcustomclient () {basichtpparams = httpprotocolparams p_1_1; iSter (새로운 계획 ( "HTTP ", plainsocketFactory.getSocketFactory (), 80)); Schreg.register ("httpsoc "kectory.getSocketfactory (), 443); clientConnectionManager = new ThreadSafeClientConnmanager (Params, Schreg); Return New DefaultTPclient (connemmgr, params);};
이러한 방식으로 Nginx 기반 HTTPS 가상 사이트에 성공적으로 액세스 할 수 있습니다.
결함:
그러나이 솔루션은 HTTPS를 사용하지만 클라이언트와 서버의 통신 내용이 암호화되지만 스니핑 프로그램은 전송 내용을 얻을 수 없지만 "중개인 공격"에 저항 할 수는 없습니다. 예를 들어, 내부 네트워크에서 DNS를 구성하고 대상 서버 도메인 이름을 로컬 주소로 분석 한 다음이 주소의 에이전트로 중간 서버를 사용하여 실제 서버에 연결되어 있습니다. 인증서. 이러한 방식으로, 모든 커뮤니케이션 컨텐츠는이 에이전트를 통과시키고 클라이언트가 인식하지 않으며, 이는 클라이언트의 비 검사 서버 공개 키 인증서로 인해 발생합니다.
사용자 정의 인증서를 사용하여 HTTPS 연결을 설정하십시오
위 제도에 의해 야기 될 수있는 "중간 공격"을 방지하기 위해 서버 -사이드 공개 키 인증서를 다운로드 한 다음 공개 키 인증서를 Android 애플리케이션에 컴파일하여 인증서 자체를 확인할 수 있습니다.
Keystore를 생성하십시오
사용자 정의 인증서를 확인하려면 먼저 KeyTool 도구를 사용하여 KeyStore 파일을 생성해야합니다. 여기서 인증서는 대상 서버의 공개 키를 나타냅니다. 이는 웹 서버에서 구성된 .crt 파일 또는 .pem 파일에서 얻을 수 있습니다. 동시에 Bouundcastle을 구성해야합니다.
keyTool -ImportCert -V -TrustCacerts -Alias 예제 -File www.example.com.crt -keystore example.bks -storetype bks -providerclass rovider.boundcastleprovider -providerpath/wzy/downloads/java/jdk1 .7.0_60/ JRE/LIB/EXT/BCPROV-JDK16-145.JAR-STOREPASS PW123456
실행 후 인증서의 내용이 표시되고 입력 할 수 있는지 확인하라는 메시지가 표시됩니다.
KeyStore 파일의 제작 후에 성공한 후 앱 응용 프로그램의 RES/RAW 디렉토리에 넣으십시오.
커스텀 키 스토어를 사용하여 연결 아이디어를 구현하려면 Trushall과 유사합니다. 그러나 인증서도 필요합니다.
com.example.pormite java.io.inputstream; java.security. importectory는 sslsocket actory를 확장합니다 );} public static sslestrest inult {input.gettresources () ;} catch (예외 e) {e.printstacktrace ();} 마지막으로 {if (input! = null) {try {input.close ();} catch (ioxception e) {e.printstacktrace ();}. 입력 = null;}}}}}}}}}}}}}
동시에 구축 한 SSLSocket으로 변경하려면 DefaultTtPclient의 레지스터 메소드를 수정해야합니다.
공공 정적 httpclient getspecilkeystoreclient (컨텍스트 컨텍스트) {basichttpparams = new basichttpparams (params, httpversion.http_1_1); Schemeregistry Schreg = 새로운 Schemeregistry ( schreg.register ( "http", plainsocketfactory.getSocketFactory (80)); 매개 변수);}}