/ django

PythonAnywhere - Let's Encrypt 보안인증서 적용하기

기존 제가 운영했던 개인 웹사이트의 도메인을 HTTP에서 HTTPS로 이전하기 위해, PythonAnywhere에서 Let’s Encrypt 무료 보안인증서를 적용하는 과정을 설명합니다.

http://www.sujinlee.mehttps://www.sujinlee.me 로 적용했습니다.

HTTPS가 처음인 분들은 오픈튜토리얼스 — HTTPS와 SSL인증서를 읽고 오시면 도움이 될 것입니다.

Let’s Encrypt

Let’s Encrypt는 무료로 개방적인 인증서를 발급하는 자동 인증 서비스 기관(CA)입니다. 이로써 누구나 간단하게 웹 사이트 통신 암호화할 수 있습니다. Let’s Encrypt은 IETF에서 표준화된 ACME라는 오픈 프로토콜을 사용하고 있습니다. 과거 HTTPS를 사용하기 위해 SSL을 구매해야 했고, 인증서 취득 프로세스가 매우 복잡했습니다. 그리하여 Lets’ Encrypt는 2015년부터 SSL을 무료로 제공함으로 안전한 웹을 실현하기 위해 무료로 암호화 보급을 하고 있습니다.

1. dehydrated 패키치 설치하기

dehydrated 패키지를 사용해 Let’s Encrypt 인증서를 발급받습니다. dehydrated을 사용하면 루팅 권한을 설정하지 않고도 편하게 인증서를 발급받을 수 있습니다.
PythonAnywhere 배시(Bash) 콘솔을 열고, 까만색 콘솔 창에서 home 디렉토리로 진입합니다.

07:01 ~ $ cd ..
07:02 /home $

홈(home) 디렉토리에서 아래 명령어를 실행하여 패키지를 설치합니다.

git clone https://github.com/lukas2511/dehydrated.git ~/dehydrated

아래와 같은 메세지가 나오면 설치가 완료된 것입니다.

04:58 /home $ git clone https://github.com/lukas2511/dehydrated.git ~/dehydrated
Cloning into '/home/sujinleeme/dehydrated'...
remote: Counting objects: 1271, done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 1271 (delta 5), reused 0 (delta 0), pack-reused 1255
Receiving objects: 100% (1271/1271), 361.55 KiB | 0 bytes/s, done.
Resolving deltas: 100% (769/769), done.
Checking connectivity... done.

dehydrate폴더가 home 디렉토리 내 새로 생성되었습니다.
완료되면, 키와 인증서 등 관련 파일이 저장될 새 디렉토리 letsencrpyt/wellknown 를 같은 home 디렉토리내 생성합니다.

mkdir -p ~/letsencrypt/wellknown
cd ~/letsencrypt

2. 정적파일 경로 연결하기

이제 PythonAnywhere가 wellknown 디렉토리에서 정적파일을 제공할 수 있게 해야합니다.
PythonAnywhere의 로고를 클릭하고 Web tab을 눌러 이동한 다음, Static files으로 가세요. 아래 처럼 정적 URL(Static URL)과 경로를 설정해주세요.

  • Static URL: /.well-known/acme-challenge
  • Static Path: /home/계정이름/letsencrypt/wellknown

http://www.sujinlee.me/.well-known/acme-challenge/xxxx 으로 연결될 겁니다.
입력 후 앱을 새로고침하세요.

3. Config file 생성하기

이제 config 파일을 letsencrypt폴더 내 생성합니다.
Files 탭으로 이동하여 Files 부분에 config라는 파일명을 입력하면 새 파일이 생성됩니다.

그리고 아래 에디터 화면에 아래 내용을 입력하세요.

WELLKNOWN=/home/계정이름/letsencrypt/wellknown

4. 인증서 발급받기

Bash콘솔로 들어가, letsencrypt디렉토리로 들어가 아래 명령어를 입력해 인증서를 요청합니다. www.도메인이름.com 대신 사용하는 실제 도메인 명을 입력합니다.

~/dehydrated/dehydrated --cron --domain www.도메인이름.com --out . --challenge http-01

이런 내용이 콘솔에 보이면 인증서가 발급된 겁니다.

# INFO: Using main config file /home/sujinleeme/letsencrypt/config
+ Generating account key...
+ Registering account key with ACME server...
Processing www.sujinlee.me
 + Signing domains...
 + Creating new directory ./www.sujinlee.me ...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for www.sujinlee.me...
 + Responding to challenge for www.sujinlee.me...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!
  • /home/계정이름/letsencrypt 디렉토리는 인증서 재발급 시, 필요한 정보를 담고 있기 때문에 보안에 유의해야 합니다.

letsencrypt 폴더 내 accounts, www.sujinee.me 도메인 폴더가 새로 생성 되었습니다.

09:22 ~/letsencrypt $ ls
accounts config wellknown www.sujinlee.me
  • 인증서 만기가 되어, 갱신이 필요하면 처음 발급시 입력한 동일한 명령어를 입력하면 됩니다. 그리고 인증서 설치 요청 메일을 다시 보내야합니다.

5. 인증서 설치 요청하기

발급받은 인증서가 설치되려면 support@pythonanywhere.com에게 메일 또는 Send Feedback 채널을 통해 연락해야합니다. 계정이름, 경로, 도메인 명을 간단하게 적어주면 됩니다.

