SSLv3, TLSv1

|

http://soul0.tistory.com/214

 

Network & WebSphere] SSL_TLSv1 차이점 및 정의,뜻,특성 그리고 적용을 알아보자.

 

안녕하세요.

2014년 접어들면서,

아니 그 이전부터 그랬었겠지만 이제 SSL은 쓰지 않는것을 권고하고 있습니다.

아래와 같이 보안 취약점이 발견된 건데요.

 

SSL 3.0 웹 암호화 기술에서 보안 취약점이 발견됐다. 데이터 보안을 위해 전송 데이터를 암호화하는 이 기술이 오히려 암호화가 풀려 해커에게 노출되는 취약점이다. 하트블리드나 배쉬버그 등과 비교해서는 위험한 수준이 아니지만, 주의가 필요하다.
15일 주요 외신들에 따르면, 구글 소속 연구원들이 SSL3.0 웹 암호화 기술의 보안 취약점을 찾아 공개했다. 푸들(Poodle, Padding Oracle On Downloaded Legacy Encryption)이라고 명명된 이 취약점은 다운그래이드 댄스(Downgrade Dance)공격을 통해 SSL 3.0을 사용하도록 강제하고 중간 공격자가 보호된 HTTP 쿠키의 암호를 풀 수 있도록 하는 방식이다.
즉, 서버와 클라이언트간에 오가는 데이터가 암호화되야 정상적이지만, 데이터 전송 중간에서 암호화가 풀려 공격자에게 내용이 노출될 수 있는 버그다.
구글 연구자들은 SSL3.0 취약점 사고를 막기 위해선 SSL3.0 기술을 서버나 브라우저에서 비활성화하는 한편, 보다 강력한 암호화 방식인 TLS을 사용하도록 권고했다.

 

이에 관하여, TLSv1 웹 암호화 방식을 사용하게 되었습니다.

그럼 SSLv3 와 TLSv1 이 뭔가를 살펴보도록 하겠습니다.

TLS (Transport Layer Security)
 - 인터넷에서의 정보를 암호화해서 송수신하는 프로토콜이다.
 - 넷스케이프 개발한 SSL(Secure Sockets Layer) 기반 기술이다.
 - 국제 인터넷 표준화 기구에서 인증받은 프로토콜이다.
 - 표준에 명시된 명칭은 TLS (but, SSL 이라는 용어가 매우 많이 사용되고 있다.)
 - 최신 버전인 TLS 버전 1.0은 SSL 버전 3.0으로부터 발전한 업그레이드를 제공한다.
 - IETF에서 SSLv3를 기반으로 표준화
 - 아래의 프로토콜 및 암호 요구사항이 변경: 필수
 - Diffie-Hellman key agreement
 - Digital Signature Standard
 - 3DES encryption
 - HMAC 사용

SSLv3
1. Netscape사에서 개발, 표준 아님
2. 아래의 프로토콜 및 암호 요구사항: 옵션
- Diffie-Hellman key agreement
- Digital Signature Standard
- 3DES encryption

참고, SSLv2 vs SSLv3/TLS
1. SSLv2는 MD5 해쉬를 사용해서 MAC 생성
2. SSLv2는 핸드쉐이크 중 보호를 받지 못함. Man-in-the-middle attack 취약
3. SSLv2는 truncation attack에 취약(공격자가 TCP-FIN를 보내서, 연결을 종료시킴),
SSLv3는 명시적인 종료 신호를 보냄.

참고. WTLS vs TLS
1. WTLS는 Elliptic curve cryptography(ECC)를 기본으로 사용
2. WTLS는 UDP를 사용
3. WTLS는 무선 환경을 고려하여 작은 크기의 인증서 사용

*IBM Site
- WebSphere 의 통신 프로토콜 방법
암호화 프로토콜은 보안 연결을 제공하여 두 당사자가 사생활 보호와 데이터 무결성을 가지고 서로 통신할 수 있도록 해줍니다. TLS(Transport Layer Security) 프로토콜은 SSL(Secure Socket Layer) 프로토콜에서 발전한 것입니다. WebSphere® MQ는 SSL과 TLS를 모두 지원합니다.
두 프로토콜의 주요 목표는 기밀성(때로는 사생활 보호라고도 함), 데이터 무결성, ID 및 디지털 인증서를 사용한 인증을 제공하는 것입니다.
두 프로토콜이 유사하긴 하지만 SSL 3.0과 TLS의 다양한 버전이 상호 운용되지 않는다는 점은 상당한 차이점입니다.
* TLS & SSL 이 서로 상호 운영되지는 않습니다.


TLS 작동 방법
 1. 정의
 - 인터넷을 사용한 통신에서 보안까지 다루게 되다보면, 서버와 클라이언트 서로가 신뢰할 수 있는 자임을 확인할 수 있어야 한다.
 - 서로간의 통신 내용이 제 3자에 의해 도청되는 것을 방지해야 한다.
 - 서로 자신을 신뢰할 수 있음을 알리기 위해 전자서명이 포함된 인증서를 사용한다.

