JWT

JWT(Json Web Token)은 토큰 기반 인증 방식으로, 사용자의 세션 상태를 저장하는 게 아니라 필요한 정보를 토큰 body에 저장해 사용자가 가지고 있고 그것을 증명서처럼 사용합니다. 사용자는 Access Token(JWT Token)을 헤더에 실어 서버로 보내게 됩니다.

토큰을 만들기 위해서는 Header, Payload, Verify Signature가 필요합니다.

  • Header: Header, Payload, Verify Signature 정보를 암호화할 방식(alg), 타입(type) 등이 들어감
    • JWT인 토큰의 유형이나 HMAC SHA256 또는 RSA와 같이 사용되는 해시 알고리즘이 무엇으로 사용했는지 등 정보가 담김
  • Payload : 서버에서 보낼 데이터가 들어감. 일반적으로 사용자의 ID, 유효기간이 포함
    • 클라이언트에 대한 정보, META data같은 내용이 들어있고, Base64로 인코딩 되어있음
  • Verify Signature : Base64 방식으로 인코딩한 Header, payload 그리고 SECRET KEY를 더한 후 서명됨

위 내용을 가진 최종적인 형태는 Encoded Header.Encoded Payload.Verify Signature (xxxx.yyyy.zzzz) 입니다.

header와 payload는 base64로 인코딩만 되므로 누구나 디코딩하여 확인할 수 있습니다. 따라서 payload에는 중요한 정보가 포함되면 안됩니다. 하지만 verify signature는 SECRET KEY를 알지 못하면 복호화할 수 없습니다. 

아래는 위 내용을 기반으로 인증하는 예시입니다.

사용자 A가 B의 데이터를 보고자 payload를 조작하려 합니다. payload에 있는 A의 ID를 B의 ID로 변경해 인코딩한 후, 서버에 해당 토큰을 전달합니다. 그러면 서버는 처음 암호화된 verify signature를 검사하게 됩니다. 여기서 payload는 B사용자의 정보가 들어있으나, verify signature는 A의 payload를 기반으로 암호화되어 있기 때문에 유효하지 않는 토큰으로 간주합니다. 따라서 A의 사용자는 SECRET KEY를 알지 못하는 이상 토큰을 조작할 수 없습니다.

JWT의 인증 방식은 아래의 단계와 같습니다.

  1. 클라이언트가 로그인을 위해 해당 정보를 서버에 전달
  2. 서버에서는 전달된 데이터로 사용자를 확인하고 사용자의 고유한 ID값을 부여한 후, 기타 필요한 정보와 함께 Payload에 추가
  3. JWT 토큰의 유효기간을 설정
  4. 암호화할 SECRET KEY를 이용해  Access Token을 발급
  5. 사용자는 Access Token을 받아 저장한 후, 인증이 필요한 요청마다 토큰을 헤더에 추가하여 전달

  6. 서버에서는 해당 토큰의 Verify Signature를 SECRET KEY로 복호화한 후, 조작 여부, 유효기간을 확인

  7. 해당 토큰이 유효하면 Payload를 디코딩하여 사용자의 ID에 맞는 데이터를 호출

세션/쿠키 방식과 가장 큰 차이점은 세션/쿠키는 세션 저장소에 유저의 정보를 넣는 반면, JWT는 토큰 안에 유저의 정보를 넣는다는 점입니다. 사용자 입장에서는 헤더에 세션ID나 토큰을 실어서 보내준다는 점에서는 동일하나, 서버 측에서는 인증을 위해 암호화를 하냐, 별도의 저장소를 이용하냐는 차이가 발생합니다.

장점

1. JWT는 발급한 후 토큰 검증만 하면 되기 때문에 추가 저장소가 필요 없음

2. 서버를 확장하거나 유지,보수하는데 유리

3. 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능

  • 예를 들어 Facebook 로그인, Google 로그인 등은 모두 토큰을 기반으로 인증. 선택적으로 이름이나 이메일 등을 받을 수 있음

단점

1. 세션/쿠키의 경우 세션ID가 변질되었다고 판단되면 해당하는 세션을 지우면 되지만 JWT는 한 번 발급되면 유효기간이 완료될 때 까지는 계속 사용이 가능하므로 유효기간이 지나기 전까지  정보들을 탈취할 수 있음

  • 기존의 Access Token의 유효기간을 짧게 하고 Refresh Token이라는 새로운 토큰을 발급하면 Access Token을 탈취당해도 상대적으로 피해를 줄일 수 있음

