System.Data.SqlClient는 SSL 3.0/TLS 1.0만 지원하는 듯!
이 질문 덕분에,
windows 2008 r2에서 ms-sql 2008 서버사용시 tls문제점
; https://www.sysnet.pe.kr/3/0/1523
TLS 통신 관련해서 좀 더 깊게 살펴보게 되는군요. 이 글에서는 클라이언트 측의 암호화 프로토콜 지정에 관해서만 다뤄보겠습니다.
SQL 서버로의 DB 연결 문자열에 Encrypt 속성을 주면,
string db = "TrustServerCertificate=true;Encrypt=true;Password=testuser2008;Persist Security Info=True;User ID=testuser;Initial Catalog=TestDB;Data Source=192.168.0.23";
SqlConnection cn = new SqlConnection(db);
cn.Open();
cn.Close();
이제 SQL 서버와의 통신을 암호화하게 됩니다. 그런데 애석하게도, 연결 문자열에는 구체적인 암호화 프로토콜을 지정할 수 있는 방법이 없습니다. 대신 TDS 프로토콜이 의존하는 SCHANNEL에서는 가능합니다. (2008 R2 이상의) 윈도우 설치 시 기본 상태에서는 SCHANNEL에 SSL 2.0을 제외하고는 SSL 3.0/TLS 1.0/TLS 1.1/TLS 1.2가 활성화되어 있습니다. 또한 프로토콜 간의 우선 순위는 기본적으로 TLS 1.0, SSL 3.0 순입니다.
이 때문에 아무런 설정 없이 SqlConnection 보안 연결을 하게 되면 TLS 1.0 프로토콜로 먼저 시도하게 됩니다. 이를 알 수 있는 방법은 Network Monitor 같은 도구를 이용해 패킷을 캡쳐해야 합니다. 그런데, 만약 SQL 서버 측에서 TLS 1.0을 막아놨다면 어떻게 될까요? 이 때의 네트워크 패킷을 가로채 보면, SQL 클라이언트 측에서 TLS 1.0 버전으로 handshake를 시도하고,
Frame: Number = 56892, Captured Frame Length = 193, MediaType = ETHERNET
+ Ethernet: Etype = Internet IP (IPv4),DestinationAddress:[00-15-5D-00-05-04],SourceAddress:[00-26-66-86-98-F8]
+ Ipv4: Src = 192.168.0.95, Dest = 192.168.0.23, Next Protocol = TCP, Packet ID = 27873, Total IP Length = 179
+ Tcp: Flags=...AP..., SrcPort=14543, DstPort=1433, PayloadLen=139, Seq=2992396582 - 2992396721, Ack=3722507225, Win=260 (scale factor 0x8) = 66560
+ Tds: Prelogin, Version = 7.300000(No version information available, using the default version), SPID = 0, PacketID = 0, Flags=...AP..., SrcPort=14543, DstPort=1433, PayloadLen=139, Seq=2992396582 - 2992396721, Ack=3722507225, Win=66560
TLSSSLData: Transport Layer Security (TLS) Payload Data
- TLS: TLS Rec Layer-1 HandShake: Client Hello.
- TlsRecordLayer: TLS Rec Layer-1 HandShake:
ContentType: HandShake:
- Version: TLS 1.0
Major: 3 (0x3)
Minor: 1 (0x1)
Length: 126 (0x7E)
- SSLHandshake: SSL HandShake ClientHello(0x01)
HandShakeType: ClientHello(0x01)
Length: 122 (0x7A)
+ ClientHello: TLS 1.0
SQL 서버 측에는 TLS 1.0 프로토콜 대신 SSL 3.0 지원을 하도록 한 경우이므로 이에 대한 응답으로 다음과 같이 SSL 3.0 통신을 명시하게 됩니다.
Frame: Number = 56893, Captured Frame Length = 1535, MediaType = ETHERNET
+ Ethernet: Etype = Internet IP (IPv4),DestinationAddress:[00-26-66-86-98-F8],SourceAddress:[00-15-5D-00-05-04]
+ Ipv4: Src = 192.168.0.23, Dest = 192.168.0.95, Next Protocol = TCP, Packet ID = 1599, Total IP Length = 0
+ Tcp: Flags=...AP..., SrcPort=1433, DstPort=14543, PayloadLen=1481, Seq=3722507225 - 3722508706, Ack=2992396721, Win=514 (scale factor 0x8) = 131584
+ Tds: Prelogin, Version = 7.300000(No version information available, using the default version), SPID = 0, PacketID = 0, Flags=...AP..., SrcPort=1433, DstPort=14543, PayloadLen=1481, Seq=3722507225 - 3722508706, Ack=2992396721, Win=131584
TLSSSLData: Secure Sockets Layer (SSL) Payload Data
- SSL: SSLv3 Rec Layer-1 HandShake: Server Hello. Certificate. Server Hello Done.
- SslV3RecordLayer: SSLv3 Rec Layer-1 HandShake:
ContentType: HandShake:
+ Version: SSL 3.0
Length: 1468 (0x5BC)
- SSLHandshake: SSL HandShake Server Hello Done(0x0E)
HandShakeType: ServerHello(0x02)
Length: 77 (0x4D)
+ ServerHello: 0x1
HandShakeType: Certificate(0x0B)
Length: 1379 (0x563)
+ Cert: 0x1
HandShakeType: Server Hello Done(0x0E)
Length: 0 (0x0)
이후 SQL 서버와 클라이언트는 SSL 3.0 통신을 하게 됩니다.
보시는 바와 같이 SqlConnection 개체는 Open을 하면 그 하부 단에서 우선 TLS 1.0 프로토콜로 시작하게 됩니다. 그렇다면, 이 상태에서 클라이언트 측의 TLS 1.0 프로토콜을 막아버리면 어떻게 될까요? (참고로, 레지스트리 변경 후 EXE 프로세스만 재시작하면 반영됩니다.)
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client]
"DisabledByDefault"=dword:00000001
"Enabled"=dword:00000000
그럼, 클라이언트는 처음부터 SSL 3.0 프로토콜을 이용해 HandShake 절차를 밟게 됩니다.
Frame: Number = 413, Captured Frame Length = 120, MediaType = ETHERNET
+ Ethernet: Etype = Internet IP (IPv4),DestinationAddress:[00-15-5D-00-05-04],SourceAddress:[00-26-66-86-98-F8]
+ Ipv4: Src = 192.168.0.95, Dest = 192.168.0.23, Next Protocol = TCP, Packet ID = 4335, Total IP Length = 106
+ Tcp: Flags=...AP..., SrcPort=2841, DstPort=1433, PayloadLen=66, Seq=1547634953 - 1547635019, Ack=3464005589, Win=260 (scale factor 0x8) = 66560
- Tds: Prelogin, Version = 7.300000(No version information available, using the default version), SPID = 0, PacketID = 0, Flags=...AP..., SrcPort=2841, DstPort=1433, PayloadLen=66, Seq=1547634953 - 1547635019, Ack=3464005589, Win=66560
- PacketHeader: SPID = 0, Size = 66, PacketID = 0, Window = 0
PacketType: Prelogin, 18(0x12)
Status: End of message true, ignore event false, reset connection false
Length: 66 (0x42)
SPID: 0 (0x0)
PacketID: 0 (0x0)
Window: 0 (0x0)
PreLoginPacketData:
TLSSSLData: Secure Sockets Layer (SSL) Payload Data
- SSL: SSLv3 Rec Layer-1 HandShake: Client Hello.
- SslV3RecordLayer: SSLv3 Rec Layer-1 HandShake:
ContentType: HandShake:
+ Version: SSL 3.0
Length: 53 (0x35)
+ SSLHandshake: SSL HandShake ClientHello(0x01)
나아가서, 다음의 레지스트리 키를 등록해 SSL 3.0도 비활성화하면 어떻게 될까요?
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client]
"Enabled"=dword:00000000
"DisabledByDefault"=dword:00000001
이후부터는 TDS:Prelogin, TDS:Response 패킷 정도만 보이고 더 이상 암호화 통신이 불가능하게 되어 이런 패킷 순서를 보이게 됩니다.
0x0 736 오후 2:40:30 2015-01-03 11.9265788 System TESTCLN SQLSVRR2 TCP TCP:Flags=......S., SrcPort=2347, DstPort=1433, PayloadLen=0, Seq=3846412218, Ack=0, Win=8192 ( Negotiating scale factor 0x8 ) = 8192 {TCP:10, IPv4:1}
0x0 737 오후 2:40:30 2015-01-03 11.9266810 System SQLSVRR2 TESTCLN TCP TCP:Flags=...A..S., SrcPort=1433, DstPort=2347, PayloadLen=0, Seq=1189447900, Ack=3846412219, Win=8192 ( Negotiated scale factor 0x8 ) = 2097152 {TCP:10, IPv4:1}
0x0 738 오후 2:40:30 2015-01-03 11.9316325 System TESTCLN SQLSVRR2 TCP TCP:Flags=...A...., SrcPort=2347, DstPort=1433, PayloadLen=0, Seq=3846412219, Ack=1189447901, Win=260 (scale factor 0x8) = 66560 {TCP:10, IPv4:1}
0x0 739 오후 2:40:30 2015-01-03 11.9324884 System TESTCLN SQLSVRR2 TDS TDS:Prelogin, Version = 7.300000(No version information available, using the default version), SPID = 0, PacketID = 1, Flags=...AP..., SrcPort=2347, DstPort=1433, PayloadLen=88, Seq=3846412219 - 3846412307, Ack=1189447901, Win=66560 {TDS:11, TCP:10, IPv4:1}
0x0 740 오후 2:40:30 2015-01-03 11.9326110 System SQLSVRR2 TESTCLN TDS TDS:Response, Version = 7.300000(No version information available, using the default version), SPID = 0, PacketID = 1, Flags=...AP..., SrcPort=1433, DstPort=2347, PayloadLen=43, Seq=1189447901 - 1189447944, Ack=3846412307, Win=131840 {TDS:11, TCP:10, IPv4:1}
0x0 741 오후 2:40:30 2015-01-03 11.9333909 System SQLSVRR2 TESTCLN TCP TCP:Flags=...A...F, SrcPort=1433, DstPort=2347, PayloadLen=0, Seq=1189447944, Ack=3846412307, Win=515 (scale factor 0x8) = 131840 {TCP:10, IPv4:1}
0x0 742 오후 2:40:30 2015-01-03 11.9385460 System TESTCLN SQLSVRR2 TCP TCP:Flags=...A...., SrcPort=2347, DstPort=1433, PayloadLen=0, Seq=3846412307, Ack=1189447945, Win=260 (scale factor 0x8) = 66560 {TCP:10, IPv4:1}
0x0 743 오후 2:40:30 2015-01-03 11.9393830 System TESTCLN SQLSVRR2 TCP TCP:Flags=...A...F, SrcPort=2347, DstPort=1433, PayloadLen=0, Seq=3846412307, Ack=1189447945, Win=260 (scale factor 0x8) = 66560 {TCP:10, IPv4:1}
0x0 744 오후 2:40:30 2015-01-03 11.9394074 System SQLSVRR2 TESTCLN TCP TCP:Flags=...A...., SrcPort=1433, DstPort=2347, PayloadLen=0, Seq=1189447945, Ack=3846412308, Win=515 (scale factor 0x8) = 131840 {TCP:10, IPv4:1}
그와 함께, SqlConnection.Open 호출 단계에서 다음과 같은 예외 메시지가 떨어집니다.
The instance of SQL Server you attempted to connect to requires encryption but this machine does not support it.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: The instance of SQL Server you attempted to connect to requires encryption but this machine does not support it.
즉, SQL 서버 측에서 다른 보안 프로토콜을 지원한다고 해도 클라이언트 측에서 이미 SSL 3.0, TLS 1.0만 지원하므로 더 이상 통신이 안되는 것입니다.
혹시, 클라이언트 측에서 SSL 3.0/TLS 1.0 이외의 프로토콜로 접속하는 방법을 아시는 분은 덧글 부탁드립니다. ^^
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]