Tag Archives: SSL

macOS Mojave 에서 SSL 지원하는 Apache 웹서버 설치하기

이번에 새롭게 출시된 macOS 모하비에서 Apache를 설치하는 방법을 정리 해 보겠습니다. 또한 추가로 HTTPS 프로토콜을 지원하는 설정도 함께 적어보도록 하겠습니다. 이글은 macOS에서 Homebrew를 사용중인것을 가정하고 작성되었습니다.

과거 시에라등의 버전에서는 Apache 웹서버가 기본적으로 설치가 되어있습니다. 계속해서 업데이트를 해왔다면 해당 아파치 웹서버가 그대로 살아있을수 있으니 다음과 같은 방법으로 제거를 해줍시다.

$ ps aux | grep httpd
_www               232   0.0  0.0  4329504    936   ??  S    12:12AM   0:00.00 /usr/local/opt/httpd/bin/httpd -D FOREGROUND
_www               231   0.0  0.0  4321312    908   ??  S    12:12AM   0:00.00 /usr/local/opt/httpd/bin/httpd -D FOREGROUND
_www               230   0.0  0.0  4329504    888   ??  S    12:12AM   0:00.03 /usr/local/opt/httpd/bin/httpd -D FOREGROUND
_www               229   0.0  0.0  4321312    932   ??  S    12:12AM   0:00.00 /usr/local/opt/httpd/bin/httpd -D FOREGROUND
_www               228   0.0  0.0  4329504    924   ??  S    12:12AM   0:00.00 /usr/local/opt/httpd/bin/httpd -D FOREGROUND

위와 같이 돌아가고 있는 httpd 프로세스가 있는것을 확인하였다면 다음의 명령을 사용하여 종료하고 기본 구동 서비스에서도 삭제 해 줍니다.

$ sudo apachectl stop
$ sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist

위와 같은 명령을 사용하고 기본적으로 설치되어있는 아파치 웹서버를 더이상 실행되지 않도록 변경할 수 있습니다. 이번에는 새로운 아파치 2.4 버전을 Homebrew를 사용하여 설치한 뒤 서비스로 구동하는 방법을 알아보겠습니다.

$ brew install httpd24 --with-privileged-ports --with-http2

위와 같은 명령을 사용하여 매우 간단하게 아파치 웹서버 2.4 버전을 설치할 수 있었습니다. –with-privileged-ports 옵션을 1024 이하의 낮은 숫자의 시스템 포트를 사용하기 위해서 사용하는 옵션입니다. 이 옵션을 사용하여 80 포트를 사용할 수 있게 되며 8080과 같은 포트를 사용하려면 굳이 이 옵션을 사용하실 필요가 없습니다.

이제 아파치의 설정 파일을 수정하여 80 포트로 구동되도록 수정하겠습니다.

$ vi /usr/local/etc/httpd/httpd.conf

다음의 내용을 찾아서

Listen 8080

다음과 같이 수정합니다.

Listen 80

이제 다음의 명령을 사용하여 웹서버를 구동할 수 있습니다.

$ sudo brew services start httpd24

위에서 설명했던것과 같이 1024 이하의 시스템 포트를 사용하려면 sudo를 사용하여 root 권한으로 구동해야 합니다. 이후의 포트를 사용하려면 굳이 sudo를 사용하지 않아도 사용이 가능합니다.

정상적으로 설치가 되었고 구동이 되었다면 웹브라우저를 통해서 localhost에 접속해 보면 “It works!”라는 문자열 출력을 확인하실 수 있습니다.

이번에는 SSL 설정을 해보도록 하겠습니다. 다시한번 아파치 웹서버 설정 파일을 수정 해 보겠습니다.

$ vi /usr/local/etc/httpd/httpd.conf

다음의 4가지 항목을 찾아서 모두 주석을 해제 해 줍니다.

#LoadModule socache_shmcb_module lib/httpd/modules/mod_socache_shmcb.so
#LoadModule ssl_module lib/httpd/modules/mod_ssl.so
#Include /usr/local/etc/httpd/extra/httpd-vhosts.conf
#Include /usr/local/etc/httpd/extra/httpd-ssl.conf

또한 ServerName 항목을 찾아서 주석을 해제하고 다음과 같이 내용을 수정 해 줍니다.

ServerName localhost:80

httpd.conf 파일의 수정은 완료되었고 이번에는 httpd-ssl.conf 파일을 수정 해 보겠습니다.

$ vi /usr/local/etc/httpd/extra/httpd-ssl.conf

다음의 내용을 찾아서

Listen 8443

다음과 같이 수정 해 줍니다.

Listen 443

추가로 좀 더 밑으로 가서 다음의 내용을 찾아서

<VirtualHost _default_:8443>