2. payload 정보가 제한적 Payload는 따로 암호화되지 않기 때문에 디코딩하면 누구나 정보를 확인할 수 있어서 담는 데이터가 제한적임 

3. 세션/쿠키 방식에 비해 JWT의 길이가 기므로 인증이 필요한 요청이 많아질수록 서버의 자원낭비가 발생

4. 단점 1번과 연관된 문제로 유효기간을 짧게 하면 재로그인 시도가 잦아지고 길면 해커에게 탈취될 가능성이 큼

Refresh Token

Access Token(JWT)를 통한 인증 방식의 문제로 탈취당할 경우 보안에 취약하다는 점입니다. 유효기간이 짧은 Token의 경우, 사용자는 새 Token을 발급받기 위해 로그인을 자주 시도해야 하고 유효기간을 늘리면, 탈취당했을 때 보안에 취약해지게 됩니다. '유효기간을 짧게 하면서 보안을 챙길 수 있는' 물음에 나온 방식이 Refresh Token입니다.

Refresh Token은 Access Token과 똑같은 형태의 JWT입니다. 로그인이 완료됐을 때, Access Token과 동시에 Refresh Token은 긴 유효기간을 갖고 발행되고 Access Token의 유효기간이 만료되었을 때 새로 Token을 발급해주는 열쇠가 됩니다. 

예를 들어, Refresh Token의 유효기간은 2주, Access Token의 유효기간은 1시간으로 설정하게 되면 사용자에게 발급된 Token이 1시간이 지나게 되면 Access Token은 만료되지만 Refresh Token의 유효기간은 아직 남아 있기 때문에 사용자의 재로그인 없이 Access Token을 새롭게 발급받을 수 있습니다. 

위의 예제와 같이 Refresh Token의 유효기간이 만료되면 사용자는 새로 로그인해야 하고 Access Token과 동일하게 Refresh Token도 탈취될 가능성이 있기 때문에 적절한 유효기간 설정이 필요합니다.

 

아래는 Refresh Token이 포함된 JWT 인증 방식입니다. (1~3번은 JWT와 동일)

  1. 클라이언트가 로그인을 위해 해당 정보를 서버에 전달
  2. 서버에서는 전달된 데이터로 사용자를 확인하고 사용자의 고유한 ID값을 부여한 후, 기타 필요한 정보와 함께 Payload에 추가
  3. JWT 토큰의 유효기간을 설정
  4. 암호화할 SECRET KEY를 이용해  Access Token, Refresh Token을 발급 (일반적으로 회원 DB에 Refresh Token을 저장)
  5. 사용자는 Refresh Token을 안전한 저장소에 저장
  6. 사용자는 Access Token을 받아 저장(쿠키)한 후, 인증이 필요한 요청마다 토큰을 헤더에 추가하여 전달

  7. 시간이 지나 Access Token이 만료되었다고 가정

  8. 사용자는 6번과 같은 방식으로 Access Token을 헤더에 담아 서버에 요청

  9. 서버는 Access Token이 만료된 것을 확인하고 사용자에게 만료 메세지를 반환

    1. 사용자는 Access Token의 payload를 통해 유효기간을 알 수 있으므로 요청 이전에 바로 재발급 요청을 할 수 있음

  10. 사용자는 Refresh Token과 Access Token을 헤더에 담아 서버에 요청

  11. 서버는 요청받은 토큰의 Verify Signature를 SECRET KEY로 복호화한 후, 조작 여부, 유효기간을 확인하고 전달받은 Refresh Token과 저장해둔 Refresh Token을 비교. Token이 동일하고 유효기간이 지나지 않았다면 Access Token 발급

  12. 사용자는 새로 발급받은 Access Token을 저장하여 인증이 필요한 요청마다 토큰을 헤더에 추가하여 전달

장점

1. Access Token이 있을 때보다 안전

단점

1. 구현이 복잡

2. Access Token이 만료될 때마다 새롭게 발급하는 과정에서 생기는 HTTP 요청이 잦음

'보안 & 보안' 카테고리의 다른 글

서버 인증 (JWT)  (0) 2019.08.17
서버 인증 (세션/쿠키 기반)  (0) 2019.08.17
SSL Pinning  (0) 2018.12.18
TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28

인증은 왜 필요할까?

