Tag Archives: apache

macOS Sierra 기준 Homebrew를 이용하여 APM 설치하기

macos-sierra-logo

이번에는 새로 출시된 macOS 시에라에서 Apache, PHP, MySQL을 설치하여 서비스로 구동하는 과정을 정리해보겠습니다. 이 모든작업들 역시 Homebrew를 사용하면 손쉽게 해낼 수 있습니다. 우선 이 글은 Homebrew가 정상적으로 설치되어있는 맥이 준비되어있다고 가정하고 작성되었습니다.

우선 설치할 것들에 대한 준비를 위해 tap 명령을 사용하여 별도의 저장소를 추가하도록 합니다. 이 명령은 Homebrew의 master 저장소에 없는 패키지들을 사용할 수 있도록 해줍니다.

MariaDB 설치

MySQL 대신에 제가 선호하는 MariaDB를 설치하도록 하겠습니다. 다음의 명령을 사용하여 매우 간단하게 설치할 수 있습니다.

설치가 완료되면 다음의 명령을 수행하여 초기에 필요한 기본 디비 구성을 할 수 있습니다.

이제 준비가 끝났으니 MariaDB를 서비스 형태로 구동해 보겠습니다.

여기까지만 진행하면 익명 상태로 mysql 명령을 사용하여 자유롭게 사용이 가능한 상태가 됩니다만 보안에 취약한 상태가 됩니다. 물론 개인 맥북에서 사용하고 계신 상태라면 크게 문제될 것은 없습니다만 mysql_secure_installation 명령을 사용하면 손쉽게 root 비밀번호를 포함한 보안 상태의 설정을 변경할 수 있습니다.

이제 mysql 명령을 사용하여 내가 결정한 비밀번호로 정상적으로 root 계정에 접속이 되는지 확인을 해봅시다.

Apache 설치하기

macOS 시에라에는 이미 아파치 2.4 버전이 기본 설치되어있습니다. 하지만 지금 설치하려는 Homebrew 패키지들에 의해서 관리하기에 복잡함이 생기므로 기본 설치된 아파치 2.4는 꺼두고 새로운 아파치를 설치해보도록 하겠습니다.

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

간단하게 설치가 완료되었습니다. 위에서 보여지는 –with-privileged-ports 옵션은 2014 이하의 낮은 숫자의 시스템 폰트를 사용하기 위해서 사용하는 옵션입니다. 이 옵션을 사용하여 80번 포트를 사용할 수 있으며 8080과 같은 포트를 사용하실 경우에는 굳이 이 옵션은 필요없습니다. 80번 포트를 사용하여 구동할 경우 보실 수 있듯이 brew services 명령 앞에 sudo를 붙이는것을 볼 수 있습니다.

아파치가 정상적으로 설치되었다면 사용하시는 브라우저에서 localhost로 접속하여 다음과 같은 화면이 뜨는것을 확인하실 수 있습니다.

install-apm-on-macos-sierra01

PHP 설치하기

이제 PHP를 설치해 보도록 하겠습니다. 선호하는 PHP 버전은 다양하게 있겠지만 저의 경우는 5.6을 설치해보도록 하겠습니다. brew search php 명령을 사용하여 사용가능한 PHP 버전을 검색해볼 수 있습니다. 이글을 쓰는 시점에 사용가능한 버전은 5.5 / 5.6 / 7.0 / 7.1 입니다.

조금 빌드 시간이 소요되겠지만 설치가 완료되면 바로 사용할 수 있는건 아니고 아파치에 몇가지 설정을 추가해 주어야 합니다.

Apache에 PHP 설정 추가하기

아파치 설정파일은 2.4 버전의 경우에는 /usr/local/etc/apache2/2.4 에서 찾을 수 있습니다. 본인이 선호하시는 텍스트 에디터를 사용하여 /usr/local/etc/apache2/2.4/httpd.conf 를 열어서 다음의 내용을 찾아봅니다.