2. 통신 과정
 - 사용할 프로토콜의 버전에 동의
 - 암호화 알고리즘 선택
 - 디지털 인증서 교환 및 유효성 검증에 의한 상호 인증
 - 공유 비밀 키 생성을 위한 키 분배 문제점을 막아주는 비대칭 암호화 기술 사용.
 - 그런 다음 SSL 또는 TLS는 메시지의 대칭 암호화에 공유 키를 사용하며, 이는 비대칭 암호화보다 더 빠릅니다.

3. 방법


1. SSL,TLS Client가 SSL,TLS 버전과 Client가 지원하는 CupherSuite 등의 암호화 정보를 나열하는 'client hello' 메시지를 송신합니다.
2. SSL,TLS Server는 Client가 제공하는 목록에서 서버가 선택한 CipherSuite, Session ID 및 다른 무작위 바이트 문자열을 포함하는 "server hello" 메시지로 응답합니다. 
    서버는 자신의 디지털 인증서를 송신합니다. + 클라이언트 인증서 요청 송신
3. SSL,TLS Client는 Server의 디지털 인증서를 확인합니다.
* SSL 및 TLS가 ID, 인증, 기밀성 및 무결성을 제공하는 방법
 - Server 인증에는 Client가 비밀 키를 처리하는데 사용되는 데이터를 암호화하기 위해 서버의 공개키를 사용
 - Server 가 정확한 개인키로 데이터 비밀번호를 해독하는 경우에만 비밀키를 생성
 - Client 인증에는 Server가 데이터 교환의 5단계 동안에 Client가 송신하는 데이터의 비밀번호를 해독하기 위해 클라이언트 인증서에 있는 공개키를 사용
 - 비밀 키로 암호화된 자료 해독
 * 인증 단계 중 어느 것이든지 실패하면, 데이터 교환이 실패하고 세션이 종료됩니다.
 - SSL , TLS 데이터 교환 중의 디지털 인증서 교환은 인증 프로세스 부분
 - 인증서가 위장에 대해보호를 제공하는 방법에 대한 자세한 정보는 아래 참고하시기 바랍니다.
(CA x = SSL,TLS Client에 인증서 발행) (CA y = SSL,TLS 서버에게 인증서 발행)

* Server 인증 필요한 것
 - CA y 가 Server에게 발행한 개인 인증서
 - 서버의 개인키

* Client 인증 필요한 것
 - CA y 의 CA 인증서

* 인증서 확인
 - 디지털 서명을 점검합니다
 - 중간 CA 인증서를 가지고 있어야 하는지 확인하기 위해 인증서 체인을 점검합니다
(인증서 체인이 작동하는 방법)
* 인증서 체인 = 인증 경로
- 엔티티를 인증하는데 사용되는 인증서 목록
- 그 엔티티의 인증서로 시작하고, 체인에 있는 각 인증서는 체인에 있는 다음 인증서에서 식별하는 엔티티에 의해 서명됩니다
- 체인은 루트 CA 인증서로 종료
- 루트 CA 인증서는 항상 CA 자체(인증기관) 에 의해 서명
- 체인에 있는 모든 인증서의 서명은 루트 CA에 도달해서 끝.

*인증서 소유자로부터 트러스트의 체인이 시작되는 루트 CA까지의 인증 경로

 - 만기 및 활성화 날짜와 검증 기간을 점검합니다.
 - 인증서의 폐기 상태를 점검합니다

* 비밀키
 - SSL 또는 TLS 데이터 교환 중에 SSL 또는 TLS 클라이언트와 서버 간의 데이터를 암호화하기 위해 비밀 키가 생성됩니다. 비밀 키는 일반 텍스트를 읽을 수 없는 암호문으로 변환하고 암호문을 일반 텍스트로 변환할 수 있도록 데이터에 적용되는 수학 공식에서 사용됩니다.
 - 비밀 키는 데이터 교환의 일부분으로 송신되는 임의 텍스트에서 생성되며 일반 텍스트를 암호문으로 암호화하는 데 사용됩니다. 또한 비밀 키는 메시지의 대체 여부를 판별하는 데 사용되는 MAC(Message Authentication Code) 알고리즘에 사용됩니다.

* 기밀성을 제공하는 방법
 - SSL,TLS는 메시지 비공개를 보장하기 위해 대칭과 비대칭 암호화의 결합을 사용합니다.
 - SSL,TLS 데이터 교환 중에 SSL,TLS 클라이언트와 서버는 하나의 세션에만 사용될 암호화 알고리즘공유 비밀 키에 동의합니다.      
 - SSL,TLS 클라이언트와 서버 사이에 전송되는 모든 메시지는 해당 알고리즘과 키를 사용하여 암호화됩니다.
 - 누군가가 메시지를 가로채더라도 반드시 개인용으로 남아있게 됩니다.
 - SSL은 광범위한 암호화 알고리즘을 지원합니다.
 - SSL 및 TLS가 공유 비밀 키를 전송할 때는 비대칭 암호화를 사용하기 때문에, 키 분배 문제점이 없습니다.