A와 B의 유저가 은행 사이트에서 각 본인의 잔액을 확인하기 위해 로그인을 하고 본인들의 잔액을 확인할 수 있습니다. 여기서 로그인은 A와 B를 구분하는 인증으로 볼 수 있습니다. 또한, A의 잔액을 B나 다른 사용자에게 노출시키면 안되므로 보안으로도 볼 수 있습니다. 현재 가장 많이 사용하는 통신 방식은 HTTP 방식입니다. HTTP의 특징으로 stateless가 있습니다. 이러한 특징으로 인해, 만약 은행 사이트에 인증과 관련된 내용이 없다면 로그인을 한 뒤에 메인 페이지로 이동했을 시, 정보가 사라져 어느 사용자인지 알 수 없습니다. 따라서 사용자마다 다른 정보를 노출하고 저장할 때, 인증은 필수적으로 가져가야 합니다. 아래에서는 다양한 인증 방식과 장단점을 설명합니다.

헤더에 사용자 정보를 추가하여 전달

사용하면 안되는 방식입니다. 로그인 이후에도 다른 페이지를 이동할 때마다 사용자의 정보를 헤더에 추가하여 서버에 전달하는 방식입니다. 개발 초기에 내부에서 테스트를 진행할 때나 사용할 수 있는 방식으로 이러한 방식으로 실제 서비스 운영이 된다면 사용자의 개인정보를 그대로 노출시켜 보안 문제를 발생시킵니다.

장점

1. 인증 방식을 고려할 필요가 없음

2. 편함

단점

1. 보안에 매우 취약

2. 요청이 올 때마다 서버는 전달받은 데이터로 해당 유저가 맞는지 검증해야 하므로 비효율적

세션/쿠키 기반 인증 방식

서버의 세션과 사용자 쿠키를 기반으로 하는 인증 방식입니다.

인증 방식은 아래의 단계와 같습니다.

  1. 클라이언트가 로그인을 위해 해당 정보를 서버에 전달
  2. 서버는 정보를 읽어 사용자를 확인하고 로그인 성공 시, 사용자를 식별할 수 있는 고유한 세션 ID를 생성하고 이를 메모리나 DB에 저장
    1. 저장하는 곳을 세션 저장소라고 하고 보통 Redis를 많이 사용함
  3. 서버는 요청의 결과값으로 세션 ID를 사용자에게 전달
  4. 세션 ID를 전달받은 사용자는 쿠키에 해당 값을 저장
  5. 이후 다른 페이지 이동이나 사용자 인증이 필요할 때, 헤더에 해당 쿠키를 실어서 전달
  6. 서버는 쿠키를 받아서 세션 저장소에 저장이 된 쿠키(세션ID)인지 확인
  7. 유효한 쿠키(세션ID)일 경우, 요청받은 데이터를 반환

Redis를 세션 저장소로 사용한다면 세션ID가 서버의 메모리에 저장이 됩니다. 만약 서버 확장 시, 모든 서버가 세션 저장소에 접근할 수 있도록 중앙 세션 저장소 관리가 필요합니다.

장점

1. 쿠키가 포함된 요청이 외부에 노출되어도 쿠키(세션ID)는 유의미한 값을 갖고 있지 않기 때문에 쿠키 자체로 큰 문제를 발생시키지 않음

2. 요청을 주는 각 사용자마다 고유의 세션ID가 발급되어 일일이 회원정보를 확인할 필요 없음

단점

1. 장점 1번에서 쿠키 자체는 유의미하지 않아 노출되도 큰 문제가 없다고 했으나, 사용자 A가 보낸 요청을 해커가 탈취(하이재킹)하여 해당 쿠키로 서버에 변질된 내용으로 HTTP요청을 보내면 서버는 해커의 요청을 A 사용자로 인식하게 됨

  • 이를 방지하기 위해 세션의 유효시간을 추가하거나 HTTPS를 사용해 탈취해도 안의 정보를 읽기 힘들게 만들 수 있음

2. 서버에서 세션 저장소를 사용하므로 추가적인 저장공간을 필요로 함

3. 중앙 세션 저장소 관리가 없으면 시스템 확장이 어려움

4. 중앙 세션 저장소에 장애가 발생하면 인증 전체가 문제가 될 수 있음

만약 세션을 사용하지 않고 쿠키만으로 인증을 한다면?

