본문 바로가기
CS

보안, 인증, 인가를 위한 최소한의 개념잡기 (feat. 해시, 디지털 서명, PKI)

by 데브겸 2023. 10. 5.

 

웹 어플리케이션을 개발하다보면 사용자 인증 기능을 구현해야 하는 경우가 많은데, 이때 사용되는 기술들을 온전히 이해하고 사용하기 위해 정리한다. 이 포스트는 널널한 개발자님 강의를 참조하여 작성하였다.

 

 

정보 보안의 3요소

  • 기밀성(Confidentiality)
    • 인가받은 사용자만이 정보에 접근할 수 있어야 함
  • 무결성(Integrity)
    • 정보가 변조, 위조되지 않아야 하고, 정보를 신뢰할 수 있어야 함
  • 가용성(Availability)
    • 신뢰 가능한 사용자는 언제든지 해당 정보에 접근할 수 있어야 함

 

 

Checksum(검사합)

체크섬은 데이터의 오류 여부, 조작 여부를 확인하는 방법으로 사용된다. 데이터를 일정 범위로 자른 후, 자른 부분들의 데이터를 합한 후 (일정 자릿수를 정하고) 범위를 넘는 자리 올림은 버려서 자릿수를 유지하는 방식으로 결과값을 만들어낸다. 네트워크 통신을 할 때 원본 데이터와 함께 이 체크섬 값을 넘겨주게되면, 사본 데이터를 받은 쪽에서는 사본 데이터의 체크섬을 구하여 둘을 비교한다. 둘이 같다면 데이터에 변경이 없었다는 것이고, 있다면 변경이 발생하였다는 것. 다만, 누군가 의도적으로 체크섬 값만 맞추면서 데이터를 조작하는 방식 등에 취약하하다는 단점이 존재한다. (-> 보안성이 높진 않음)

 

 

단방향 암호화 - Hash(해시)

체크섬의 케이스처럼 결과를 맞추면서 데이터를 조작하는 것을 수학적으로 매우 어렵게 만든 것이 Hash(해시).

 

해시 함수의 특징

  • 해시 알고리즘은은 단방향성 함수라고 생각하면 편함! 단방향성을 지닌다는 것은 함수의 결과를 보고 원본 데이터를 유추해내기 어렵다는 의미 (몫과 나머지가 있어야 나눗셈의 원본을 알아낼 수 있음. 하지만 나머지 연산은 몫 정보를 빼고 연산을 진행함으로써 원본을 알아내기 어렵게 함. 나머지만 보고 나누기 이전의 값을 유추할 수 없으니) 
    • 단방향이라는 것은 해시 결과를 원본으로 복호화는 불가능하다는 의미이다. 단, 전수조사를 통해 하나하나 해시 결과를 비교하여 원본이 무엇인지 알아내는 방식으로 유추하는 것은 가능
  • 어떤 데이터를 해시 함수에 넣으면 입력 값의 크기와 상관없이 결과의 길이(혹은 크기)가 일정한 암호문을 만들어낸다.
  • 원본 데이터 중 단 1비트만 달라져도 최종 결과가 완전히 달라진다는 특성 때문에, 해시 결과를 통해 데이터의 위변조가 되지 않았음(무결성)을 보장할 수 있음

 

대표적인 해시 알고리즘

기본: 암호화하는 알고리즘은 고려해야 하는 경우의 수가 많을 수록 좋음(예를 들어 비밀번호가 1~10사이에 있는 것과 1~100000사이에 있는 것 중 후자가 뚫기 위해서 더 많은 연산을 요하므로 더 보안성이 높음. 이를 나머지 연산 등에 적용하면 나누는 수의 범위가 크는 것 등에 적용 가능)

  • MD-5
    • 길이가 짧기 때문에(== 경우의 수가 적기 때문에) 노가다 해킹 공격(브루트 포스 공격)에 취약, 패스워드 단방향 암호화에 사용해서는 안 됨
  • SHA-1
  • SHA-128, 256, 384, 512
    • 숫자가 클수록 경우의 수 범위가 넓기 때문에 보안성이 높음

 

 