Please apply https to my site.
path : /home/sujinleeme/letsencrypt/accounts
username: sujinleeme
website link: www.sujinlee.me

<img width="100%" src="https://cdn-images-1.medium.com/max/1600/1*VOby_lIzNlSGwGRcJ4KvCw.png/>

적용까지 걸리는 시간은 정확하진 않지만 5시간 내외로? 걸렸습니다.
담당자 승인 후 확인 메일이 발송될 겁니다.

6. https 적용 확인하기

이제 자물쇠 버튼이 생겼네.요 :)

크롬 개발자 도구 로 들어가  보안에서 인증서와 보안 내용을 확인해 보세요.

https://www.ssllabs.com/ssltest 에서도 보안 등급 테스트를 할 수 있습니다.

6. Settings.py 수정

1) http URL를 https로 리다이렉트 하기

모든 http를 https로 강제 리다이렉트를 시킬 수 있습니다. 예를 들면, 주소창에 http://sujinlee.me라 입력하면 https://sujinlee.me로 리다이렉트 됩니다. 웹 프레임워크별로 방법이 다릅니다. 프레임워크를 별도로 사용하지 않는 경우, ‘Send Feedback’ 를 누르고 요청사항을 적으면 됩니다.

Please force all connections to go through HTTPS
link: http://www.sujinlee.me

Django 1.8 이상일 경우, settings.py내 아래와 같이 리다이렉트를 명시해주세요.

SECURE_SSL_REDIRECT = True

Django 1.8 아래 버전은 django-sslify 패키지를 설치하세요.

pip install --user django-sslify

그 외 쿠키설정, 프록시설정, CSRF 쿠키설정을 해줘야합니다.

  1. 쿠키설정
    세션쿠키와 CSRF쿠키에 보안을 적용하기 위해 true로 설정합니다.브라우저는 HTTPS 연결 시에만 쿠키 전송을 허락해줍니다.
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
  1. 프록시 설정
    기본적으로 장고 애플리케이션은 프록시가 실행된 이후에 실행되어, 암호화 적용이 되었는지 아닌지를 판단할 수 없습니다. 때문에 실제 배포에서, 보안 적용된 요청임에도 장고 is_secure() 메소드가 False를 반환할 때가 있습니다.
    HTTPS 연결은 프론트엔드 로드벨런스나 리버스-프록시, 내부 프록시 연결을 위한 것인데, 장고 내부 프록시 시스템 연결은 HTTPS가 아니기 때문입니다. 보통 이런 경우에는 프록시 서버에 보안된 외부 연결 여부를 나타내는 헤더를 (“header”, ”value”)로 설정하여 제공합니다.

request.META(HTTP_)값(https)에 설정되어 있으면, 장고는 HTTPS를 통해 들어오는 안전한 요청이라고 판단하여 is_secure() 메소드를 True로 반환합니다.

https://docs.djangoproject.com/en/1.10/ref/settings/#secure-proxy-ssl-header
SECURE_PROXY_SSL_HEADER = (‘HTTP_X_FORWARDED_PROTOCOL’, ‘https’)
정리하면, settings.py에는 아래내용이 추가되어야 합니다.
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

다시 터미널로 돌아와 python manage.py runserver 명령어로 로컬 개발 서버를 실행하면 아래와 같은 에러 메세지가 뜰겁니다.

You’re accessing the development server over HTTPS, but it only supports HTTP.

개발서버에서 HTTPS를 지원하지 않기 때문입니다.
때문에 개발 서버에서도 HTTPS로 접속하게 설정해줘야 합니다. django-sslserver 패키지를 사용하면 개발 서버와 production 모두 SSL을 사용할 수 있습니다.

8. django-sslserver 패키지 설치하기

로컬 가상환경과 Pythonanywhere 가상환경 둘다 모두 아래 명령어를 입력해 설치해주세요.

$ pip install django-sslserver

settings.py 에서 INSTALLED_APPS 부분에 아래 sslserver 앱을 추가하세요.

INSTALLED_APPS = (...
"sslserver",
...
)

이제 명령어를 입력해 SSL-enabled 디버그 서버를 시작하세요. 기존 서버 실행 명령어가 python manage.py runserver 에서 runsslserver로 바뀌었습니다.

$ python manage.py runsslserver

그러면 https://127.0.0.1:8000/ 로 연결될 겁니다. 터미널에서 아래와 같이 나온다면 잘 작동하고 있는 겁니다.

(sujinvenv) Sujins-MacBook-Pro:sujin-web sujin$ python manage.py runsslserver
Validating models...
System check identified no issues (0 silenced).
October 23, 2016 - 23:04:01
Django version 1.9, using settings 'mysite.settings'
Starting development server at https://127.0.0.1:8000/
Using SSL certificate: /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/sslserver/certs/development.crt
Using SSL key: /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/sslserver/certs/development.key

포트를 바꿔 연결 하고 싶다면 다음과 같이 할 수 있습니다.

$ python manage.py runsslserver 127.0.0.1:9000

그러면 https://127.0.0.1:9000/에 연결되겠죠?
지금까지 PythonAnywhere에서 HTTP에서 HTTPS로 이전하는 방법, 개발환경에서도 HTTPS를 사용하는 방법을 살펴보셨습니다.
해피 코딩!