사용자가 로그인 시, 서버는 ID, PWD와 같은 값을 암호화 또는 인코딩으로 변환하여 사용자에게 전달하고 사용자는 이를 쿠키에 저장합니다. 그리고 인증이 필요할 때마다 이 쿠키를 헤더에 담아서 서버에 요청을 하고 서버는 해당 쿠키를 복호화 또는 디코딩으로 풀어 사용하게 됩니다. 여기서 문제는 쿠키가 유의미한 값을 갖게 되기 때문에 외부에 노출이 된다면 헤더에 사용자 정보를 전달하는 방식과 같은 문제를 띄게 됩니다.

'보안 & 보안' 카테고리의 다른 글

서버 인증 (JWT)  (0) 2019.08.17
서버 인증 (세션/쿠키 기반)  (0) 2019.08.17
SSL Pinning  (0) 2018.12.18
TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28

ssl pinning은 HPKP (HTTP Public Key Pinning)에서 주로 사용되는 용어입니다. 

이미 잘 알려져 있다시피 SSL/TLS 로 이루어진 암호화 통신은 중간자 공격 (Man in the Middle) 에 취약합니다. 특히 요즘에는 여러 보안장비들이 SSL Decryption 기능을 제공하며 이 중간자 공격 (Man in the Middle) 형태로 SSL 및 TLS 세션을 복호화 하여 내용을 검증하도록 되어 있습니다. 이 때 보안장비는 공격자와 마찬가지로 암/복호화에서 사용할 인증서를 임의로 교체하여 중간에서 데이터를 복호화 하여 검증 하도록 구성되어 있습니다.

위 예제와 같이 클라이언트 (유저) 는 최종적으로 중간의 보안장비 또는 공격자가 제공한 인증서를 기반으로 암호화 통신을 진행하게 되며 이를 통하여 Man in the Middle 에 노출되게 됩니다. 

HKPK란 위와 같이 침해된 인증서를 동반한 공격을 막기 위해 고안됐습니다. 브라우저가 HPKP를 사용하는 웹사이트에 접속하면 브라우저는 특정 웹 서버에 어떤 공개 키가 사용되는지를 일정 기간 동안 기억할 수 있게 됩니다. 그 기간 동안 브라우저는 다른 모든 공개 키를 무시합니다. 현재 크롬, 파이어폭스, 오페라만이 이 HKPK 기능을 지원하고 있었으나 크롬은 이 대열에서 빠지게 됐습니다.

HPKP(HTTP Public Key Pinning)


클라이언트가 SSL/TLS 암호화 통신에 사용할 인증서를 최종서버의 인증서로 고정(Pinning) 하는 방식을 HPKP라 합니다. 이렇게 클라이언트가 최종서버의 인증서를 고정하면 중간에서 보안장비 또는 공격자가 제공한 임의의 인증서를 맞지 않는 인증서라 판단하여 거부할 수 있습니다. 

이처럼 특정 서버의 호스트를 확실히 알고 싶거나 공격이 발생할 것이라 예상되는 환경에서 작업할 때 사용하게 됩니다.

크롬은 HPKP를 왜 제거할까?

간단하게 더 이상 도움이 되지 않기 때문입니다.

HKPK는 가짜 인증서 공격에는 강력한 대응책이 되나, 공격자들이 악성 핀을 설치하거나 사이트 운영자가 실수나 고의로 방문자들을 차단할 수 있다는 결함이 있습니다. 공격자가 특정 웹 서버를 침해하는 데 성공한다면, 해당 웹사이트 방문자들에게 악성 HPKP 헤더를 전송할 수도 있으며 사이트 운영자가 다시 한 번 해당 웹사이트에 대한 통제권을 가져온다고 해도 공격자의 HPKP 정책 때문에 브라우저들로 접근하는 게 여전히 불가능해질 수도 있습니다. 또한 운영자가 HKPK를 적용할 때 실수를 하나만 해도 사용자들이 엉뚱한 키를 다운로드 받아 사이트에 며칠에서 몇 달씩 접속하지 못하도록 하는 등 커다란 피해가 발생해 도입이 부담이 될 수 있습니다. 이렇게 보안적으로는 완벽하지만 실제 운영에서는 유연성이 떨어진다는 면도 존재합니다. 

다른 이유로 공개 키 피닝(PKP) 자체의 도입률이 매우 저조하다는 것입니다. 탑 백만 사이트들 중 약 0.04%만 적용이 되어 있습니다. 따라서 구글이 HKPK를 폐지하기로 한 건 이런 기술적인 어려움과 완전하지 못한 보안성 때문입니다.