위의 내용을 찾으셨다면 다음과 같이 변경을 해주시기 바랍니다. DirectoryIndex 에 값을 추가하였고 FilesMatch 항목을 추가하였습니다.

이제 아파치를 재시작 하겠습니다.

이제 PHP가 정상적으로 구동중인지 확인을 해봐야겠지요. 다음과 같이 PHP 테스트 결과를 출력하는 페이지를 만들어 줍니다. 여기서 알 수 있듯이 기본적으로 아파치 기본 도큐먼트 디렉토리는 /usr/local/var/www/htdocs 입니다.

이제 다시 한번 브라우저에서 localhost에 접속해보도록 하겠습니다.

install-apm-on-macos-sierra02

정상적으로 phpinfo가 실행된것을 볼 수 있습니다. 조금 밑으로 내려보시면 MySQL(MariaDB) 역시 정상적으로 연동이 되어있는것을 확인해 볼 수 있습니다.

install-apm-on-macos-sierra03

다 좋은데 date 쪽 항목에서 다음과 같은 경고가 뜨고 있는것을 볼 수 있습니다.

install-apm-on-macos-sierra04

시스템의 타임존 설정이 제대로 되어있지 않다는것인데요. 이렇게 된 김에 이부분의 설정도 해보도록 하겠습니다. php.ini 파일을 수정해야 하는데 /usr/local/etc/php/5.6 안에 있습니다. Date 항목을 찾아서 date.timezone의 내용이 주석처리 되어있는데 다음과 같이 수정해주시면 됩니다.

이제 준비는 완료되었고 마지막으로 한번 더 아파치를 재시작 해주시면 됩니다.

 

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

logo-google-play-vetor

구글이 기존의 수많은 앱들의 X509TrustManager를 무력화 시켜 구현한 것에 대한 대응을 나선 것 같습니다. 현재 HTTPS 통신을 위해 SSL 관련된 코드를 구현하였지만 그 방법이 잘못된 경우에 대해 구글 플레이에서 다음과 같은 경고가 뜨고 있습니다.

앱이 Apache HTTP 클라이언트가 있는 X509TrustManager 인터페이스의 안전하지 않은 구현을 사용하고 있어 보안 취약성에 노출되었습니다. 취약성 수정 마감일 등 자세한 내용은 Google 도움말 센터의 이 도움말을 참조하세요

영문판의 경우의 경고 메시지는 다음과 같습니다.

Your app is using an unsafe implementation of the X509TrustManager interface with an Apache HTTP client, resulting in a security vulnerability. Please see this Google Help Center article for details, including the deadline for fixing the vulnerability.

구글플레이에 앱을 출시하고 5시간(저의경우에는 하루정도 뒤에 확인 가능했었습니다)정도 뒤에 구글플레이에 앱 리스트에 경고 표시가 다음과같이 표기됩니다.

google_play_warning_x509trustmanager

이는 다음과 같은 코드가 앱내에 존재할 경우 발생하는 경고이며 2016년 5월 17일부터 해당 문제가 해결되지 않은 앱들을 차단할 예정이라고 합니다.

문제가 되는 부분은 checkServerTrusted 메소드의 내부 구현이 아무것도 없는것에서 기인합니다; 정확하게는 위의 코드는 SSL의 동작을 완벽하게 무력화 시켜 인증 여부를 보장할 수 없는 누구와도 통신할 수 있게 된 상태를 야기합니다. 만약 TrustManager를 커스터마이징해서 사용해야 하는 경우  내부에 원치 상황에 대해 CertificateException 또는 IllegalArgumentException 예외를 발생시키는 코드를 구현해야 합니다.

우선 문제가 되는 Apache의 HttpClient를 사용하는 올드한 형태의 예제를 확인해 보겠습니다.

그리고 다음의 코드는 개발하신 스타일에 따라 다른 모습이겠지만 SSLSocketFactory와 X509TrustManager를 구현한 코드입니다. 위의 코드에서 MySSLSocketFactory라는 이름으로 가져다 사용하고 있습니다.