* 무결성을 제공하는 방법
 - SSL,TLS는 메시지 축약을 계산하여 데이터 무결성을 제공합니다.
 - SSL,TLS를 사용하는 경우, 채널 정의 내의 CipherSpec이 CipherSpec 지정의 테이블에서 설명한 대로 해시 알고리즘을 사용하는 한 데이터 무결성이 보장됩니다.

4. SSL,TLS 클라이언트가 후속 메시지 데이터를 암호화하기 위해 사용될 비밀 키를 클라이언트와 서버 모두가 처리하게 해주는 무작위 바이트 문자열을 송신합니다. 
 - 무작위 바이트 문자열 자체는 서버의 공개 키로 암호화됩니다.
5. SSL,TLS 서버가 "클라이언트 인증서 요청"을 송신했으면, 클라이언트가 클라이언트의 디지털 인증서나 "디지털 인증서 없음 경보"와 함께 클라이언트의 개인 키로 암호화된 무작위 바이트 문자열을 송신합니다. 
 - 이 경보는 경고일뿐이지만, 일부 구현에서 클라이언트 인증이 필수인 경우에 데이터 교환은 실패합니다.
6. SSL,TLS 서버는 클라이언트의 인증서를 확인합니다. 
7. SSL,TLS 클라이언트가 서버에게 "완료" 메시지를 송신하며, 이는 데이터 교환의 클라이언트 부분이 완료되었다는 것을 표시하는 비밀 키로 암호화되어 있습니다.
8. SSL,TLS 서버가 클라이언트에게 "완료" 메시지를 송신하며, 이는 데이터 교환의 서버 부분이 완료되었다는 것을 표시하는 비밀 키로 암호화되어 있습니다.
9. SSL,TLS 세션 지속 기간에 서버와 클라이언트가 이제 공유 비밀 키로 대칭적으로 암호화되어 있는 메시지를 교환할 수 있습니다.
 

------------------------------------

https://eastdg.wordpress.com/2014/04/09/ssltls-%EA%B8%B0%EB%B3%B8/

 

Leave a comment

글을 쓴지 거의 1년이나 지나버렸다. 평소 생활이 바쁜 것도 있지만, 게으른 것도 있으리라. 내 생각이 담긴 글은 아니고.. 보안에 관심은 있는데 관련 업종이 아니니 자주 접하질 못하고, 또 자꾸 잊어먹기도 하여 틈틈이 개념들을 정리해 놓곤 하는데, 그 중 하나인 SSL/TLS과 관련된 글이다. Stackexchange에서 “How does SSL work?” 질의에 대한 답변(특히 Thomas Pornin의 답변)을 보고 정리한 것이다. 오역도 있고 그럴테지만 기본 적인 개념을 쌓는데는 충분하다고 생각되고, 글도 올린지 너무 오래되어 이 글을 올려본다. 그리고 최근(14년 4월 7일) OpenSSL 1.0.1 버전 부터 1.0.1f 버전에 매우 심각한 버그가 있음이 발견되었다. 해당 버전의 OpenSSL을 사용하고 있으면 heartbeat를 이용하여 메모리에 상주하고 있는, 비밀키를 포함한 모든 정보를 가져갈 수 있다. 자세한 내용은 Heartbleed Bug를 참고하고, 현재 사용하고 있다면 빨리 패치해야 한다.


SSL/TLS

최초의 SSL은 Netscape사에서 개발되었다. SSL의 목적은 안전하지 않은 전문들을 암호화 하여 안전하게 전달하기 위해서이다. SSL 버전 1은 실제로 발표되진 않았었고, SSL 버전 2가 이후 공개적으로 발표가 되었는데 많은 보안 취약점이 있었다. 그래서 그것을 보안한 것이 SSL 버전 3이며 공식적으로 표준화 한 이름이 TLS 이다. 이를 같이 묶어서 SSL/TLS 라고 부른다. 좀 더 자세히 말해 보자면 아래와 같이 버전이 대입된다.

  • SSL v3: SSL 버전 3.0
  • SSL/TLS 1.0: SSL 버전 3.1
  • SSL/TLS 1.1: SSL 버전 3.2
  • SSL/TLS 1.2: SSL 버전 3.3

TLS는 현재 TLS 1.0, TLS 1.1 그리고 TLS 1.2 버전으로 나뉘어져 있으며, 보안상 TLS 1.2가 가장 강력하다. 하지만 아직까지도(2013년) TLS 1.2를 지원하지 않는 브라우저나 애플리케이션이 존재하기 때문에 TLS 1.2만 쓰지는 않고 TLS 1.1 등을 같이 지원하면서 사용한다. SSL/TLS의 가장 큰 목적은 상호간에 데이터를 매우 안전하게 전달하는 것에 있다. TCP는 패킷 이라는 단위를 통하여 데이터를 전송한다. 이 패킷은 악의적인 공격자에 의하여 쉽게 탈취가 가능하며, 공격자는 탈취한 패킷을 임의의 데이터로 조작하여 재 전송을 할 수 있다. 전송해야 할 데이터가 모두 노출이 되어 있기 때문에 가능한 일이다. 이를 방지하도록 도움을 주는 것이 SSL/TLS 이다. SSL/TLS는 TCP/IP 위에서 동작한다. 그렇기 때문에 몇몇 사람들에 의하여 네트워크의 OSI 레이어 중 TCP/IP 레이어 인지, Application 레이어인지 갑론을박이 벌어지기도 한다. 이 2개의 레이어에 속하도록 하는 것이 아니라 이 2개의 레이어 사이에 있다고 보는게 더 적당한 것 같다. 아무튼 이 SSL/TLS는 TCP/IP 위에서 동작하기 때문에 SSL/TLS의 목적인 보안성과 함께 TCP/IP의 안정성까지 가지고 있다.