키 스트레칭(Key Stretching)과 솔트(Salt)

위에서 잠깐 언급했듯, 해시 결과를 복호화하는 것은 불가하지만 전수조사를 통해 해시 결과를 비교, 원본을 유추하는 것은 가능하다. 이는 동일한 원본에 대해 동일한 해시 결과를 반환하기 때문에 발생하는 한계점. 이로 인해 유명한 해싱 알고리즘의 결과값들의 경우 아예 테이블로 작성되어 레인보우 테이블(Rainbow Table)이라는 이름으로 공유되고 있다. (그렇기 때문에 비밀번호를 함부로 "qwer1234" 같은 걸로 저장하면 안 된다) 이를 극복하기 위해 나온 것이 키 스트레칭과 솔트.

 

키 스트레칭은 해싱된 값을 다시 해시 함수에 여러 번 넣는 것이다. 이는 반복횟수를 알아내야 한다는 제약 조건이 추가로 붙고, 연산 자원을 더 소모해야 한다는 점에서 한층 더 보안성이 강화된 방법이다.

 

솔트는 평문에 임의의 문자열을 덧붙이는 방법이다. 임의라는 것은 매번 다른 솔트값을 평문에 추가한다는 뜻이다. 비밀번호를 예시로 들면, 유저마다 고유의 솔트를 생성, 비밀번호에 추가하여 해시하고 해시 결과를 DB에 저장한다. 

이렇게 하면 동일한 비밀번호를 사용하였다고 하더라도 해시값이 다르기 때문에 한 명의 비밀번호가 유출되어도 동일한 비밀번호를 지닌 유저의 비밀번호는 안전하다. 만약 사용자 고유의 솔트를 알아냈다고 하더라도 해당 솔트와 결합한 문자열을 계속해서 대입해보아야 하기 때문에 쓰지 않았을 때보다 훨씬 더 많은 경우의 수를 생성하여 시간이 오래 걸리게 한다.

 

 


 

양방향 암호화 - Symmetric Key(대칭키), Asymmetric Key (비대칭키)

Symmetric Key(대칭키)

키 하나로 암호화와 복호화가 모두 가능한 방식이다. 비대칭키에 비해 연산양이 적기 때문에 효율적임(따라서 여건이 허락한다면 대칭키를 사용하는 것이 좋다)

 

대표적인 알고리즘으로 DES, 3DES, SEED-128, ARIA, AES-128, AES-256 등이 있음. (마찬가지로 키의 길이가 길수록 경우의 수가 많아지기 때문에 보안성이 높아짐)

 

다만, 암호화 복호화 모두 가능한 하나의 키를 양쪽(client, server)가 모두 같이 사용하기 때문에 보안적으로 취약한 면이 존재한다. 특히 인터넷이란 오픈되고 험난한 공간에서 안전하게 대칭키를 주고 받는 것은 매우 힘든 일.

 

 

 

Asymmetric Key(비대칭키)

인터넷 환경에서 대칭키를 안전하게 주고 받는다는 것은 거의 불가능. 이를 극복하기 위해 등장한 것이 비대칭 키. 비대칭 키는 한 쌍의 키가 서로 상호작용하는 구조이다. 하나의 키로만 암호화를, 다른 하나의 키로만 복호화를 할 수 있다. 보통 암호화하는 키는 외부에 공개되는 키이기 때문에 공개키(Public key), 복호화하는 키는 공개하지 않기 때문에 개인키 혹은 비밀키(Private key)라고 부른다. 

 

프라이빗하게 통신을 하고자 하는 서버와 클라이언트는 각각 public key와 private key를 생성하고 각자의 public key를 주고받는데(IKE - Internet Key Exchange), 이때 키를 주고받거나 비밀통신하는 TCP/IP 통신 세션을 tunnel이라고 한다.

 

아래 예시에서 숫자 5와 29는 각각 공개키, 개인키이며 둘은 한 쌍이다. 키를 엄청나게 큰 소수로 사용할 경우 개인키를 알아내는 것은 엄청난 컴퓨팅 자원을 소모해야 하기 때문에(슈퍼컴퓨터 정도는 들고 와야 함), 공개키와 암호화된 결과를 알고 있어도 개인키를 알아내는 것은 매우 어렵다. 

 

 