크롬에서 가짜 인증서를 통한 공격은 HPKP 대신 Expect-CT 헤더를 도입하여 방어를 진행하고 있습니다. Expect-CT는 사이트 운영자들이 설정 오류를 저질러도 유연하게 복구할 수 있게 해줘서 HPKP보다 훨씬 안전하고 다양한 인증기관과의 호환성을 갖추고 있습니다.

'보안 & 보안' 카테고리의 다른 글

서버 인증 (JWT)  (0) 2019.08.17
서버 인증 (세션/쿠키 기반)  (0) 2019.08.17
SSL Pinning  (0) 2018.12.18
TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28

TLS란?

인터넷에서의 정보를 암호화해서 송수신하는 프로토콜

넷스케이프 커뮤니케이션스사가 개발한 SSL(Secure Sockets Layer)에 기반한 기술로, 국제 인터넷 표준화 기구에서 표준으로 인정받은 프로토콜입니다. 표준에 명시된 정식 명칭은 TLS지만 아직도 SSL이라는 용어가 많이 사용되고 있습니다.


흔히 SSL이라 부르는 것들의 대부분은 TLS입니다. SSL은 POODLE, DROWN 등의 취약점이 발견되어 현재 사용되지 않는다고 보면 됩니다. TLS를 사용해 암호화된 연결을 하는 HTTP를 HTTPS(Secure)라고 하며, 웹사이트 주소는 HTTPS로 시작합니다. 기본 포트 또한 80번이 아닌 443번을 씁니다.

TLS와 HTTPS를 혼동하는 경우가 많은데, 둘은 유사하긴 하지만 다른 개념입니다. TLS는 다양한 종류의 보안 통신을 하기 위한 프로토콜이며, HTTPS는 TLS 위에 HTTP 프로토콜을 얹어 보안된 HTTP 통신을 하는 프로토콜입니다. 다시 말해 TLS는 HTTP뿐만이 아니라 FTPSMTP와 같은 프로토콜까지 포함하며, HTTPS는 TLS와 HTTP가 조합된 프로토콜만을 가리킵니다.


'보안 & 보안' 카테고리의 다른 글

서버 인증 (세션/쿠키 기반)  (0) 2019.08.17
SSL Pinning  (0) 2018.12.18
TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28
알려진 평문 공격 (기지 평문 공격) - Known-plaintext attack  (0) 2017.03.27

스니핑은 네트워크 패킷을 가로채서 분석하는 해킹기법입니다. 아래는 파이썬을 사용한 간단한 스니핑 프로그램 예제입니다.

from socket import *
import os

def sniffing(host):
    # 아래 값들은 소켓을 생성할 때 프로토콜을 지정하는 세 번째 인자로 사용
    # 윈도우는 프로토콜에 관계없이 들어오는 모든 패킷을 가로채기 때문에 IP를 지정해도 무관하지만 유닉스나 리눅스는 ICMP를 가로채겠다는 것을 명시적으로 표시해야함
    if os.name == 'nt':
        socket_protocol = IPPROTO_IP
    else:
        socket_protocol = IPPROTO_ICMP
    # socket_protocol로 지정된 프로토콜을 이용하는 Raw 소켓을 만들고 호스트와 바인드
    sniffer = socket(AF_INET, SOCK_RAW, socket_protocol)
    sniffer.bind((host, 0))
    # 가로채는 패킷에 IP 헤더를 포함하라고 소켓의 옵션으로 지정
    sniffer.setsockopt(IPPROTO_IP, IP_HDRINCL, 1)

    # 윈도우인 경우 소켓을 promiscuous모드로 변경하여 호스트에 전달되는 모든 패킷을 수신.
    # 소켓이 promiscuous 모드가 아니면 코드가 구동되는 컴퓨터가 목적지가 아닌 패킷은 모두 버리게 됨
    # if os.name == 'nt':
    #     sniffer.ioctl(SIO_RCVALL, RCVALL_ON)
    # 소켓으로 패킷이 들어올 때까지 대기. 65565는 버퍼의 크기로 단위는 바이트
    packet = sniffer.recvfrom(65565)
    print(packet)

    # if os.name == 'nt':
    #     sniffer.ioctl(SIO_RCVALL, RCVALL_OFF)