Records (레코드)

SSL/TLS의 가장 하위 단은 record protocol이다. TCP가 데이터를 패킷으로 나뉘어 사용하듯이 SSL/TLS은 데이터를 record(이하 레코드) 단위로 나뉘어 사용한다. 레코드는 아래와 같은 형태로 되어 있다.

HH V1V2 L1L2 data

각 필드들은 아래와 같다.

  • HH: 1 바이트로 레코드 안에 있는 데이터 타입을 결정한다. 아래와 같은 4개의 타입이 정의되어 있다.
    • 20: change_cipher_spec
    • 21: alert
    • 22: handshake
    • 23: application_data
  • V1V2: 2바이트로 구성되며 현재 사용되는 SSL/TLS 버전을 뜻 한다. 아래와 같이 대입된다고 보면 된다.
    • 0300: SSL 버전 3.0
    • 0301: SSL 버전 3.1 (SSL/TLS 1.0)
    • 0302: SSL 버전 3.2 (SSL/TLS 1.1)
    • 0303: SSL 버전 3.3 (SSL/TLS 1.2)
  • L1L2: 전송되는 데이터의 길이를 뜻 한다. 빅 엔디언(big-endian) 표기법이기 때문에 실제 사람이 읽을 수 있는 길이는 256*L2+L1 으로 계산해야 한다. 그렇기 때문에 최대 전송 가능한 길이는 18,432 바이트 이지만 실제 이 길이에 도달할 정도로 레코드가 구성되지는 않는다.

이 이후에는 대칭키 암호로 암호화 된 데이터와 무결성 검사용 데이터들이 최대 18KB가 온다. 복호화 할 때 쓰이는 키와 사용되는 암호화 알고리즘, 그리고 무결성 체크 알고리즘은 이미 상호간에 기 교환된 알고리즘들로 체크하게 된다. 만약 압축 기법을 서로 사용하기로 했다면 상호간에 사용하기로 한 압축 기법으로 해제도 수행한다. 대략적인 과정은 아래와 같다.

  • 전송하고자 하는 데이터를 최대 16,384 바이트 잡는다. 18,432 바이트가 아닌 이유는 레코드로 구성시 별도로 추가되는 데이터 때문이다.
  • 압축 기법을 사용하기로 했다면 상호간에 사용하기로 한 압축기법으로 압축을 수행한다. 현재에는 사용하지 않거나 “Deflate”를 사용하거나 하는데 “Deflate”를 사용할 경우 CRIME attack에 의하여 취약점이 노출될 수 있어 실제는 압축 기법 사용을 권고하지 않는다. 아무튼 압축 기법 사용시 데이터 길이가 더 길어지기도 하는데 그럴 경우를 대비하여 SSL/TLS는 1KB 정도의 여유 공간을 더 잡아 두고 있다.
  • 보안성과 무결성을 유지하기 위해 마지막에는 MAC(여기서는 일반적으로 HMAC)을 붙인다. HMAC을 추가하기 위해 SSL/TLS은 1KB 정도를 HMAC을 위한 공간으로 예약해 두고 있다.

HMAC은 MD5, SHA-1 이나 SHA-256 등을 이용하여 구성하고, 암호화는 block cipher인 경우 CBC 모드를, stream cipher인 경우에는 RC4를 사용한다. HMAC는 전송될 데이터와 연결 순서와의 조합에서 생성하기 때문에 공격자는 레코드를 바꿔치지 못하게 된다.

Handshake