Public Key와 Private Key 모두 암호화, 복호화가 가능한데 각각의 의미가 살짝 다르다

- Public Key로 암호화하는 경우: 공개되지 않는 Private Key로만 복호화할 수 있기 때문에 데이터 보안에 중점이 있다

- Private Key로 암호화하는 경우: Public Key로 암호화할 수 있다는 것은 그와 대응되는 Private Key로 암호화되어 있다는 것, 즉 특정 사용자가 암호화했다는 것을 의미한다. 이는 데이터를 전송한 이의 인증과정에 보통 쓰인다

 

*디지털 서명(Digital Signature)

데이터의 무결성을 확보할 수 있는 방법 중 하나. 어떤 데이터에 대한 해시값을 생성하고, 그 해시값을 private key로 암호화하여 보내는 것. 

데이터 수신자는 수신한 데이터를 해시하고, 공개된 public key로 암호화된 해시값을 복호화하여 둘을 비교한다. 만약 해시값이 같다면 ① 수신한 데이터는 위변조되지 않았다는 것이고 ② 암호화는 오직 private key로만 가능하기 때문에 올바른 송신자라는 것을 알 수 있음(발신자 인증)

 

 

대칭 키와 비대칭 키 혼합해서 사용하기

비대칭 키가 보안성 측면에서 더 좋을 수 있으나, 생성 시에 더 많은 자원을 소모하기 때문에 할 수 있으면 대칭키를 사용하는 것이 좋음. 대칭 키와 비대칭 키를 혼합하면 둘의 장점만 사용할 수 있게 됨. 

 

PC는 대칭 키를(이때 생성한 대칭 키를 세션 키라고도 하며, 각 PC마다 고유한 세션 키를 생성하게 된다), 서버는 퍼블릭 키, 프라이빗 키 쌍을 생성한다. 이때 둘 간의 비밀 TCP/IP 통신 세션을 tunnel이라고 한다.

 

1. 서버가 서버의 퍼블릭 키를 PC에 전달한다

2. PC는 서버의 퍼블릭 키로 세션 키를 암호화한다.

3. 암호화된 세션 키를 서버에 전달한다.

4. 서버는 전달받은 암호화 된 세션 키를 자신의 프라이빗 키로 복호화한다. 이로써 PC와 서버 모두 대칭키 보유

5. 서버와 PC 모두 대칭 키 기반으로 데이터를 암호화/복호화 한다.

 

 

 

하지만 이런 방식을 취한다고 하더라도 중간에 해커가 끼어들어 자신의 퍼블릭, 프라이빗 키를 발급하여 PC에 전달해주는 MITM(Man In The Middle) 공격에 취약하다. PC는 서버인 줄 알고 자신의 세션 키를 해커의 퍼블릭 키로 암호화 하여 해커에게 전달, 해커는 자신의 프라이빗 키로 데이터를 복호화할 수 있다. 결국 PC의 입장에서 자신이 받은 퍼블릭 키가 정말 내가 통신하고자 하는 서버인지를 확신할 수 없다는 것이 가장 큰 문제가 된다. 또한 퍼블릭 키, 프라이빗 키 쌍을 생성하는데는 꽤 많은 컴퓨팅 자원이 필요한데, 이를 매 통신마다 생성한것은 매우 비효율적일 수 있다.

 

 

 

PKI(공개 키 보안구조) 인증체계