print(gethostname())
host = gethostbyname(gethostname())
print('start sniffing {0}'.format(host))
sniffing('127.0.0.1') # 호스트 이름을 IPv4형식으로 변경한 ip를 했을 때 에러나서 임시 ip 지정

# 스니핑된 패킷 결과
# (b'E\x00$\x00\x1d\xc1\x00\x00@\x01\x00\x00\x7f\x00\x00\x01\x7f\x00\x00\x01\x03\x03\x07\xe2\x00\x00\x00\x00E\x00\xeb\x00)\xf2\x00\x00@\x11\x00\x00\x7f\x00\x00\x01\x7f\x00\x00\x01\xc7\xd9~x\x00\xd7\x00\x00', ('127.0.0.1', 0))

종류

스니핑에는 여러가지 종류가 있습니다.

  • IP Header 스니퍼
  • ICMP 스니퍼
    • IP 네트워크에서 진단이나 제어 용도로 사용되며, 오류에 대한 응답으로 생성.
  • 호스트 스캐너
    • ICMP 스니핑을 사용하면 해당 호스트가 살아있는지 아닌지 확인할 수 있음. 호스트 스캐너는 컴퓨터에 연결된 서브네트워크의 모든 호스트로 특정 메시지가 포함된 IP 데이터그램을 전송하고 이에 대한 응답 내용을 분석하여 호스트가 동작 중인지 알아내는 프로그램. 
  • PING을 사용한 호스트 스캐너

방어대책

  • 패킷 스니퍼가 설치될 수 없도록 네트워크 미디어에 대한 물리적 접근 제한
  • 중요 정보에 대해 암호화 사용
  • ARP 스푸핑 방지를 위해 정적 IP와 정적 ARP 테이블을 사용
  • ARP 캐시에 게이트웨이 영구 MAC 주소 설정
  • SSH나 SCP, SSL 등과 같은 암호화 세션 사용
  • 승인된 사용자로 네트워크 제한이 가능하다면 스니핑 도구가 패킷을 감지하지 못하도록 브로드캐스트 기능 오프


'보안 & 보안' 카테고리의 다른 글

SSL Pinning  (0) 2018.12.18
TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28
알려진 평문 공격 (기지 평문 공격) - Known-plaintext attack  (0) 2017.03.27
무차별 대입 공격 (Brute Force Attack)  (0) 2017.03.27

1. 유닉스(리눅스) 패스워드 크래킹

유닉스나 리눅스는 기본적으로 사용자의 패스워드를 MD5 해시값으로 변경하여 관리하고 있습니다. 예를 들어, abcd 아이디의 패스워드가 1234라고 하면 1234에 대한 MD5 해시값인 81 dc 9d db 52 d0 4d c2 00 36 db d8 31 3e d0 55를 사용합니다. 그런데 test 아이디를 가진 사람의 패스워드도 1234라고 하면 문제가 발생할 수도 있습니다. abcd 아이디를 가진 사람이 우연히 test의 비밀번호 MD5값이 동일하다는 것을 안다면 비밀번호가 1234라는 것을 알 수 있기 때문입니다. 그래서 이런 문제를 해결하기 위해 salt라 부르는 2개의 문자를 원래 패스워드에 추가한 후 MD5 해시를 구성하는 매커니즘을 사용하고 있습니다. 

다시 예를 들어 abcd 아이디의 패스워드가 1234면 salt값로 fa를 앞에 추가하여 fa1234의 MD5 해시값을 07 9b 71 85 33 d9 9a fe 18 9a fb e2 bc 4a a3 58과 같이 만듭니다. 이 값에 salt인 fa를 추가합니다 . 문자 fa는 16진수 ASCII 값으로 66 61이므로 abcd의 1234는 66 01 07 9b 71 85 33 d9 9a fe 18 9a fb e2 bc 4a a3 58로 관리하게 됩니다. 동일한 원리로 test의 패스워드 1234에 salt로 f3을 추가했다고 하면 abcd와 test의 MD5 해시값은 다른 값이 생성됩니다.


리눅스는 사용자 인증에 필요한 정보를  /etc/passwd에 저장하고 관리합니다. 

root : x : 0 : 0 : root : /root : /bin/bash
#로그인 이름:패스워드:사용자아이디:그룹아이디:코멘트:홈디렉토리:기본쉘

두 번째 필드가 패스워드이지만 모두 x로 표시되어 있으며, 실제 패스워드는 /etc/shadow 파일에 저장되어 있습니다. 