Handshake는 레코드 단위에서 동작되는 행동이며, SSL/TLS의 레코드에 적용할 알고리즘과 키를 교환하는 것에 목적이 있다. 이 handshake를 마치고 나면 오직 둘만이 소통할 수 있는 세션(session)이라는 통로가 생성된다. Handshake는 메시지들로 구성되어 있는데, 각각의 메시지들은 4개의 바이트 헤더를 가지고 있으며 메시지는 레코드 형태로 전송이 된다. 레코드 형식으로 전송되므로 레코드에서 사용하는 헤더도 역시 포함되어 전송이 된다. 헤더의 첫 번째 바이트는 메시지의 타입을 나타내며 3 바이트는 메시지의 길이를 나타낸다. (빅 엔디언 방식으로 표시된다.) 메시지들은 레코드 형식으로 다시 보내지므로 여기서 레코드에서 사용하는 타입은 22를 사용한다. SSL/TLS 를 시작하기 위한 최초의 교신은 암호화와 MAC 없이 시작한다. 최초의 메시지는 ClientHello 라고 불리우며 클라이언트(Client)가 SSL 통신을 시작하기 원한다는 것을 뜻한다. ClientHello가 포함하고 있는 내용은 아래와 같다.

  • 클라이언트가 지원하는 최대 SSL/TLS 버전
  • Client Random: 총 32바이트로 구성되며 이 중 28 바이트는 Cryptographically Strong Number Generator로 무작위로 생성된다.(아니면 가정된다)
  • Session ID: Abbreviated Handshake를 사용시 이용됨. SSL/TLS를 다시 사용하고자 할 경우 사용되는 값.
  • Cipher Suites: 클라이언트가 수용할 수 있는 암호화 기법 목록
  • Compression Algorithms: 클라이언트가 알고 있는 압축 기법 목록
  • Optional Extensions

Cipher suite는 16 비트로 사용할 암호화 기법을 정의한다. 예로 TLS_RSA_WITH_AES_128_CBC_SHA는 0x002F로 표현되며 나타내는 바는 HMAC/SHA-1과 128 비트 키로 AES 암호화를 사용하며, 키 교환은 RSA로 수행하겠다는 뜻이다. ClientHello의 응답으로 서버는 ServerHello를 보낸다. ServerHello는 다음과 같은 내용을 포함하고 있다.

  • 클라이언트와 서버가 사용할 SSL/TLS 버전
  • Server Random: 총 32바이트로 구성되며 28바이트는 Client Random과 동일함
  • Sesion ID: 현 연결에서 사용할 Session ID
  • Cipher Suite: 현 연결에서 사용할 Cipher Suite
  • Compression Algorithm: 현 연결에서 사용할 Compression Algorithm
  • Optional Extensions

전체적인 Handshake는 아래와 같은 형식으로 진행 된다.

Client                               Server

ClientHello        -->
                                ServerHello
                               Certificate*
                         ServerKeyExchange*
                        CertificateRequest*
                   <--      ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished           -->
                         [ChangeCipherSpec]
                   <--             Finished
Application Data   <->     Application Data

ClientHello와 ServerHello를 마치면 사용하는 cipher suite와 다른 인자 값들에 따라 몇몇의 메시지들을 서버는 추가로 보내게 된다.

  • Certificate: 공개키를 담고 있는 서버의 인증서를 보낸다. 클라이언트가 인증서를 보내지 말라고 요청 할 때만 보내지 않으며, 그 외는 모두 보낸다.
  • ServerKeyExchange: 키 교환시 인증서만으로 충분하지 않은 경우 사용되는 메시지. 예로 “DHE” 사용시 ephermeral Diffie-Hellman 키 교환을 사용하게 되는데 이 때 이 메시지를 이용한다.
  • CertificateRequest: 클라이언트의 인증서를 요청하는 메시지. 서버가 추가 인증을 필요한 경우 요청하는 메시지이며, 이 메시지에는 서버가 믿고 있는 상위 인증서들(Root Certificates) 목록을 포함하고 있다.
  • ServerHelloDone: Marker message로 ServerHello가 끝났다는 것을 알린다. 지금 부터는 클라이언트가 응답을 시작해야 함을 알린다.

위와 같은 메시지를 서버에게 받으면 클라이언트는 아래와 같이 응답을 해줘야 한다.

  • Certificate: 서버가 인증서를 요청하였다면 클라이언트 인증서를 이 메시지를 통하여 전송한다.
  • ClientKeyExchange: 키 교환시 사용할 메시지이다.
  • CertificateVerify: 이전의 handshake 메시지들을 가지고 계산된 디지털 서명으로서 서버가 클라이언트의 인증서를 요청하였을 경우 응답하게 되는 메시지이다. 이것을 통하여 클라이언트의 인증서가 진짜임을 알린다.

ChangeCipherSpec은 handshake 메시지가 아니다. 레코드 타입(타입 20번) 중 하나로서 발송되며 cipher suite를 서버와 다시 협의하게 된다. Finished 메시지는 이전의 서버와 클라이언트간 모든 handshake 메시지들을 가지고 암호학적인 체크섬을 계산한 것이다. 서버는 이 값을 받으면 재 계산을 통하여 자신이 계속 똑같은 클라이언트와 교신을 했는지 검증하게 된다. 클라이언트가 ChangeCipherSepc을 요청하였다면 서버는 그에 대한 응답을 해주고, Finished 응답을 해준다. 이것으로 상호간 SSL/TLS을 이용하여 교환하고자 하는 데이터를 전송하게 된다. Session ID를 기억하고 있다면 위와 같은 Full Handshake를 이용하지 않아도 된다. Abbreviated Handshake를 이용하면 되는데 아래와 같이 절차가 매우 간단하다.

Client                               Server

ClientHello        -->
                                ServerHello
                         [ChangeCipherSpec]
                   <--             Finished
[ChangeCipherSpec]
Finished           -->
Application Data   <->     Application Data