# General setup for the virtual host
DocumentRoot "/usr/local/var/www"
ServerName www.example.com:8443
ServerAdmin you@example.com

다음과 같이 수정 해 줍니다.

<VirtualHost _default_:443>

# General setup for the virtual host
#DocumentRoot "/usr/local/var/www"
#ServerName www.example.com:443
#ServerAdmin you@example.com

이번에는 httpd-vhosts.conf 파일을 수정하여 가상호스트 설정을 해 보겠습니다.

$ vi /usr/local/etc/httpd/extra/httpd-vhosts.conf

이미 몇개의 가상호스트 설정이 있습니다만, 모두 주석 처리 해 주고 다음의 두가지 설정을 추가 해 줍니다.

<VirtualHost *:80>
    DocumentRoot /usr/local/var/www
    ServerName localhost
</VirtualHost>

<VirtualHost *:443>
    DocumentRoot /usr/local/var/www
    ServerName localhost
    SSLEngine on
    SSLCertificateFile "/usr/local/etc/httpd/server.crt"
    SSLCertificateKeyFile "/usr/local/etc/httpd/server.key"
</VirtualHost>

여기서 눈여겨 봐야 하는 부분은 DocumentRoot 설정을 통해서 /usr/local/var/www를 웹서버의 기본 리소스 디렉토리로 설정했다는것과 443포트 연결에 대해서 SSLEngine이 on되었고 추가로 SSLCertificateFile와 SSLCertificateKeyFile 세팅이 되었다는 점 입니다.

DocumentRoot의 설정은 본인의 개발 환경에 맞게 설정 해 주시면 됩니다.

이번에는 로컬에서만 사용될 Self-Signed 인증서를 만들어보도록 하겠습니다. 여기서 만들 인증서 파일을 사용하겠다는 설정은 이미 위에서 해두었습니다. 다음의 명령어를 사용하여 인증서를 만드시면 됩니다.

$ cd /usr/local/etc/httpd
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt
Generating a 2048 bit RSA private key
.............+++
.......................................................................................+++
writing new private key to 'server.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:KR
State or Province Name (full name) []:Gyeonggi-do
Locality Name (eg, city) []:Seongnam-si
Organization Name (eg, company) []:MyCompany
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:
Email Address []:

이제 다 된것 같습니다. 다음의 명령을 사용하여 설정이 정상적으로 되었는지 확인이 가능합니다.

$ sudo apachectl configtest
Syntax OK

이제 웹브라우저를 재시행하여 http://localhost https://localhost 둘 모두 접속이 잘 되는것을 확인 해 봅시다.

$ sudo brew services restart httpd24

Google Play 안전하지 않은 onReceivedSslError 경고 대응하기

logo-google-play-vetor

요즘 들어 구글플레이에 등록한 앱의 코드 레벨의 검증이 수행되고 있나 봅니다. 이번에는 웹뷰를 구현할때에 필히 사용되는 WebViewClient 클래스의 onReceivedSslError 의 처리가 안전하지 않다는 경고가 뜨는 사례가 발생하고 있는데요. 현재 이부분을 정상적으로 처리하지 않은 앱의 경우 업데이트가 이루어지지 않고 있습니다. 이 오류의 대상자가 되면 받는 메일의 내용은 다음과 같습니다.

애플리케이션에 WebViewClient.onReceivedSslError 핸들러가 안전하지 않은 방식으로 구현되었습니다. 특히 해당 구현은 모든 SSL 인증서 확인 오류를 무시하여 앱을 중개인 공격에 취약하게 만듭니다. 공격자는 영향을 받은 WebView의 콘텐츠를 변경하고, 전송된 데이터(예: 로그인 사용자 인증 정보)를 읽고, 자바스크립트를 사용해 앱 내부에서 코드를 실행할 수 있습니다.

SSL 인증서를 제대로 확인하려면 서버에서 제공하는 인증서가 요구사항을 충족할 때마다 코드를 변경하여 SslErrorHandler.proceed()을(를) 호출하고 그렇지 않으면 SslErrorHandler.cancel()을(를) 호출합니다. 대상 앱 및 클래스를 포함하는 이메일 알림이 개발자 계정 주소로 전송됩니다.

최대한 빨리 취약점을 해결하고 업그레이드된 APK의 버전 번호를 올리시기 바랍니다. SSL 오류 핸들러에 대한 자세한 내용은 개발자 도움말 센터의 Google 문서를 참조하시기 바랍니다. 다른 기술 관련 질문은https://www.stackoverflow.com/questions에 게시하고 ‘android-security’ 및 ‘SslErrorHandler’ 태그를 사용하세요. 이 문제에 대한 책임이 있는 타사 라이브러리를 사용하는 경우 타사에 문의하여 이 문제를 해결하시기 바랍니다.