SSLSocketFactory를 상속하여 내부적으로 커스터마이징 된 X509TrustManager를 사용한 SSLContext를 통하여 소켓을 생성하도록 구현되어있습니다. 이렇게 생성한 SSL Socket은 보안에 취약한 상태입니다.

사실 정상적인 CA가 발급한 SSL 인증서로 구축된 서버라면 다음과 같은 코드만으로 통신에 문제가 없습니다.

하지만 TrustManager를 무력화 시키면서까지 HTTPS 통신을 하려 했다는건 인증서 비용등의 문제로 자체 발급한 Self-Signed 인증서를 사용중이기 때문이 아닐까 생각됩니다. 확인 할 수 없는 인증서로 인한 통신 불가 상황에서는 다음과 같은 예외가 발생합니다.

이 문제를 해결하는 가장 간단한 방법은 정상적인 CA가 발급한 인증서를 구매하여 서버에 채택하고 위쪽의 예제 코드처럼 SSLSocketFactory 를 기본 형태로 사용하는 방법입니다.

하지만 여전히 자체 발급한 인증서로도 구글의 권고안을 따라 문제를 해결할 수 있습니다. TrustManager를 재구현하면서 무력화 시킨 코드가 문제가 되기 때문에 TrustManager를 무력화 시키지 않는 방법으로도 해결을 해보도록 하겠습니다.

우선 자체 발급한 인증서는 일반적인 공인된 CA들이 인증해 주지 않는다는것이 중요하므로 자체적인 CA의 인증서를 앱내에 탑재하여 인증을 가능케 하는 방법이 있습니다. 인증서 자체 발급에 대해서는 [Self-Signed SSL로 Apache HTTPS 구현하기]를 참고해주시기 바랍니다.

앱내에 탑재될 인증서는 CA의 PEM 포맷의 인증서이며 위의 참고글에서 언급되는 rootCA.crt 파일이 여기에 해당됩니다. 이 인증서의 내용은 BASE64 인코딩이 되어있는 형태입니다. 이것을 이용하여 코드를 수정해 보겠습니다.

다른 많은 예제들은 인증서를 앱내에 파일로 포함하여 FileInputStream등으로 읽어서 쓰는 예시가 많았습니다만 파일을 앱에 포함할 정도면 텍스트를 그대로 하드코딩 해도 문제가 되지 않겠다고 생각되어 위와 같이 작성 해 보았습니다. 위에서 언급되었던 잘못된 MySSLSocketFactory의 구현은 다음과 같이 변경되었습니다.

위와 같이 수정 후 통신 테스트를 해보면 잘 되는 것을 확인할 수 있습니다. 해당 CA로 부터 발급된 모든 인증서가 적용된 서버들과 통신이 문제없이 가능합니다. 만약에 지정한 CA 인증서와 연관이 없는 인증서가 적용된 서버일 경우 다음과 같은 오류가 발생합니다.

만약에 서버의 CA인증서 존재 여부가 불분명하고 자체 발급하여 사용중인 인증서 역시 확인하기가 어렵다면 아쉬운대로 다음과 같은 명령을 사용하여 자체 발급된 인증서를 확인 하실 수 있습니다.

s_client 명령을 사용하여 통신하고자 하는 서버의 인증서를 확인 할 수 있습니다. 이는 CA 인증서는 아니지만 이렇게 조회된 인증서를 이용해도 1:1간의 통신에는 문제가 없습니다.

문제를 해결하고 Version Code를 올린 APK를 재등록하고 하루정도가 지나면 해당 경고메시지가 사리지는것을 확인하실 수 있습니다.

스크린샷 2016-02-22 오후 3.26.24

참고 :

  • https://support.google.com/faqs/answer/6346016
  • https://developer.android.com/intl/ko/training/articles/security-ssl.html#UnknownCa