Abbreviated Handshake는 latency를 줄이기 위해 자주 사용된다. 일반적인 웹 브라우저는 SSL 연결을 Full Handshake를 통하여 열고 나머지는 모두 Abbreviated Handshake를 통하여 교신을 한다. 그리고 일반적인 웹 서버들은 약 15초간 아무일을 하지 않으면 연결을 끊지만 session ID를 기억하고 있기 때문에 언제든지 Abbreviated Handshake를 통하여 SSL 연결을 다시 열 수 있다.

Key Exchange (키 교환)

SSL/TLS이 사용할 수 있는 몇몇 키 알고리즘들이 있는데, 대부분의 키 알고리즘들은 서버의 공개키를 이용하여 동작한다. 다음은 많이 쓰이는 키 알고리즘 들이다.

  • RSA: 서버의 키…….유형이 RSA 형식인 경우 사용가능하다. 클라이언트는 46바이트의 랜덤 값과 2바이트 버전을 포함한 총 48바이트의 “pre-master secret” 값을 만들어 서버의 공개키로 암호화 하여 전송한다. 이러한 경우 ServerKeyExchange 과정은 없다.
  • DHE_RSA: 서버의 키 유형이 RSA 형식인 경우지만, 해당 키는 서명을 하는 경우에만 사용된다. 실제 키 교환은 Diffie-Hellman 알고리즘을 이용하여 교환하는데, 이 경우 서버는 DH 인자값들(modulus, generator)과 DH용 공개키를 포함한 ServerKeyExchange 메시지를 보낸다. (아직까진 이걸로 추천)
  • DHE_DSS: DHE_RSA 키 알고리즘과 유사하게 동작하지만 서버가 DSS 키를 가지고 있는 경우 사용된다. DSS는 DSA로도 알려져 있으며 서명에만 쓰인다.

다음은 보안상이나 기타 다른 이유로 잘 쓰이지 않는 키 알고리즘들이다.

  • DH: 서버의 키 유형이 Diffie-Hellman 유형인 경우 사용된다.
  • DH_anon: DHE와 비슷하지만 서버의 서명이 없다. 서버의 인증서 없이 동작되기 때문에 MITM 공격에 취약하다.
  • PSK: 키를 이미 기타 다른 방법으로 공유한 경우 사용되는 키 알고리즘이다.
  • SRP: application of the SRP protocol which is a Password Authenticated Key Exchange protocol. Client and certificate authenticate each other with regards to a shared secret, which can be a low-entropy password (whereas PSK requires a high-entropy shared secret). Very nifty. Not widely supported yet.
  • An ephermeral RSA key: DHE와 비슷하지만 RSA 키쌍을 생성한다. 그렇기 때문에 성능 부분에 대해 꽤 비싼 비용을 지불하며, 또 그렇게 매력적인 옵션은 아니다.
  • ECDH_ECDSA, ECDH_RSA, ECDHE_ECDSA, ECDHE_RSA, ECDH_anon: elliptic curves를 이용한 다양한 DH* 알고리즘들로서 가장 강력하며 추후 표준이 될 수도 있다. (ECDH_anon은 제외)

현 시점에서는 elliptic curves를 이용한 DH* 알고리즘을 지원하는 클라이언트가 그리 많지 않다. 그리고 대부분의 클라이언트가 RSA 또는 DHE_RSA를 지원하기 때문에 이 2개를 먼저 고려하게 될 것이다. 이 2개중 어느것이 더 괜찮냐고 물어본다면 DHE_RSA가 더 괜찮다. 이유인즉 RSA경우 만약에 공격자가 서버의 비밀키를 획득하게 된다면 이전의 모든 SSL/TLS 전문들을 다시 복호화 할 수 있기 때문이다. DHE_RSA인 경우에는 별도로 교환된 키로 암복호화 하기 때문에 이전의 SSL/TLS 전문들을 다시 복호화 하기는 힘들다.

인증서와 인증

디지털 인증서는 비 대칭키이므로 해당 키를 어떻게 분배할 것인가에 대하여 꽤 깊은 고민을 해봐야 한다. 이유인즉, 클라이언트는 서버의 공개키를 사용하여 비밀 통신을 하고 싶지만 공격자는 중간에 자신의 공개키를 서버의 공개키라고 속이고 비밀 통신을 유도할 수 있기 때문이다. 이를 방지하기 위해 표준 인증서인 X.509를 사용한다. X.509는 공인 인증기관(Certification Authority 또는 CA)에서 서명한 인증서로서 클라이언트가 서버의 인증서가 진짜임을 CA가 서명한 것으로 판단할 수 있게 도와준다. CA 서명 기법은 다른 CA들이 추가로 서명을 해줄 수 있는데, 이렇게 함으로써 인증서의 보안성을 높이기도 한다. 이러한 인증서들은 chain of certificates라고도 하는데, 맨 처음은 root CA의 인증서부터 시작해서 중간마다 intermediate CA들 인증서, 그리고 맨 마지막에는 서버의 인증서로 끝난다. 그리고 각각의 인증서들은 이전 인증서로 서명된 값들을 포함하고 있다. 즉, 아래와 같이 클라이언트는 서버 인증서를 검증할 수 있다고 볼 수 있다.

  • 서버의 인증서에서 certificate chain을 가져온다.
  • 클라이언트는 각 체인의 인증서들의 서명값과 X.590 bit 값들을 검증하고, 인증서 유효기간 또한 검증한다.
  • 서버 인증서에 있는 서버 이름을 검증한다. 이유인즉 다른 서버의 인증서를 그대로 가져와 사용할 수도 있기 때문이다.