제대로 업그레이드되었는지 확인하려면 업데이트된 버전을 개발자 콘솔에 업로드하고 5시간 후에 다시 확인하세요. 앱이 제대로 업그레이드되지 않은 경우 경고 메시지가 표시됩니다.

이러한 특정 문제가 WebView SSL을 사용하는 일부 앱에는 영향을 미치지 않을 수 있으나 모든 보안 패치를 최신 상태로 유지하는 것이 좋습니다. 사용자를 보안 위험에 노출시키는 취약점을 보유하고 있는 앱은 Google의 악의적 행위 정책 및 개발자 배포 계약의 섹션 4.4를 위반하는 것으로 간주될 수 있습니다.

게시된 모든 앱이 개발자 배포 계약 및 개발자 프로그램 정책을 준수하는지 확인하시기 바랍니다. 궁금한 점이나 우려되는 사항이 있으면 Google Play 개발자 도움말 센터를 통해 지원팀에 문의하세요.

혹은 영어 버전의 경고 메일의 내용은 다음과 같습니다.

Security alert Your application has an unsafe implementation of the WebViewClient.onReceivedSslError handler. Specifically, the implementation ignores all SSL certificate validation errors, making your app vulnerable to man-in-the-middle attacks. An attacker could change the affected WebView’s content, read transmitted data (such as login credentials), and execute code inside the app using JavaScript.

To properly handle SSL certificate validation, change your code to invoke SslErrorHandler.proceed() whenever the certificate presented by the server meets your expectations, and invoke SslErrorHandler.cancel() otherwise. An email alert containing the affected app(s) and class(es) has been sent to your developer account address.

Please address this vulnerability as soon as possible and increment the version number of the upgraded APK. For more information about the SSL error handler, please see our documentation in the Developer Help Center. For other technical questions, you can post to https://www.stackoverflow.com/questions and use the tags “android-security” and “SslErrorHandler.” If you are using a 3rd party library that’s responsible for this, please notify the 3rd party and work with them to address the issue.

To confirm that you’ve upgraded correctly, upload the updated version to the Developer Console and check back after five hours. If the app hasn’t been correctly upgraded, we will display a warning.

Please note, while these specific issues may not affect every app that uses WebView SSL, it’s best to stay up to date on all security patches. Apps with vulnerabilities that expose users to risk of compromise may be considered dangerous products in violation of the Content Policy and section 4.4 of the Developer Distribution Agreement.

Please ensure all apps published are compliant with the Developer Distribution Agreement and Content Policy. If you have questions or concerns, please contact our support team through the Google Play Developer Help Center.

문제가 되는 코드는 WebViewClient를 구현한 다음과 같은 코드입니다. SSL 오류가 발생하면 묻지도 따지지도 않고 그것을 수용하는것을 확인하실 수 있습니다.

@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
  handler.proceed();
}

원래는 이곳에 이 유효하지 않은것으로 판단되는 인증서가 문제가 없는지 판단하고 문제가 없을 경우 proceed()를 호출하거나 아닌 경우 cancel()을 호출하도록 처리해 주시면 됩니다. 이 판단을 하는 부분을 어떻게 구현할지는 각 앱마다 혹은 회사마다 다르겠지만 스택오버플로우에서 좋은 예를 발견하였습니다.

invalid_ssl_certificate_theeye

위의 스크린샷은 웹브라우저에서 유효하지 않은 인증서를 가진 HTTPS 홈페이지에 진입할 때 볼 수 있는 경고입니다. 여기에 주목할 부분은 “안전하지 않음(으)로 이동”이라는 문구인데요. 안전하지 않지만 유저가 진입할지 말지를 결정할 수 있게 함으로써 브라우저의 책임을 다했다는 것일까요?

마찬가지로 Android에서도 유효하지 않은 인증서로 판단되었을 경우 유저에게 직접 물어보면 됩니다.

@Override
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
  final AlertDialog.Builder builder = new AlertDialog.Builder(this);
  builder.setMessage(R.string.notification_error_ssl_cert_invalid);
  builder.setPositiveButton("continue", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
      handler.proceed();
    }
  });
  builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
      handler.cancel();
    }
  });
  final AlertDialog dialog = builder.create();
  dialog.show();
}

R.string.notification_error_ssl_cert_invalid 에는 유효하지 않은 사이트에 진입할것인지 물어보는 글이 들어가 있으면 되겠네요. 이와 같은 대응을 한 뒤 버전을 업그레이드 하여 구글 플레이에 등록하게 되면 5시간정도 뒤에 해당 경고가 사라지게 됩니다.

참고 : http://stackoverflow.com/questions/36050741/webview-avoid-security-alert-from-google-play-upon-implementation-of-onreceiveds