위 한계를 넘어서기 위해 중간에 믿을만한 기관을 두고, 그 기관을 통해 신뢰성을 보장받는 것이다. 그럼 어떤 기관에게 신뢰 보장을 맡길까?

  • PAA(Policy Approval Authorities): 공인인증서에 대한 정책을 결정하고 하위 기관의 정책을 승인하는 기관. 대한민국에서는 과학기술정보통신부가 이를 담당
  • PCA(Policy Certification Authorities, 정책인증기관): RootCA를 발급하고 기본 정책을 수립하는 기관. RootCA는 모든 인증서의 기초가 되는 인증서를 보유. 대한민국에서는 KISA(Korea Information Security Agency, 한국정보보호진흥원)이 해당.
  • CA(Certification Authority, 인증기관): PCA의 하위기관으로 인증서 발급과 취소 등의 실질적인 업무를 하는 기관. 금융결제원이나 NCA(한국 전산원)이 여기에 속하며, CA끼리는 상호 신뢰한다 (요즘엔 네이버 카카오 등의 민간 기업도 인증기관할 수 있는듯)
  • RA(Register Authority, 등록기관): 사용자의 신분을 확인하고 CA 간 인터페이스를 제공하는 기관

 

갑자기 많은 기관이 나와서 정신이 없을 수 있지만, 실질적으로 기억해야 할 것은 CA와 RA다. 쉽게 CA는 인증서를 만드는 기구(개발팀), RA는 인증서를 구매하고자 하는 실무자들과 소통하는 기구(비즈팀) 같은 느낌이다. 

 

퍼블릭 키 대신, 인증서(== SSL 인증서)라는 용어가 나온 것도 의문일 수 있다. SSL 인증서란, [① 퍼블릭 키와 ② 여러 정보들(인증서 소유자 이름, 유효 기간, 고유한 UID)와 ③ 인증서의 내용에 대한 디지털 서명(인증서 내용을 종합해 해시한 값을 프라이빗 키로 암호화한 값)]을 X.509 형식으로 만든 것이다. 여기에서 가장 주목해야 하는 특징이 ③인데, 이 디지털 서명을 퍼블릭 키로 풀어 해시 값을 비교함으로써 인증서의 위변조 여부와 이 인증서(특히 인증서 안에 있는 퍼블릭 키)가 내가 통신하고자 하는 서버에서 보낸 것인지를 확신할 수 있게 된다.

 

비밀통신을 위한 인증서, 프라이빗 키(프라이빗 키는 인증서 형식으로 저장하지 않는다)를 사용하고자 하는 회사는 RA를 통해 CA에서 만든 SSL 인증서, 프라이빗 키를 받는다. 이 둘을 자신의 서버에 설치하고 이용하는데, 한 번 설치할 때 6개월~1년 정도 이용할 수 있다.

 

서버는 비밀통신을 하고자 하는 PC에게 SSL 인증서를 보낸다. SSL 인증서에 있는 디지털 서명은 CA의 프라이빗 키로 암호화되어 있으며, CA의 퍼블릭 키는 마이크로소프트와 같은 제휴 업체에게 공유되고, 이 퍼블릭 키는 보안 업데이트를 할 때 사용자의 PC에 최종적으로 전달된다. 사용자는 자신이 받은 인증서를 CA의 퍼블릭 키로 복호화하여 인증서가 자신이 통신하고자 하는 서버인지, 인증서의 내용이 위변조되지는 않았는지 검증하게 된다. 만약 검증이 성공적이라면, 인증서를 보낸 그 서버에게 PC 자신이 만든 세션 키를 보낸다.

 

복잡하다...

 

인증서를 통한 인증(?)

위에서 PKI 인증체계를 통해 PC의 입장에서 어떤 서버가 내가 생각하는 그 서버인지, 믿을만한 서버인지 검증하는 과정을 알아보았다. 이 흐름을 살짝 비틀어서, 위 그림에서 PC와 서버의 위치를 뒤바꾸면 우리가 흔히 볼 수 있는 인증의 과정이 된다. 서버에서 지금 서비스 사용요청을 하는 저 사용자는 내가 아는 그 회원, 신뢰할 수 있는 회원인가를 보는 과정이기도 한 것!

 

 

서버가 사용자가 보낸 인증서(주로 그 안에 있는 퍼블릭 키)를 승인해줄 것인가는, CA의 퍼블릭 키로 인증서의 디지털 서명을 복호화하여 정말 내가 통신하고자 하는 그 사용자가 맞는지, 인증서 조작 여부를 판단한 후에 하면 되는 것이다. 이렇게 함으로써 검증과 더불어 인증까지 가능하게 된다.