Handshake Again

이론적으로는 이미 기 구축된 SSL/TLS 연결 내에서 새로운 handshake를 수행할 수 있으며, 실제적으로도 수행되며 일어나고 있다. 이를 수행하기 위해 서버는 SSL/TLS가 구축된 환경 내 아무때나 HelloRequest를 보내고 클라이언트는 ClientHello를 보내면 된다. 전형적은 흐름은 다음과 같다.

  • SSL/TLS 연결 가능한 서버로 클라이언트가 handshake를 수행한 후 연결되어 있다.
  • 클라이언트는 접근하고자 하는 URL를 접근하려고 하고, 서버는 해당 URL이 특정 인증서로 인증되어야만 접근 가능한 URL이다.
  • 서버는 새로운 handshake를 시도한다.

이 과정에서 약간의 취약점이 있는데 이를 간략하게 설명한다면, 일반적으로 SSL/TLS 보안성을 “forward” 측면에서만 활용한다. 새로운 handshake를 수행할 때, 이전 연결에서 유효한 클라이언트에 관한 모든 것들은 새로운 handshake 이후에도 계속 유효해야 하지만 그 반대는 아니다. (이말인즉, 이후 생성된 SSL/TLS 연결에서 교환된 정보는 이전 생성된 SSL/TLS 연결에서는 유효하지 않다는 얘기이다.) 어쨋든 위 상황에서 첫 번째 요청(request)은 두 번째 생성된 SSL/TLS 연결(인증서 기반 연결)에서 보호되지 않는다. 이 점을 공격자가 노린다.

Alerts

Alert 메시지는 경고나 에러 메시지를 보낼 때 사용한다. 이 메시지중 close_notify 메시지가 중요하다. 이 메시지는 서버나 클라이언트가 연결을 끊고자 할 때 보내는 메시지이다. 해당 메시지를 서버나 클라이언트가 받으면 해당 메시지에 대한 응답을 해줘야 하고 해당 연결을 끊도록 해야 한다. 하지만 해당 세션은 abbreviated handshake로 재 연결을 하기 위해 계속 유효하다. 이 메세지는 다른 레코드들 처럼 암호화 기법으로 보호되어 있어 공격자에 의해 접근하기 힘들다. 참고로 오래된 HTTP에서의 SSLv2는 close_notify 없이 SSL/TLS 연결을 끊을 수 있도록 되어 있어서 공격자들이 이를 이용했었다. 현재는 대부분의 HTTP 서버들이 Content-Length나 chunked encoding을 사용하므로 유효하지 않다.

 

-------------------------------------

https://lesstif.gitbooks.io/web-service-hardening/content/ssl-tls-https.html

 

Creating a KeyStore in JKS Format

https://docs.oracle.com/cd/E19509-01/820-3503/ggfen/

 

Java 2-way TLS/SSL (Client Certificates) and PKCS12 vs JKS KeyStores

http://blog.palominolabs.com/2011/10/18/java-2-way-tlsssl-client-certificates-and-pkcs12-vs-jks-keystores/index.html

 

 

-----------------------------------------

 

 

 

--------------------------------------------

 

 

 

저작자 표시 비영리 변경 금지
신고
Trackback 0 And Comment 0

ManualResetEvent for Java

|

https://roshanfonseka.wordpress.com/2016/03/06/a-taste-of-manualresetevent-for-java/

 

 

https://github.com/roshfsk/Java-ManualResetEvent/blob/master/src/com/devthread/manualreseteventdemo/ManualResetEvent.java

 

 

 

 

 

저작자 표시 비영리 변경 금지
신고

'개발/활용정보 > Java' 카테고리의 다른 글

ManualResetEvent for Java  (0) 2017.09.07
event handling  (0) 2017.07.10
정규식  (1) 2017.07.05
singleton pattern  (0) 2017.06.29
BundleActivator와 BundleContext  (0) 2014.12.16
guava  (0) 2013.08.08
Trackback 0 And Comment 0

event handling

|

http://docs.oracle.com/javase/6/docs/api/java/util/Observable.html

 

An Observable object has a list of observers which implement the Observer interface, and mechanisms for adding and removing observers. If o.notifyObservers(x) is called on the observable, update(o,x) will be called on each observer. This mechanism is somewhat old fashioned and rarely used in new code - it dates from Java 1.0 before EventObject was added in Java 1.1 and better event handling added for AWT and beans.

 

------------------------------------

 

https://scatteredcode.wordpress.com/2011/11/24/from-c-to-java-events/

Events in C#