root:$1$agjnf2382F32o9h#T2:14923:0:99999:7:	:	:
abcd:$1$fnafnQO'I2R28y:14945:0:99999:7:	:	: 

첫 번쨰 필드는 사용자계정이고 두 번째 필드는 salt가 포함된 사용자 패스워드 해시값입니다.

두 번째 필드 분류

$1$: MD5

$5$: SHA256

$6$: SHA512 

위에서 예로 든 /etc/shadow 파일의 내용에 접근하여 root와 abcd의 패스워드 해시값을 얻었다면 오프라인 공격 유형으로 패스워드 크래킹을 수행할 수 있습니다. 인터넷에는 패스워드 크래킹을 위한 사전을 텍스트 파일로 유통하는 사이트가 많이 있습니다. 보통 용량이 크기 때문에 아래와 같이 사전파일을 예로 만들고 패스워드 크래킹의 원리를 설명합니다.

apple
python
password
12345
secret
welcome
admin
pineapple
other
login
pokemon
iloveyou


/etc/shadow에서 패스워드 크래킹을 위해 획득했다고 가정하고 passwords.txt로 저장합니다.

root:$1$a3gSE1RAj6522:14923:0:99999:7:::
test:$1$zfti6chVSQLlQ:14945:0:99999:7:::


 아래 코드를 작성한 후 실행하면 다음의 결과가 생성됩니다.

import crypt


def find_pass(pass_hash, dictfile):
    salt = pass_hash[3:5]
    with open(dictfile, 'r') as dfile:
        for word in dfile.readlines():
            word = word.strip('\n')
            cryptwd = crypt.crypt(word, salt)
            if cryptwd == pass_hash[3:]:
                return word


dictfile = 'dictionary.txt'
with open('passwords.txt', 'r') as pass_file:
    for line in pass_file.readlines():
        data = line.split(':')
        user = data[0].strip()
        passwd = data[1].strip()
        word = find_pass(passwd, dictfile)

        if word:
            print('id: {0} password: {1}'.format(user, word))

        else:
            print('not found')
 
# 결과
# id: root password: iloveyou
# id: test password: python

2. zip 파일 패스워드 크래킹

zip 파일은 사전공격이나 무차별 대입 공격으로 ZIP 파일을 풀 수 있습니다. 아래는 사전공격으로 zip 파일을 푸는 파이썬 예시입니다.

import zipfile
from threading import Thread


def crackzip(zfile, passwd):
    try:
        zfile.extractall(pwd=passwd)
        print('zip file pass {0}'.format(passwd.decode()))
        return True

    except:
        pass
    return False


dictfile = 'dictionary.txt'
zipfilename = 'locked.zip'
zfile = zipfile.ZipFile(zipfilename, 'r')
pfile = open(dictfile, 'r')

for line in pfile.readlines():
    passwd = line.strip('\n')
    t = Thread(target=crackzip, args=(zfile, passwd.encode('utf-8')))
    t.start()

해당 파일의 같은 경로에 zip파일과 비밀번호가 있는 dictionary.txt 파일이 존재하면 압축파일이 해제되는 것을 확인할 수 있습니다.

3. 시스템 패스워드 크래킹 

수동적 온라인 공격

공격자가 대상 시스템에 직접 연결하거나 통신하지 않고 패스워드 크래킹을 수행하는 방법입니다. 유선 스니핑, 중간자 공격 등이 있습니다.

능동적 온라인 공격

공격자가 대상 시스템에 직접 접속하여 패스워드를 추측하여 입력함으로써 공격하는 방법입니다. 패스워드를 일일이 입력하지 않고 자동화된 도구를 활용하여 공격합니다. 자동화 도구로는 트로이 목마, 스파이웨어, 키로거 등이 있습니다.

오프라인 공격

오프라인 패스워드 공격은 공격자가 시스템이 관리하는 패스워드 파일에 접근할 수 있을 경우 가능한 공격 방법입니다. 오프라인 공격에 보편적으로 활용되는 해킹 기법은 무차별 대입 공격, 사전공격, 음절 공격, 레인보우 테이블 공격 등과 같은 암호 공격입니다.

'보안 & 보안' 카테고리의 다른 글

TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28
알려진 평문 공격 (기지 평문 공격) - Known-plaintext attack  (0) 2017.03.27
무차별 대입 공격 (Brute Force Attack)  (0) 2017.03.27
SSL (Secure Socket Layer)  (0) 2017.03.27

+ Random Posts