개인 웹사이트 보안 강화: 클라이언트 인증서로 나만의 보안 웹사이트 설정
아무도 접근할 수 없는 나만의 보안 웹사이트로 설정하세요.
중요한 정보를 지기키 위해 반드시 필요합니다.
Apache 웹서버에 클라이언트 인증서 인증을 구현하여 지정된 기기에서만 웹사이트 접속을 허용하는 방법을 단계별로 안내합니다.
목적
요즘은 웹어플리케이션 만들기가 참 쉽습니다.
오픈소스를 이용해도 되고, 웹호스팅도 무료인 것이 많죠.
아니면 서버를 아예 내가 구축할 수도 있습니다.
그런데 요즘은 해킹 기술도 워낙 좋아져서
나 혼자 사용하는 나만의 비밀 정보를 저장하는 웹사이트를 인터넷에 서비스하는게 불안하죠.
아이디/패스워드로 보안을 설정한다고해도 여전히 불안합니다.
ACL을 설정하여 특정 IP에서만 접속이 가능하도록 하면
정보보안은 아주 강화되지만
웹어플리케이션이라는 특성을 살릴 수 없어서 내가 많이 불편해 집니다.
이럴 때는 클라이언트 인증서(Client Certificate)를 사용할 수 있습니다.
마치 ACL과 같이 인증서를 사전에 등록한 디바이스(웹브라우저)에서만 웹사이트에 접속할 수 있게되죠.
나 혼자만 사용하는 보안 웹사이트를 운영할 때 제격입니다.
이 포스팅은 제가 다음에 서버 설정할 때 참고할 수 있도록
제가 서버 설정하였던 과정을 기록합니다.
구현 예정 보안 구조
- 1차 인증: 클라이언트 SSL 인증서 (Apache SSL/TLS 레벨)
- 2차 인증: ID/PW 로그인 (애플리케이션 레벨)
- 결과: 인증서가 없으면 웹사이트 접속 자체가 불가능
이 방법은 은행이나 금융기관에서 사용하는 수준의 보안 수준으로
공격자는 인증서 파일과 비밀번호를 모두 탈취해야만 개인 웹사이트에 접속이 가능합니다.
서버 환경
- 서버: Rocky Linux 9.7
- 웹서버: Apache 2.4
- 도메인: sample-website.com (예시)
- 클라이언트: macOS Safari, Chrome, iPhone Safari
클라이언트 인증서 생성
작업 디렉토리
sudo mkdir -p /etc/httpd/client-certs
cd /etc/httpd/client-certs
CA(Certificate Authority) 개인키 생성
sudo openssl genrsa -aes256 -out ca-key.pem 4096
비밀번호를 입력하라는 메시지가 나타나는데
앞으로 필요할 때 마다 사용하니 기억하기 쉬운 비밀번호로 설정하세요.
참고:
openssl은 암호화 도구로 인증서를 생성하고 관리하는 데 사용합니다~
CA 인증서 생성
sudo openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem
저는 인증서 파일을 완벽하게 관리할 수 있어서 귀찮은 마음에 10년을 설정했습니다. (보안은;;;)
명령어 실행하면 여러 정보를 입력하라고 나오는데 그냥 모두 Enter 입력하고 넘어가도 됩니다.
명령어 인자 의미:
-days 3650: 10년 동안 유효한 인증서-x509: 자체 서명 인증서 형식-sha256: SHA-256 암호화 방식 사용
클라이언트 개인키 생성
sudo openssl genrsa -out client-key.pem 4096
이번에는 비밀번호 없이 그냥 Enter 입력합니다.
클라이언트 인증서 서명 요청(CSR) 생성
sudo openssl req -new -key client-key.pem -out client.csr
여기서도 정보 입력하는 화면이 나오는데 그냥 모두 Enter 입력하고 넘어갑니다.
CA로 클라이언트 인증서 서명
sudo openssl x509 -req -days 3650 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -sha256
이 명령어 실행할 때 아까 CA 개인키 설정할 때 지정한 비밀번호를 입력합니다.
역시나 귀찮은 마음에 기간은 10년.
(10년동안 절대 잃어버리지 말 것!)
브라우저용 PKCS12 파일 생성
sudo openssl pkcs12 -export -out client.p12 -inkey client-key.pem -in client-cert.pem -certfile ca.pem
나중에 웹브라우저에 인증서 설치할 때 입력할 비밀번호를 여기에서 설정합니다.
기억할 수 있는 비밀번호로 지정하세요~
생성된 파일 확인
자, 이제 다음과 같은 파일들이 생성되었습ㄴ디ㅏ.
ca-key.pem: CA 개인키 (유출 금지!)ca.pem: CA 인증서 (Apache 설정용)client-key.pem: 클라이언트 개인키client-cert.pem: 클라이언트 인증서client.csr: 인증서 서명 요청client.p12: 브라우저 설치용 파일
Apache 설정
SSL 설정 파일 수정
https 접속 시 반드시 클라이언트 인증서를 확인하도록 SSL 설정 부분을 변경합니다.
sudo vi /etc/httpd/conf.d/sample-website.com-ssl.conf
기존 conf 파일에서 SSLCertificateKeyFile 줄 아래에 다음의 3줄을 추가합니다.
SSLCACertificateFile /etc/httpd/client-certs/ca.pem
SSLVerifyClient require
SSLVerifyDepth 2
참고로 설정의 의미는 다음과 같습니다.
SSLCACertificateFile: CA 인증서 위치 설정SSLVerifyClient require: 클라이언트 인증서 필수로 지정SSLVerifyDepth 2: 인증서 체인 검증 깊이
수정 후 conf 파일 내용
conf 내용은 웹서버마다 다르니 아래 내용은 참고만 하세요~
<VirtualHost *:443>
ServerName sample-website.com
ServerAlias www.sample-website.com
DocumentRoot /var/www/vhosts/sample-website.com/public_html
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/sample-website.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/sample-website.com/privkey.pem
# 클라이언트 인증서 설정
SSLCACertificateFile /etc/httpd/client-certs/ca.pem
SSLVerifyClient require
SSLVerifyDepth 2
<Directory "/var/www/vhosts/sample-website.com/public_html">
AllowOverride All
Require all granted
</Directory>
ErrorLog /var/log/httpd/sample-website.com_ssl_error.log
CustomLog /var/log/httpd/sample-website.com_ssl_access.log combined
</VirtualHost>
Apache 설정 확인
자, 이제 Apache 설정ㅇ르 검토하고 Apache를 재시작 합니다.
sudo apachectl configtest
sudo systemctl restart httpd
sudo systemctl status httpd --no-pager
Syntax OK가 나와야 하고
active (running) 상태인지 확인합니다.
클라이언트 인증서 설치
client.p12 파일 복사
FTP 클라이언트 등을 이용하여 생성한 파일 중 client.p12 파일을 컴퓨터로 전송합니다.
파일 전송을 위해서는 파일 권한이나 소유자를 변경해야 할 수 있습니다.
sudo chmod 644 /etc/httpd/client-certs/client.p12
그리고 다운로드 받은 p12 파일의 파일명을 기억하기 쉬운 파일명으로 수정하세요.
나중에 시간이 지나서 이 파일을 보면 “이게 무슨 파일이었지??“라고 기억 안 날 수 있습니다.
이제 컴퓨터가 바뀌거나 웹브라우저를 변경할 때 이 파일만 등록하면 됩니다.
(예시) macOS에 설치
- 다운로드 한
client.p12파일을 더블클릭 - “키체인 접근” 앱이 자동으로 열림 (필요시 macOS 패스워드 입력)
- 앞서 설정하였던 웹브라우저용 비밀번호 입력
- “로그인” 키체인에 추가 완료
- “키체인 접근” 앱 실행
- 왼쪽에서 “로그인” 선택
- “나의 인증서” 카테고리 클릭
- “Default Company Ltd” 인증서를 더블클릭
- “Trust” (신뢰) 섹션 펼치기
- “When using this certificate"를 “Always Trust"로 변경
- 설정 완료
(예시) 아이폰에 설치
client.p12파일을 iCloud, AirDrop 방법 등으로 아이폰으로 옮깁니다.- iPhone “파일” 앱에서
client.p12파일 실행 - “프로파일 다운로드됨” 알림 확인
- 설정 앱으로 이동
- “프로파일” → “설치”
- 비밀번호 입력
- 설정 완료
테스트 및 검증
이제 다 됐습니다!
웹브라우저를 열어서 웹사이트에 접속해 봅시다.
인증서 확인이 자동으로 뜰 것입니다.
인증서 있는 기기에서 접속 시
macOS Safari 또는 Chrome에서 웹사이트에 접속
https://sample-website.com
- 인증서 선택 팝업이 나타납니다.
- “Default Company Ltd” 선택합니다.
- “Allow” 또는 “Continue” 클릭합니다.
- 웹사이트가 정상적으로 열립니다.
인증서 없는 기기에서 접속 시
정말 웹사이트 접속을 차단하는지 확인하기 위해 다른 컴퓨터로 접속해 봅시다.
https://sample-website.com
- “This website requires a certificate” 메시지가 나타납니다.
- 선택 가능한 인증서 없음
- 접속이 차단되어 화면에 아무것도 안 뜹ㄴ디ㅏ.
CURL 명령어로 명확하게 확인
웹사이트와 핸드쉐이크 과정이 어떻게 진행되는지 확인하기 위해
인증서 없는 컴퓨터에서 CMD 창을 열고 다음 명령어를 입력합니다.
curl -v https://sample-website.com
그러면 내용 중 아래와 같은 메시지가 나타나면서
웹사이트 핸드쉐이크 과정 중에 접속이 차단되어 연결이 완전히 불가능함을 알 수 있습니다.
SSL handshake failed
SEC_E_ILLEGAL_MESSAGE
최종 결과
구현된 보안 구조
1차 방어: 클라이언트 인증서 (SSL/TLS 레벨)
- 인증서 없으면 연결 자체가 차단
- 웹페이지, 로그인 화면조차 볼 수 없음
- 10년 유효 (나만의 웹사이트이니 편의상)
2차 방어: ID/PW 인증 (애플리케이션 레벨)
- 인증서가 있어도 로그인 필요
- 이중 인증 완성
HTTP 활용과 보안에 관하여
저는 80포트는 완전히 서비스 하지 않지만
특별히 Let’s Encrypt 인증서를 자동갱신하기 위해 아래와 같이 설정합니다.
<VirtualHost *:80>
ServerName sample-website.com
# Let's Encrypt 인증서 갱신을 위한 경로는 허용
Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
<Directory "/var/www/html/.well-known/acme-challenge/">
Require all granted
</Directory>
# 나머지는 HTTPS로 리다이렉트
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
이렇게 설정하면 80 포트로 Let’s Encrypt도 잘 동작하고
나머지 경로에 대해서는 모두 강제로 https 리다이렉트 하기 때문에
웹브라우저 인증서가 없다면 연결이 차단됩니다.
마무리
이렇게 웹사이트를 설정하면 클라이언트 인증서만 유출되지 않게 잘 보관하면서
컴퓨터를 바꿀 때 마다 내 웹브라우저에 등록하면 됩니다.
혹시나 클라이언트 인증서를 잃어버린 경우
그냥 위 과정을 다시 반복해서 새로 만들면 됩니다.
이렇게 공격자가 나의 민감한 데이터에 접근하지 못하도록
웹사이트 접근 단계에서부터 완벽하게 차단할 수 있습니니다.
참 쉽죠? 끝.