The first conceptual hurdle I came across was dealing with Events. In C#, events are pretty easy to deal with, as an event is can be described as a collection of methods that all conform to a single delegate’s method signature. An example of this, based on a good tutorial on Code Project is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;
namespace wildert
{
    public class Metronome
    {
        public event TickHandler Tick;
        public EventArgs e = null;
        public delegate void TickHandler(Metronome m, EventArgs e);
        public void Start()
        {
            while (true)
            {
                System.Threading.Thread.Sleep(3000);
                if (Tick != null)
                {
                    Tick(this, e);
                }
            }
        }
    }
     
    class Test
    {
        static void Main()
        {
            Metronome m = new Metronome();
            m.Tick += HeardIt;
            m.Start();
        }
         
        private void HeardIt(Metronome m, EventArgs e)
        {
            System.Console.WriteLine("HEARD IT");
        }
    }
}

This is essentially adding the HeardIt method to the Metronome.Tick event, so whenever the event is fired, it calls theTest.HeardIt() method (along with any other method attached to the event). This is pretty straightforward in my (biased) opinion.

Events In Java

I started reading some pages on the net about how events in Java are handled. The first few articles I came across were kind of confusing and all over the place. I felt like I almost understood how it’s done but I was missing one piece of crucial information that binds it all together for me. After reading a few more articles, I finally had my “Ah ha!” moment, and it all clicked.

The confusion was due to that fact that unlike in C#, there is no event keyword in Java. In fact, and this is the piece I was missing, there essentially is no such thing as an event in Java. In Java you are essentially faking events and event handling by using a standard set of naming conventions and fully utilizing object-oriented programming.

Using events in java is really just a matter of defining an interface that contains a method to handle your event (this interface is known as the listener interface). You then implement this interface in the class that you want to handle the event (this is the listener class). In the class that you wish to “fire off” the event from you maintain a collection of class instances that implements the listener interface, and provide a method so listener classes can pass an instance of themselves in to add and remove them from the collection. Finally, the act of firing off events is merely going through the collection of listener classes, and on each listener call the listener interface’s method. It’s essentially a pure-OOP solution masquerading as an event handling system.

To see this in action, let’s create the equivalent of the C# event example in Java.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.kalldrexx.app
 
// Listener interface
public interface MetronomeEvent {
    void Tick(Date tickDate);
}
 
// Listener implementation
public class MainApp implements MetronomeEvent {
 
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        EventFiringSource source = new EventFiringSource();
        source.addMetronomeEventListener(this); // Adds itself as a listener for the event
        source.Start();
    }
     
    public void Tick(Date tickDate)
    {
        // Output the tick date here
    }
}
 
// Event source
public class EventFiringSource {
 
    // Our collection of classes that are subscribed as listeners of our
    protected Vector _listeners;
     
    // Method for listener classes to register themselves
    public void addMetronomeEventListener(MetronomeEvent listener)
    {
        if (_listeners == null)
            _listeners = new Vector();
             
        _listeners.addElement(listener);
    }
     
    // "fires" the event
    protected void fireMetronomeEvent()
    {
        if (_listeners != null && _listeners.isEmpty())
        {
            Enumeration e = _listeners.elements();
            while (e.hasMoreElements())
            {
                MetronomeEvent e = (MetronomeEvent)e.nextElement();
                e.Tick(new Date());
            }
        }
    }
     
    public void Start()
    {
        fireMetronomeEvent();
    }
}

When the app starts (and enters the MainApp’s main() method), it creates the event source and tells it that the MainApp class should be registered as a listener for the Metronome event. When the event source class starts, it will “fire” off the event by just looking at all classes registered that implement the MetronomeEvent interface, and call the Tick() method for that implemented class.

No special magic, just pure object-oriented programming!

 

In Java 8, the code can be simplified using the lambda, streams, and pipeline features:

if (_listeners != null && _listeners.isEmpty())
{
Enumeration e = _listeners.elements();
while (e.hasMoreElements())
{
MetronomeEvent e = (MetronomeEvent)e.nextElement();
e.Tick(new Date());
}
}

can be changed to

if (_listeners != null)
{
_listeners.parallelStream().forEach(ell -> ell.Tick(new Date()));
}

 

-------------------------------------

 

 

 

---------------------------------------

 

 

 

-----------------------------------------

 

 

 

--------------------------------------

 

 

 

---------------------------------------------

 

 

 

-------------------------------------------

 

 

 

------------------------------------

 

 

 

--------------------------------

 

 

 

-------------------------------------

 

 

 

-------------------------------------

 

 

 

 

 

저작자 표시 비영리 변경 금지
신고

'개발/활용정보 > Java' 카테고리의 다른 글

ManualResetEvent for Java  (0) 2017.09.07
event handling  (0) 2017.07.10
정규식  (1) 2017.07.05
singleton pattern  (0) 2017.06.29
BundleActivator와 BundleContext  (0) 2014.12.16
guava  (0) 2013.08.08
Trackback 0 And Comment 0
prev | 1 | 2 | 3 | 4 | ··· | 83 | next