수안이의 컴퓨터 연구실

  • Mainpage
  • About Me
  • Tags
  • Metapage
  • Notice
  • Location
  • Keywords
  • Guestbook
  • Admin
  • Write an Article
  • Total | 1621008
  • Today | 388
  • Yesterday | 482

3 Articles, Search for '보안'

  1. 2008/06/17 오라클 보안 세미나
  2. 2007/05/25 데이터 보안 [SQL 주입 공격 대처 방법]
  3. 2007/01/09 .NET Framework의 강력한 이름 및 보안
Database/Oracle2008/06/17 10:56

오라클 보안 세미나


사용자 삽입 이미지
s01.pdf
보안의 새로운 접근전략
Governance, Risk, and Compliance 전략과 방안


사용자 삽입 이미지
s02.pdf
내부자 정보 유출 방지를 위한 DB 보안 솔루션


사용자 삽입 이미지
s03.pdf
오라클 계정관리 솔루션을 통한 기업 내,외부의 안전한 비지니스 환경 구축 방안


사용자 삽입 이미지
s04.pdf
Oracle을 위한 HyperBac 보안백업 솔루션



"Oracle" 카테고리의 다른 글
  • 오라클 보안 세미나 (0)2008/06/17
  • Installing Oracle Database 11g on Linux (0)2008/05/21
  • Oracle Ports for Network Services (0)2008/05/19
  • Oracle Error Code (0)2008/05/19
2008/06/17 10:56 2008/06/17 10:56
Posted by webdizen
Tags HyperBac, Oracle, 계정관리, 내부자 정보, 보안, 보안 솔루션, 보안백업
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3254

Leave your greetings.

[로그인][오픈아이디란?]

Database/MSSQL2007/05/25 10:31

데이터 보안 [SQL 주입 공격 대처 방법]

Paul Litwin │Fred Hutchinson Cancer Research Center 수석 프로그래머


ASP.NET 및 Microsoft SQL Server과 같은 강력한 데이터베이스 서버의 고급 서버측 기술을 통해 개발자는 동적인 데이터 중심 웹 사이트를 매우 쉽게 만들 수 있습니다. 하지만 ASP.NET 및 SQL의 기능은 SQL 주입 공격이라는 너무나 일반적인 공격 방식을 알고 있는 해커들에게도 쉽게 악용될 수 있습니다.


SQL 주입 공격에 대한 기본 개념은 다음과 같습니다. 사용자가 텍스트 상자에 텍스트를 입력할 수 있도록 웹 페이지를 만들고 이러한 텍스트는 데이터베이스에 대한 쿼리를 수행하는 데 사용됩니다. 해커는 이러한 텍스트 상자에 쿼리의 특성을 변경하여 백엔드 데이터베이스에 침입하거나 데이터베이스를 손상시킬 수 있는 잘못 형성된 SQL 문을 입력합니다. 어떻게 이런 일이 가능할까요? 몇 가지 예를 통해 이러한 방법에 대해 설명하겠습니다.


SQL 문의 변환

여러 ASP.NET 응용 프로그램에서는 그림 1에 표시된 것과 같은 폼을 사용하여 사용자를 인증합니다. 사용자가 BadLogin.aspx의 Login 단추를 클릭하면 사용자가 폼의 텍스트 상자 컨트롤에 입력한 값과 UserName 및 Password가 일치하는 Users 테이블에 있는 레코드 수를 계산하는 쿼리를 실행하여 cmdLogin_Click 메서드가 사용자를 인증하도록 시도합니다.


대부분의 경우 폼은 정확히 의도된 대로 작동합니다. 사용자는 Users 테이블에 있는 레코드와 일치하는 사용자 이름 및 암호를 입력합니다. 동적으로 생성된 SQL 쿼리를 사용하여 일치하는 행의 개수를 검색합니다. 그런 다음 사용자를 인증하고 요청된 페이지로 리디렉션합니다. 잘못된 사용자 이름 및/또는 암호를 입력하는 사용자는 인증되지 않습니다. 하지만 이 경우에도 해커가 UserName 텍스트 상자에 겉보기에는 잘못된 것이 없는 다음과 같은 텍스트를 입력하여 유효한 사용자 이름 및 암호를 알지 못하더라도 시스템에 침입할 수 있습니다.



해커는 잘못 형성된 SQL을 쿼리에 주입하여 시스템에 침입합니다. 이 경우의 해킹은 다음과 같이 사용자가 입력한 고정 문자열 및 값의 연결을 통해 실행 쿼리가 형성되기 때문에 작동됩니다.



유효한 사용자 이름인 "Paul"과 암호 "password"를 사용자가 입력하는 경우 strQry는 다음과 같이 됩니다.



하지만 해커가 다음을 입력하면



쿼리가 다음과 같이 됩니다.



이중 하이픈은 SQL에서 주석의 시작 부분을 나타내므로 쿼리는 다음과 같이 됩니다.



식 1=1은 테이블의 모든 행에 대해 항상 True이고 다른 식이 포함된 True 식 or'd는 항상 True를 반환합니다. 따라서 User 테이블에 적어도 하나 이상의 행이 있다고 가정할 경우 이 SQL은 항상 0이 아닌 레코드 개수를 반환합니다.


일부 SQL 주입 공격에는 폼 인증이 포함되지 않습니다. 폼 인증과 관련한 SQL 주입 공격에 필요한 사항은 동적으로 구성된 일부 SQL과 트러스트되지 않은 사용자 입력이 있는 응용 프로그램입니다. 정확한 조건만 주어진다면 이러한 공격으로 인한 피해 범위를 해커의 SQL 언어 및 데이터베이스 구성에 대한 지식 수준으로만 제한할 수 있습니다.


이제 BadProductList.aspx에서 가져온 그림 2에 표시된 코드를 살펴 보십시오. 이 페이지는 Northwind 데이터베이스의 제품을 표시하고 사용자가 txtFilter라는 텍스트 상자를 사용하여 제품 결과 목록을 필터링하도록 할 수 있습니다. 마지막 예에서와 같이 이 페이지는 실행 SQL이 사용자가 입력하는 값으로 동적으로 생성되기 때문에 SQL 주입 공격에 당할 가능성이 높습니다. 이러한 특정 페이지는 약삭빠른 해커가 공격하여 기밀 정보를 훔치고, 데이터베이스의 데이터를 변경하고, 데이터베이스 레코드를 손상시키고, 심지어는 새로운 데이터베이스 사용자 계정을 만들 수도 있기 때문에 해커에게는 천국과도 같습니다.


SQL Server를 포함한 대부분의 SQL 호환 데이터베이스는 메타데이터를 sysobjects, syscolumns, sysindexes 등의 이름으로 일련의 시스템 테이블에 저장합니다. 즉, 해커는 이러한 시스템 테이블을 사용하여 데이터베이스에 대한 스키마 정보를 확신하고 추가적인 데이터베이스 손상을 위한 도움을 얻을 수 있습니다. 예를 들어 다음과 같이 txtFilter 텍스트 상자에 입력된 텍스트는 데이터베이스에서 사용자 테이블의 이름을 확인하는 데 사용될 수 있습니다.



UNION 문은 해커가 한 쿼리의 결과를 다른 쿼리로 분할할 수 있도록 하기 때문에 해커에게 특히 유용합니다. 이러한 경우 해커는 데이터베이스의 사용자 테이블 이름을 제품 테이블의 원래 쿼리로 분할합니다. 여기에 사용된 방법은 단지 열의 개수와 데이터 형식을 원래의 쿼리와 일치시키는 것 뿐입니다. 이전 쿼리는 Users라는 테이블이 데이터베이스에 있음을 나타낼 수 있습니다. 두 번째 쿼리는 Users 테이블에 있는 열을 노출시킬 수 있습니다. 해커는 이러한 정보를 사용하여 txtFilter 텍스트 상자에 다음을 입력할 수 있습니다.



이 쿼리를 입력하면 그림 3에서와 같이 Users 테이블에 있는 사용자 이름 및 암호를 노출시킵니다.

사용자 삽입 이미지


SQL 주입 공격은 또한 데이터를 변경하거나 데이터베이스를 손상시키는 데에도 사용될 수 있습니다. SQL 주입 해커는 txtFilter 텍스트 상자에 다음을 입력하여 첫 번째 제품의 가격을 $18에서 $0.01로 바꾸고 이러한 사실을 다른 사람이 눈치채기 전에 일부 제품을 재빠르게 구매할 수 있습니다.



이러한 해킹은 SQL Server에서 세미콜론이나 공백을 사용하여 구분된 여러 SQL 문을 함께 입력할 수 있도록 허용하기 때문에 가능합니다. 이 예에서 DataGrid는 아무 것도 표시하지 않지만 업데이트 쿼리는 성공적으로 실행됩니다. 이러한 같은 기술을 사용하면 DROP TABLE 문을 실행하거나 새로운 사용자 계정을 만들고 이 사용자를 sysadmin 역할에 추가하는 시스템 저장 프로시저를 실행할 수도 있습니다. 이러한 해킹은 모두 그림 2에 표시된 BadProductList.aspx 페이지를 사용하여 가능합니다.


동일한 해킹 기회


SQL 주입 공격은 SQL Server에만 국한된 문제가 아닙니다. Oracle, MySQL, DB2, Sybase 등의 다른데이터베이스에서도 이러한 종류의 공격을 받을 수 있습니다. SQL 주입 공격은 SQL 언어에 다음과 같이 강력하고 유연한 여러 기능이 포함되어 있기 때문에 가능합니다.


이중 하이픈을 사용하여 SQL 문에 주석을 포함시킬 수 있는 기능
여러 SQL 문을 함께 입력하고 이를 일괄 처리로 실행할 수 있는 기능
SQL을 사용하여 표준 시스템 테이블 집합으로부터 메타데이터를 쿼리할 수 있는 기능


일반적으로 데이터베이스에서 지원되는 SQL 언어의 기능이 강력할수록 데이터베이스에 대한 공격 가능성도 높아집니다. 따라서 SQL Server가 주입 공격의 일반적인 대상이 되는 것입니다.


SQL 주입 공격은 ASP.NET 응용 프로그램으로만 제한되지 않습니다. 기존의 ASP, Java, JSP 및 PHP 응용 프로그램도 모두 같은 위험이 있습니다. 실제로 SQL 주입 공격은 데스크톱 응용 프로그램에 대해서도 수행될 수 있습니다. 예를 들어 이 문서에 대한 다운로드 파일(이 문서의 맨 위에 있는 링크로 제공)에 SQL 주입 공격을 받을 수 있는 SQLInjectWinForm이라는 Windows Forms 응용 프로그램 예제를 포함되어 있습니다.


SQL 주입 공격 방지를 위한 한 두 개의 핵심 방법을 쉽게 설명할 수도 있지만 이 문제에 대해서는 계층적 방식을 사용하는 것이 가장 좋습니다. 이러한 방식에서는 일부 취약성으로 인해 보안 방식 중 하나가 무효화되더라도 계속해서 보호 상태를 유지할 수 있습니다. 권장되는 계층은 그림 4에 설명되어 있습니다.

사용자 삽입 이미지



모든 입력에 대한 검사 수행


그림 4에 나열된 첫 번째 원칙은 매우 중요한 것입니다. 모든 사용자 입력은 악의적인 것으로 간주하십시오! 데이터베이스 쿼리에서 검사되지 않은 사용자 입력을 사용해서는 안됩니다. 특히 RegularExpressionValidator 컨트롤과 같은 ASP.NET 유효성 검사 컨트롤은 사용자 입력의 유효성을 검사하기 위한 훌륭한 도구입니다.


유효성 검사에 대한 기본적인 두 가지 방식은 문제가 있는 문자를 허용하지 않거나 적은 수의 필수 문자만 허용하는 것입니다. 하이픈과 작은따옴표와 같은 문제가 되는 일부 문자를 쉽게 허용하지 않을 수도 있지만 이 방법은 두 가지 이유로 인해 적합하지 않을 수 있습니다. 첫 번째, 해커에게 유용하게 사용되는 문자를 놓칠 수 있으며, 두 번째 잘못된 문자를 표현하는 방법이 여러 가지일 수 있습니다. 예를 들어 해커는 작은따옴표를 이스케이프 처리하여 유효성 검사 코드에서 놓치도록 만들거나 이스케이프 처리된 따옴표를 데이터베이스에 전달하여 일반적인 작은따옴표 문자와 동일하게 취급되도록 할 수 있습니다. 더 나은 방법은 허용 가능한 문자를 식별하고 해당 문자만 허용하는 것입니다. 이러한 방식에는 더 많은 작업이 필요하지만 입력에 대해 보다 세밀한 제어가 가능하며 보다 안전합니다. 어떤 방식을 사용하던 간에 일부 해킹에는 많은 수의 문자가 필요하므로 입력에 대한 길이를 제한할 수 있습니다.


GoodLogin.aspx(다운로드 코드에서 제공)에는 두 개의 일반 식 유효성 검사 컨트롤이 포함되며, 이 중에서 하나는 사용자 이름에 대한 컨트롤이고 다른 하나는 암호에 대한 컨트롤입니다. 또한 여기에는 4-12개의 숫자, 알파벳 문자 및 밑줄로 입력을 제한하는 다음과 같은 ValidationExpression 값이 포함되어 있습니다.



사용자가 텍스트 상자에 잠재적으로 손상될 가능성이 있는 문자를 입력하도록 허용해야 할 수 있습니다. 예를 들어 사용자 이름의 일부로 작은따옴표(또는 어포스트로피)를 입력해야 할 수 있습니다. 이러한 경우 정규 식이나 String.Replace 메서드를 사용하여 각각의 작은따옴표를 두 개의 작은따옴표로 바꾸면 작은따옴표를 안전하게 렌더링할 수 있습니다. 예를 들면 다음과 같습니다.




동적 SQL 방지

이 문서에서 설명하는 SQL 주입 공격은 모두 동적 SQL의 실행을 기반으로 합니다. 즉, 사용자가 입력한 값과 SQL을 연결하여 생성되는 SQL 문입니다. 하지만 매개 변수가 있는 SQL을 사용하면 해커가 SQL을 코드에 주입할 수 있는 가능성이 크게 줄어듭니다.


그림 5의 코드는 매개 변수가 있는 SQL을 사용하여 주입 공격을 방지합니다. 매개 변수가 있는 SQL은 사용자가 임시 SQL을 사용해야 하는 경우 뛰어난 성능을 보여 줍니다. 이러한 방식은 IT 부서에서 저장 프로시저를 믿지 않거나 버전 5.0까지 이를 지원하지 않은 MySQL과 같은 제품을 사용하는 경우에 필수적입니다. 하지만 가능하다면 추가 기능에 대해 저장 프로시저를 사용하여 데이터베이스에 있는 기본 테이블에 대한 모든 권한을 제거하여 그림 3에 표시된 것과 같은 쿼리를 만들 수 있는 가능성을 제거해야 합니다. 그림 6에 표시된 BetterLogin.aspx는 procVerifyUser라는 저장 프로시저를 사용하여 사용자에 대한 유효성을 검사합니다.



최소 권한으로 실행

BadLogin.aspx 및 BadProductList.aspx에서 보여진 잘못된 구현 방법 중 하나는 sa 계정을 통해 연결 문자열을 사용한다는 점입니다. 다음은 Web.config에서 발견할 수 있는 연결 문자열입니다.




이 계정은 로그인 생성과 데이터베이스 삭제 등 거의 모든 작업을 수행할 수 있는 System Administrators 역할로 실행됩니다. 말할 필요도 없이 응용 프로그램 데이터베이스 액세스에 대해 sa(또는 고급 권한이 있는 계정)를 사용하는 것은 매우 잘못된 생각입니다. 대신 제한된 액세스 계정을 만들고 이를 사용하도록 하는 것이 훨씬 좋습니다. GoodLogin.aspx에 사용된 계정은 다음과 같은 연결 문자열을 사용합니다.




NWindReader 계정은 db_datareader 역할에 따라 실행되며 이 역할은 데이터베이스에 대한 테이블의 읽기로 액세스를 제한합니다. BetterLogin.aspx는 저장 프로시저와 WebLimitedUser 로그인을 사용하여 상황을 더욱 향상시켜 줍니다. 이 로그인에는 해당 저장 프로시저를 실행하는 권한만 포함되어 있으며 기본 테이블에 대해서는 어떠한 권한도 없습니다.


기밀 정보를 안전하게 저장하기

그림 3에 표시된 SQL 주입 공격은 Users 테이블의 사용자 이름과 암호를 노출시킵니다. 이러한 종류의 테이블은 일반적으로 폼 인증을 적용하는 경우에 사용되며 대부분의 응용 프로그램에서 암호는 일반 텍스트로 저장됩니다. 더 나은 방법은 데이터베이스에서 암호화된 암호 또는 해시된 암호를 저장하는 것입니다. 해시된 암호는 암호를 해독할 수 없기 때문에 암호화된 암호보다 안전합니다. 해시에 salt(암호화 방식으로 안전한 임의 값)를 추가하여 해시된 암호의 보안 성능을 더욱 높일 수도 있습니다. BestLogin.aspx에는 사용자가 입력한 암호를 SecureUsers 테이블에 저장된 암호의 salt로 지정된 해시된 암호와 비교하는 코드가 포함되어 있습니다(그림 7 참조). 해시된 퍼즐에 대한 또 다른 측면은 AddSecureUser.aspx에서 볼 수 있습니다. 이 페이지를 사용하면 salt로 지정되어 해시된 암호를 생성하고 이를 SecureUsers 테이블에 저장할 수 있습니다. BestLogin.aspx 및 AddSecureUser.aspx는 모두 그림 8에 표시된 것과 같이 SaltedHash 클래스 라이브러리의 코드를 사용합니다. Jeff Prosise가 만든 이 코드는 System.Web.Security 네임스페이스의 FormsAuthentication.HashPasswordForStoringInConfigFile 메서드를 사용하여 암호 해시를 만들고 System.Security.Cryptography 네임스페이스의 RNGCryptoServiceProvider.GetNonZeroBytes 메서드를 사용하여 16바이트의 임의 salt 값(Convert.ToBase64String을 사용하여 문자열로 변환할 겨우 24 문자가 됨)을 만들 수 있습니다.


SQL 주입 공격과 직접 관련되지는 않지만 BestLogin.aspx는 연결 문자열의 암호화라는 또 다른 최선의 보안 구현 방법을 보여 줍니다. 연결 문자열은 포함된 데이터베이스 계정 암호가 들어 있는 경우 BestLogin.aspx에서와 같이 특히 중요하게 보호되어야 합니다. 데이터베이스에 연결하려면 연결 문자열의 암호를 해독해야 하기 때문에 연결 문자열은 해시할 수 없습니다. 그 대신 연결 문자열을 암호화해야 합니다. 다음은 Web.config에 저장되어 있고 BestLogin.aspx에서 사용되는 암호화된 연결 문자열을 보여 줍니다.



BestLogin은 그림 9에서와 같이 SecureConnection 클래스로부터 GetCnxString 메서드를 호출하여 cnxNWindBest AppSetting 값을 검색하고 이를 다음 코드로 암호 해독합니다.



순서대로 SecureConnection 클래스는 호출을 Win32 DPAPI(데이터 보호 API)로 래핑하는 DataProtect 클래스 라이브러리(여기에 표시되지는 않지만 이 문서의 다운로드에 포함되어 있음)를 호출합니다. DPAPI의 다양한 기능 중 하나는 사용자를 위해 암호화 키를 관리하는 것입니다. DataProtect 클래스 라이브러리 및 이 라이브러리를 사용할 때 고려해야 하는 추가 옵션에 대한 자세한 내용은 Microsoft 패턴 및 연습 가이드 중 하나인 "보안적인 ASP.NET 응용 프로그램 작성: 인증, 권한 부여 및 보안 통신 (영문)"을 참조하십시오.

사용자 삽입 이미지


EncryptCnxString.aspx 페이지를 사용하면 시스템 특정 암호화된 연결 문자열을 만들어서 구성 파일에 붙여 넣을 수 있습니다. 이 페이지는 그림 10에 표시되어 있습니다. 물론, 암호화하거나 해시해야 하는 기밀 정보에는 암호 및 연결 문자열 외에도 신용 카드 번호 및 해커에게 노출될 경우 위험할 수 있는 기타 모든 정보가 포함됩니다. ASP.NET 2.0에는 암호 해싱 및 연결 문자열 암호화를 단순하게 만들어 주는 여러 기능이 포함되어 있습니다.


안전한 실패

런타임 예외를 적절하게 처리하지 못할 경우에도 해커는 이를 악용할 수 있습니다. 따라서 모든 프로덕션 코드에 예외 처리기를 포함시키는 것이 중요합니다. 또한 처리된 예외 및 처리되지 안은 예외는 항상 해커에게 도움이 될 수 있는 정보를 최소한으로만 제공해야 합니다. 처리된 예외의 경우 오류 메시지에서 원래 사용자에 대한 유용성과 악의적인 해커에게 너무 많은 정보를 제공하지 않는 보안성 간의 균형을 맞추어야 합니다.


처리되지 않은 예외의 경우에는 컴파일 요소(Web.config 파일)의 디버그 특성을 False로 설정하고 customErrors 요소의 모드 특성을 On 또는 RemoteOnly로 설정하여 해커에게 최소한의 정보만 표시되도록 해야 합니다. 예를 들어 다음을 보십시오.



RemoteOnly 설정은 localhost로부터 사이트에 액세스하는 사용자에게는 유용한 오류 메시지를 제공하고 원격 위치로부터 사이트에 액세스하는 다른 사용자에게는 예외에 대한 어떤 유용한 정보도 노출시키지 않는 일반적인 오류 메시지를 제공하도록 보장합니다. 로컬 사용자를 포함한 모든 사용자에게 일반 오류 메시지를 표시하도록 하려면 On 설정을 사용하십시오. 프로덕션 환경에서는 Off 설정을 절대로 사용하지 마십시오.


결론

SQL 주입 공격은 보안 시스템에 침입하여 데이터를 훔치거나, 변경 또는 삭제할 우려가 있기 때문에 응용 프로그램 개발자가 신중하게 다루어야 하는 문제입니다. 사용하는 ASP.NET 버전과는 관계없이 이러한 공격에는 너무나 쉽게 취약해질 수 있습니다. 실제로 ASP.NET을 사용하지 않는 경우에도 SQL 주입 공격에 쉽게 당할 수 있습니다. Windows Forms 응용 프로그램과 같이 사용자 입력 데이터를 사용하여 데이터베이스를 쿼리하는 모든 응용 프로그램은 잠재적으로 주입 공격의 대상이 될 수 있습니다.


SQL 주입 공격으로부터 자신을 보호하는 방법은 그렇게 어렵지 않습니다. 모든 사용자 입력에 대한 유효성을 검사 및 확인하고, 동적 SQL을 절대로 사용하지 않고, 최소 권한으로 계정을 사용하고, 해당 기밀 정보를 해시 또는 암호화하고, 해커에게 유용한 정보를 제공하지 않도록 거의 정보를 표시하지 않는 오류 메시지를 제공하는 응용 프로그램은 SQL 주입 공격을 매우 효과적으로 방지할 수 있습니다. 여러 계층의 공격 방어 방법을 사용할 경우 하나의 방법이 실패하더라도 계속해서 보호 상태를 유지할 수 있습니다. [주입 공격 취약성에 대한 응용 프로그램 테스트 정보는 측면 메뉴에 있는 "주입 공격 테스트"를 참조하십시오.]


제공 : DB포탈사이트 DBguide.net

출처명 : 한국마이크로소프트
"MSSQL" 카테고리의 다른 글
  • SQL 서버에서「데이터 코드 에러」처리하기 (0)2007/05/25
  • SQL 성능을 높이는 5가지 방법 (1)2007/05/25
  • 데이터 보안 [SQL 주입 공격 대처 방법] (0)2007/05/25
  • 기본적인 시스템 테이블과 저장프로시저 (0)2007/05/25
  • 다중 데이터베이스 작업 방법론 (0)2007/05/25
2007/05/25 10:31 2007/05/25 10:31
Posted by webdizen
Tags SQL 주입, 데이터베이스, 동적 SQL, 보안, 해킹
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3034

Leave your greetings.

[로그인][오픈아이디란?]

Programming/.NET2007/01/09 10:28

.NET Framework의 강력한 이름 및 보안

고수닷넷 - 방랑자

.NET Framework의 강력한 이름 및 보안

Keith Brown
DevelopMentor

요약: 강력한 이름은 어셈블리를 고유하게 식별하여 전역 어셈블리 캐시에 배치되도록 하는 데 필요합니다. 또한 Microsoft .NET Framework 공용 언어 런타임에서 버전 지정 시스템을 사용하는 데도 필요합니다. 강력한 이름에 대한 자세한 정보와 사용 방법을 살펴봅니다(10페이지/인쇄 페이지 기준).

목차

GUID에서 공개 키까지
RSA 및 디지털 서명
CLR 및 공개 키
강력한 이름 및 확인
강력한 이름 및 .NET 보안 정책
공개 키 및 버전 지정
서명 연기를 사용하여 노출 줄이기
개발 팀 보호
결론

GUID에서 공개 키까지

강력한 이름의 근본적인 개념을 이해하려면 Microsoft Windows 플랫폼의 이전 구성 요소 네이밍 스키마인 GUID(Globally Unique Identifier)를 살펴보는 것이 좋습니다. GUID는 COM 분야에서 여러 항목을 명명하는 데 사용되는 128비트(16바이트) 고유 정수입니다. 레지스트리 작업을 해 본 적이 있다면 오늘날 무수히 많은 GUID가 사용되고 있다는 것을 알고 있을 것입니다. COM 프로그래머라면 GUID가 매우 세부적인 항목을 명명하는 데 사용되었기 때문에 이러한 사실을 알고 있습니다. 각 COM 클래스, COM 인터페이스, 응용 프로그램, 형식 라이브러리 및 열거에는 고유의 GUID가 필요합니다. 실제로 GUID는 과도할 정도로 사용되고 있습니다.

Windows 2000 이전에는 GUID가 DCE RPC의 일부분으로 정의된 UUID(Universally Unique Identifier)를 기준으로 생성되었습니다. 간단히 말해 UUID의 고유한 특성은 현재 날짜 및 시간에서 파생되며, 고유 48비트 IEEE 802 주소는 NIC(네트워크 인터페이스 카드)에서 파생됩니다.

Windows 2000부터 GUID는 더 이상 이 알고리즘을 기준으로 생성되지 않습니다. 대신 CryptoAPI에서 제공하는 난수 생성기를 호출하여 생성된 임의의 16바이트 정수가 GUID입니다. 이렇게 변경된 가장 큰 이유는 1999년 초에 나타난 개인 정보 보호 문제 때문입니다. 당시 Microsoft Office는 데이터 파일에서 GUID를 유일한 식별자로 사용했습니다. 그러나 불행하게도 GUID에서 사용된 NIC 주소를 통해 문서가 작성자에게 다시 연결될 수 있는 부작용이 있었습니다. 따라서 데이터 파일에 GUID를 넣으면 익명성이 보장되지 않으므로 보안상 좋지 않았습니다.

COM에서의 모든 명명 문제를 파악한 CLR(공용 언어 런타임) 팀은 구성 요소를 고유하게 식별할 수 있는 보다 나은 방법을 만들고자 했습니다. 그리고 핵심적인 결정은 계층 구조 네이밍 스키마를 사용하기로 한 것이었습니다. COM에서 GUID를 사용할 때와 같이 개별 형식마다 고유 식별자를 지정하는 대신, CLR 형식은 네임스페이스를 비롯한 전체 형식 이름과 형식이 패키지된 어셈블리의 이름을 기준으로 식별됩니다. 덕분에 클래스, 인터페이스 등에 간단한 형식 이름을 사용할 수 있게 되었습니다. 로더는 어셈블리의 이름을 각 형식 이름의 일부분으로 간주하므로 실제로는 네임스페이스가 컴파일 시간 명명 충돌을 해결하는 데 중요함에도 불구하고 각 어셈블리에 공간 및 시간적으로 고유한 이름을 지정하기만 하면 됩니다. 계층 구조 스키마를 사용하여 명명함으로써 GUID가 너무 길어지는 문제를 완전히 해결했습니다.

이로써 CLR 팀은 고유 어셈블리 이름을 생성하기 위한 알고리즘을 찾아내기만 하면 되었습니다. 이름의 일부분은 GUID와 비슷한 큰 난수일 가능성이 있습니다. 또한 충돌에 어느 정도 더 저항할 수 있도록 16바이트보다 클 수도 있습니다. 따라서 사용자가 어셈블리를 명명할 때 사용한 것과 동일한 식별자를 다른 사람이 실수로 선택하는 일이 없게 됩니다. 그러나 공격자가 사용자의 어셈블리와 비슷하게 보이는 트로이 목마 어셈블리를 고의적으로 만드는 것은 막지 못합니다. 이를 해결하기 위해 CLR 팀은 흥미로운 결정을 내렸습니다. 단순히 큰 난수를 사용하는 대신 매우 큰 임의의 소수 두 개를 곱해서 얻은 128바이트 숫자인 1024비트 RSA 공개 키를 사용하기로 결정한 것입니다.

강력한 이름을 이해하기 위해서는 암호화의 역할을 이해하는 것이 중요하므로 이번에는 암호화에 대해 알아보겠습니다.

RSA 및 디지털 서명

이 항목에 대한 자세한 소개는 Practical Cryptography(Ferguson/Schneier 공저, Wiley 2003: 영문)를 참고하십시오. 간단히 말해 RSA의 기초적인 개념은 키가 공개 키 및 개인 키의 한 쌍으로 생성된다는 것입니다. 개인 키는 비밀이므로 아무에게 알려 줘서는 안 됩니다. 반대로 공개 키는 다른 사람과 공유할 수 있습니다. 공개 키를 가지고 개인 키를 알아내는 것은 불가능한 것으로 알려져 있습니다. 공개 키를 사용하여 암호화한 데이터는 개인 키로만 해독할 수 있으며, 개인 키를 사용하여 암호화한 데이터는 공개 키로만 해독할 수 있습니다.

RSA 키는 디지털 서명을 통해 데이터의 무결성을 보장하는 데 사용될 수 있습니다. 일부 데이터에 서명하려면 먼저 암호화 해시 알고리즘을 사용하여 해당 데이터를 해시한 다음 개인 키를 사용하여 최종 해시 값을 암호화합니다. 실제로 서명은 이 암호화된 해시 값일 뿐입니다. 데이터와 서명을 게시하면 사용자의 공개 키를 알고 있는 모든 사람이 데이터를 해시하고 자신의 해시 값과 사용자 서명 안에 있는 해시 값을 비교하여 서명을 확인한 다음 사용자의 공개 키를 사용하여 해독할 수 있습니다. 즉, 받은 데이터가 원래 서명된 데이터와 동일하고 서명자가 개인 키를 알고 있는 경우에만 해시가 일치하는 것이 기본 개념입니다. 이 기술을 어셈블리에 적용하면 서명을 위조할 수 없기 때문에 공격자가 사용자의 어셈블리를 트로이 목마 버전으로 바꿀 수 없습니다. 물론 그 사람은 사용자의 개인 키를 몰라야 합니다. 따라서 개인 키를 보호하는 것은 매우 중요하며, 개인 키를 주고받는 방법을 설명하는 것이 본 문서의 주요 목적 중 하나입니다.

RSA 공개 키를 어셈블리 이름의 일부분으로 사용할 경우 CLR 팀은 일석이조의 효과를 얻습니다. 첫째는 안전성입니다. 임의로 생성되는 RSA 공개 키는 기본 특성상 충돌하는 경우가 없으므로 실수로 명명 충돌이 발생하지 않습니다. 실제로 1024비트 공개 키는 GUID보다 8배 큽니다. 둘째는 보안입니다. 대응하는 개인 키를 사용하여 어셈블리에 서명할 수 있으므로 공격자가 사용자의 어셈블리를 자신의 코드로 바꿀 수 없습니다. 그러나 모든 보안 조치와 마찬가지로 여기에는 개인 키를 항상 비밀로 간직해야 하는 책임이 따릅니다. 개인 키가 노출될 경우에는 보안상 위험해지며 심각한 호환성 문제가 발생할 수 있습니다.

CLR 및 공개 키

강력한 이름의 어셈블리에는 공개 키가 할당됩니다. 이 할당 작업은 컴파일러에서 처리합니다. 예를 들어 자신의 키 쌍을 생성할 경우 다음과 같이 단순히 컴파일러에 키 파일의 위치를 알림으로써 새로 만드는 어셈블리에 공개 키를 할당할 수 있습니다.

using System.Reflection;
[assembly: AssemblyKeyFile(@"c:\temp\mykeyfile")]

class Foo {...}

Microsoft Visual Studio .NET에서 마법사에 의해 생성된 대부분의 프로젝트는 이 특성을 AssemblyInfo라는 파일에 넣지만 사용자는 원하는 원본 파일에 넣을 수 있습니다. 컴파일러에서는 이 특성을 발견하면 전체 공개 키를 어셈블리의 메타데이터에 복사하고 개인 키를 사용하여 디지털 서명을 만듭니다. 이 작업은 어셈블리에서 파일을 해시하고, 해당 해시 값을 어셈블리의 매니페스트에 통합하며, 매니페스트를 해시하고, 마지막으로 대응하는 개인 키를 사용하여 이 최종 해시 값을 암호화한 다음 어셈블리에 있는 또 다른 메타데이터 블록으로 감추는 순서로 이루어집니다.

간단하게 요약하여 설명한 이 방법을 컴파일러가 사용하려면 c:\temp\mykeyfile 파일에 공개 키뿐만 아니라 개인 키도 있어야 합니다. 이 문서의 뒷부분에서 코드 서명에 대한 보다 안전한 접근법을 배울 수 있습니다.

ILDASM을 사용하여 어셈블리의 매니페스트를 살펴보면 그림 1과 같이 공개 키를 확실하게 볼 수 있습니다.


사용자 삽입 이미지


그림 1. 어셈블리에 할당된 공개 키

서명이나 중간 해시 값은 표시되지 않습니다. 때로는 이것이 강력한 이름에 대해 배우는 사람들을 혼란스럽게 하기도 합니다. ILDASM은 디스어셈블러이기 때문에 서명이나 중간 해시 값을 표시하지 않습니다. 어셈블리에 컴파일될 수 있는 IL을 만들기만 하면 됩니다. 그리고 서명 및 해시 값은 컴파일러(이 경우 ILASM)에서 출력됩니다. 어셈블리에 공개 키가 할당되었는지 보려면 강력한 이름 도구인 SN.EXE를 사용하십시오.

sn -Tp foo.dll


그러면 어셈블리의 공개 키가 출력되거나 어셈블리에 강력한 이름이 지정되지 않았다는, 즉 공개 키가 할당되어 있지 않다는 의미의 메시지가 나타납니다. 그러나 어셈블리에 공개 키가 있다고 해서 반드시 대응하는 서명이 있거나 해당 서명이 유효한 것은 아닙니다. 서명의 존재 여부와 유효성을 테스트하려면 다음 명령을 사용하십시오.

sn -vf foo.dll

그러면 SN.EXE가 어셈블리에 있는 각 파일의 자체 해시를 계산하여 어셈블리 바이너리가 서명 이후에 변경되지 않았는지 확인합니다. 그런 다음 어셈블리 매니페스트의 자체 해시를 계산하고, 어셈블리에 패키지된 서명(ILDASM에 표시되지 않는 서명)을 해독하고, 자체적으로 계산한 해시 값을 해독된 서명과 비교합니다. 해시가 일치하면 어셈블리가 유효하다는 내용을 보고하고 그렇지 않으면 오류를 보고합니다. 나중에 자세히 설명할 서명 연기된 어셈블리의 경우처럼 단순히 어셈블리에 아직 서명이 적용되지 않아서 오류가 발생할 수도 있습니다.

.NET Framework와 함께 제공되는 도구를 사용하여 새 어셈블리를 GAC(전역 어셈블리 캐시)(GACUTIL.EXE 또는 Fusion 캐시 뷰어)에 설치하면 다음 명령에 해당하는 서명 확인이 수행됩니다.

sn -v foo.dll

GAC에 상주하지 않는 강력한 이름의 어셈블리를 CLR에서 로드할 때마다 동일한 상황이 발생합니다. 공개 키가 있으면 서명을 확인합니다. sn -vf 명령과 sn -v 명령 사이의 미묘한 차이는 후자의 경우 관리자가 신뢰하는 항목으로 등록한 공개 키에 대해서는 서명 확인을 건너뛴다는 것입니다. 신뢰하는 항목에 대해서는 나중에 자세히 설명하겠습니다. 요약하자면 CLR은 로드할 때 또는 어셈블리가 GAC에 설치될 때 어셈블리 서명을 확인합니다.

GAC는 신뢰된 리포지토리로 간주됩니다. GAC에 설치된 어셈블리를 수정하지 못하도록 막는 유일한 보호 장치는 GAC의 모든 항목에 있는 강력한 파일 시스템 ACL입니다. 이는 CLR 및 기타 운영 체제 바이너리를 보호하는 ACL과 근본적으로 동일합니다. 공격자가 컴퓨터의 관리 권한을 가지게 되면 GAC에 있는 어셈블리를 트로이 목마 버전으로 바꿀 수 있습니다. 이 경우 CLR은 GAC에서 어셈블리를 로드할 때 서명을 다시 확인하지 않으므로 해당 어셈블리가 트로이 목마 버전으로 바뀐 것을 알지 못합니다. 하지만 외부인이 GAC에서 어셈블리를 수정하거나 바꿀 수 있을 정도의 파일 시스템 권한을 가지게 되면 CLR 바이너리(MSCORWKS.DLL 및 유사 항목) 또는 운영 체제 자체에 대해서도 동일한 작업을 수행할 수 있습니다. 로드 시간을 줄이기 위해 CLR은 GAC에서 로드된 어셈블리의 서명을 다시 확인하지 않습니다.

강력한 이름 및 확인

CLR 어셈블리 해결 프로그램은 어셈블리를 약한 방법 또는 강한 방법의 두 가지 방법으로 참조합니다. 약한 방법은 파일 이름에서 확장명을 뺀 약식 어셈블리 이름만 고려합니다. 예를 들어 FOO.DLL의 약식 어셈블리 이름은 FOO입니다. 로드할 때 버전 확인을 수행하지 않습니다. 반대로 강력한 이름은 약식 이름과 그 외에 버전 번호, culture 및 공개 키의 세 부분으로 구성됩니다. 공개 키를 어셈블리에 할당하면 "강력한 이름"이 지정된 것으로 간주됩니다. 이 어셈블리를 참조하는 다른 어셈블리는 이 어셈블리에서 네 부분으로 구성된 이 강력한 이름을 사용합니다. 실제로 이는 곧 어셈블리를 GAC에 넣고 버전 정책의 이점을 활용할 수 있다는 의미입니다.

공개 키, 서명, 해시 등의 개념에 너무 신경을 쓰다 보면 실제로 무엇이 어떻게 보호되는지를 잊기 쉽습니다. CLR이 보증하려는 것은 다음과 같습니다. FOO.DLL이라는 어셈블리를 빌드하고 서명하면, 즉 강력한 이름을 지정하면 컴파일 시 자신의 어셈블리에서 FOO.DLL을 참조하는 모든 사람에게 사용자(강력한 이름 뒤에 숨겨진 개인 키를 알고 있는 사람)가 만든 FOO.DLL도 런타임에 전달됩니다. 버전 정책에 따라 CLR에서 원본 대신 다른 버전을 사용할 수도 있으므로 정확하게 일치하는 FOO.DLL이 아닐 수도 있지만, 원본 FOO.DLL을 만든 사람이 런타임 시 코드를 만들었다는 보증이 어느 정도는 있어야 합니다. 그러면 제3자가 FOO.DLL을 트로이 목마 버전으로 바꿀 수 없게 됩니다.

구현 방법은 다음과 같습니다. 예를 들어 FOO.DLL이라는 강력한 이름의 어셈블리를 참조하는 BAR.EXE라는 어셈블리를 컴파일하는 경우 컴파일러는 FOO.DLL의 강력한 이름을 BAR.EXE의 매니페스트에 기록합니다. 여기에는 공개 키에 대한 참조가 포함됩니다(그림 2 참고). 로드 시, 어셈블리 바이너리의 무단 수정을 감시하기 위한 일반 서명 확인 외에도 로더는 FOO.DLL의 공개 키가 BAR.EXE에 기록된 공개 키와 일치하는지 확인합니다. 따라서 어셈블리 사이의 연결이 보호됩니다.

사용자 삽입 이미지


그림 2. 강력한 이름의 어셈블리에 대한 참조

이제 BAR.EXE가 보호하는 내용을 알아보겠습니다. 명령 셸을 열고 단순히 BAR <Enter>를 입력하여 BAR.EXE를 실행할 경우에는 BAR.EXE가 트로이 목마로 바뀌었는지 알 수 있는 방법이 전혀 없습니다. 이는 문제가 될 수 있습니다. 트로이 목마가 아니라는 확신을 가지려면 BAR.EXE의 알려진 올바른 공개 키를 운영 체제에 제공할 수 있는 방법이 필요합니다. 그렇지 않으면 공격자가 임의로 생성한 키를 사용하여 BAR.EXE의 트로이 목마 버전에 서명할 수 있기 때문입니다. CLR은 BAR.EXE 자체에 일관성이 있는지 확인할 수 있습니다. 즉, 매니페스트에 공개 키가 있으면 서명을 확인할 수 있습니다. 그러나 이 경우에는 BAR.EXE의 원래 작성자가 할당한 공개 키가 아닙니다. 이 문제는 Assembly.Load()를 호출하여 공개 키 정보를 어셈블리 이름과 함께 전달하는 작은 로더 프로그램을 만들어서 해결할 수 있습니다. 이 프로그램을 LOADER.EXE라고 가정하겠습니다. 그러나 이 LOADER.EXE를 확인할 경우에도 동일한 문제가 발생합니다.

Microsoft ASP.NET 페이지와 BAR.EXE는 비슷합니다. 다음과 같이 페이지에서 강력한 이름의 어셈블리를 참조할 수는 있지만,

<%@assembly name='foo, Version=1.0.0.0,
Culture=neutral,PublicKeyToken=2d7adc3047e7238d'%>

ASP.NET에 페이지 어셈블리의 강력한 이름을 알릴 수 있는 방법은 없습니다. 페이지에 강력한 이름을 지정할 수 있다 하더라도 큰 도움이 되지 않습니다. 반면에 web.config 또는 machine.config에 등록된 미리 컴파일된 처리기나 모듈은 강력한 이름을 통해 참조할 수 있습니다. 물론 공격자가 구성 파일을 수정하고 공개 키를 자신의 것으로 바꿀 수 있는 경우에는 확인이 실패합니다.

한 가지 세부적인 구현 사항을 살펴볼 필요가 있습니다. 위의 어셈블리 참조에서 전체 공개 키가 아닌 "공개 키 토큰"을 사용하여 어셈블리를 참조하는 방법에 주목하십시오. 이 토큰은 공개 키의 손도장과 같습니다. 강력한 이름을 사용하여 어셈블리를 참조하는 경우 항상 공개 키 토큰을 사용하므로 로더가 제공할 수 있는 최상의 확인 방법은 지정된 손도장이 로드 중인 어셈블리의 공개 키와 일치하는지를 확인하는 것뿐입니다. 공격자가, 자신이 개인 키를 알고 있는 RSA 키 쌍에 대해 공개 키의 손도장이 사용자의 것과 동일한 다른 RSA 키 쌍을 생성할 수 있는 확률이 어느 정도인지 알아보겠습니다. 공개 키 토큰은 공개 키의 20바이트 SHA1 해시에서 아래쪽의 8바이트를 사용하여 구성됩니다. 8바이트 토큰의 경우 가능한 값은 2^64개입니다. 오늘날의 하드웨어에서는 2^64 단계를 완료하는 것이 꽤 쉽기 때문에 이것만으로는 외부 공격을 바로 차단할 수 없습니다. 하지만 RSA 키 쌍을 계산하는 것은 쉽지 않은 작업이고 이를 2^64번 계산한다는 것은 상당한 금액의 특수 하드웨어를 구입하지 않고서는 어렵습니다. 다시 말해 보통의 해커가 이러한 하드웨어를 혼자서 구입하기는 어렵지만 근처에서 흔히 볼 수 있는 정보 대행사에서는 이를 이미 구비하고 있을 것입니다.

보안을 유지하는 데 강력한 이름 확인 기능만을 사용하는 경우에는 손도장에 대한 공격을 염두에 두어야 합니다. 전체적으로 보면 손도장이 보안상 가장 취약한 부분이기 때문입니다. CLR 팀에서 여러 가지 조건을 검토한 결과 이 보안 방법을 선택한 이유는 쉽게 이해할 수 있습니다. 8바이트 공개 키 토큰을 입력하면 16번의 키 입력이 필요하지만 훨씬 높은 수준의 보안을 제공하는 전체 20바이트 SHA1 해시를 입력하려면 40번의 키 입력이 필요하기 때문입니다. 하지만 공개 키 토큰을 입력하는 경우는 그리 많지 않습니다. 특히 .NET Framework 구성 스냅인 같은 도구가 주어질 경우에는 더욱 그렇습니다. 그리고 예를 들어 공개 키 토큰이 Microsoft의 공개 키와 같은 대체 RSA 키 쌍을 계산하고 게시하는 작업은 혼자서도 가능합니다. 앞으로 이 손도장의 길이가 늘어나기를 기대합니다.

손도장에 대한 이 이론적인 논의는 개인 키가 노출될 경우에는 아무런 의미가 없습니다. 공격자가 개인 키를 알고 있으면 트로이 목마로 사용할 모든 어셈블리에 서명할 수 있습니다.

강력한 이름 및 .NET 보안 정책

개인 키가 노출될 경우 트로이 목마 어셈블리만 문제가 되는 것은 아닙니다. 공격자가 사용자의 컴퓨터에서 강력한 이름의 어셈블리를 트로이 목마 버전으로 바꾸려면 강력한 이름 확인을 통과해야 합니다. 또한 사용자의 컴퓨터에 코드를 넣어야 합니다. 다행히도 이는 간단한 일이 아닙니다. 하지만 좀 더 직접적이고 위험한 공격은 신뢰 결정이 이루어지는 리포지토리인 .NET 보안 정책과 관련된 것입니다. 이 정책은 네트워크를 통해 침투할 수 있는 알려진 관리되는 맬웨어(malware, malicious와 software의 합성어)로부터 컴퓨터를 안전하게 보호합니다. 다음에 컴퓨터에 관리자로 로그인할 경우 시작 메뉴의 관리 도구에 있는 .NET Framework 구성 도구를 열어 보십시오. 이 도구를 사용하여 런타임 보안 정책을 어느 정도 살펴볼 수 있습니다. 컴퓨터 정책 수준 아래의 코드 그룹 트리를 전체 확장하면 보안 정책이 간혹 강력한 이름을 기준으로 매우 많은 항목을 신뢰하는 것을 볼 수 있습니다. 예를 들어 Microsoft_Strong_Name이라는 코드 그룹은 Microsoft 소유의 특수 키로 서명된 모든 로컬 설치 코드를 완전히 신뢰합니다. 이 키는 .NET Framework 자체를 구성하는 핵심 어셈블리에 서명하는 데 사용됩니다.

조직에서 .NET Framework을 도입하고 자동 배포 같은 기능을 사용하기 시작함에 따라 강력한 이름을 기준으로 더 많은 보안 정책이 결정됩니다. 당연히 부분적으로 신뢰되는 환경에서 실행되는 프로그램을 만들고자 하는 조직은 거의 없으므로 보안 정책은 내부 회사의 강력한 이름을 기준으로 완전 신뢰를 부여하도록 구성될 것입니다. 다행히도 강력한 이름을 보안 정책의 일환으로 지정할 경우 손도장뿐만 아니라 전체 공개 키가 지정됩니다. 하지만 이것도 공격자가 개인 키를 알아낸 경우에는 별 도움이 되지 못합니다. 공격자가 개인 키를 알게 되면 원하는 모든 코드에 서명하고 사용자의 강력한 이름을 지정할 수 있습니다.

다음 시나리오를 보면 이 문제를 좀 더 확실히 파악할 수 있습니다. 예를 들어 Windows Forms 응용 프로그램이 웹 서비스의 씩(thick) 클라이언트 역할을 하고 있습니다. 그리고 편의상 이 씩(thick) 클라이언트를 자동 배포로 게시했습니다. 사용자는 브라우저에서 링크를 클릭하기만 하면 아무런 문제 없이 항상 클라이언트의 최신 버전을 얻을 수 있습니다. 하지만 클라이언트 프로그램은 때때로 P/Invoke를 통한 호출을 사용하여 일부 레거시 코드에 액세스하므로, 사용자가 클라이언트를 배포한 방법으로 인해 예외가 throw됩니다. 네트워크에서 다운로드한 코드는 모바일 코드로 간주되며 기본적으로 관리되지 않은 코드를 직접 호출할 수 있을 정도로 신뢰되지 않습니다. 이 문제를 해결하기 위해 .NET 보안 정책이 조직 전반에서 강력한 이름의 어셈블리를 완전히 신뢰하도록 업데이트했다고 가정합니다. 그림 3은 이러한 내용을 보여 줍니다.

사용자 삽입 이미지


그림 3. 강력한 이름에 완전 신뢰 부여

이 시나리오에서는 공격자가 사용자의 개인 키를 알아내는 경우 자신의 웹 사이트에 사용자의 강력한 이름이 있는 코드를 게시할 수 있습니다. 공격자가 조직 내 누군가를 속여서 자신의 코드를 가리키는 링크를 클릭하도록 할 경우 그 코드는 아무런 경고도 없이 링크를 클릭한 사람의 모든 권한으로 자동 실행됩니다. 이는 꽤 위험한 요소입니다. 이와 같은 시나리오를 통해 개인 키를 안전하게 보호해야 하는 이유를 알 수 있습니다.

이 내용은 Authenticode 서명을 만드는 데 사용되는 키는 물론, 다른 유형의 개인 키에도 적용됩니다. .NET 보안 정책에서 게시자 증거로 변환되는 Authenticode 서명을 강력한 이름 대신 사용하여 완전 신뢰를 부여하는 동일한 시나리오에서도 위험 요소는 동일합니다.

그림 3에서와 같이 ACME_Strong_Name 코드 그룹을 루트가 아닌 LocalIntranet_Zone 코드 그룹 아래에 넣어서 Microsoft_Strong_Name을 My_Computer_Zone 코드 그룹 아래에 넣는 것과 같은 방법으로 보안을 더욱 강화할 수 있습니다. 자식 코드 그룹은 부모가 일치하는 경우에만 평가됩니다. 따라서 어셈블리가 LocalIntranet 영역에서 로드되고 어셈블리에 사용자의 강력한 이름이 있는 경우에만 완전 신뢰를 부여하는 정책이 만들어집니다. 물론 이 이후로는 대부분의 회사에서 생각하는 것보다 더 심각한 위험인 내부인의 공격에 대비해야 합니다.

이는 아무리 강조해도 부족합니다. 강력한 이름을 사용하는 경우 어셈블리에 서명하는 안전한 프로세스가 필요합니다. 그렇지 않으면 개인 키가 노출될 수 있습니다. 이러한 프로세스에 대한 간단한 설명 이전에 먼저 개인 키를 안전하게 관리해야 하는 한 가지 이유를 더 살펴보겠습니다.

공개 키 및 버전 지정

버전 정책은 공개 키를 사용할 때 고려해야 하는 흥미로운 요소입니다. 일단 여기서는 어셈블리에는 항상 동일한 공개 키가 있지만 버전은 시간이 지남에 따라 바뀐다고 가정하겠습니다. 버전 정책은 다양한 방법을 통해 시스템 관리자나 소프트웨어 게시자가 응용 프로그램에 로드되는 어셈블리의 버전에 영향을 미칠 수 있도록 합니다. 그러나 버전 정책은 어셈블리 이름과 공개 키가 일관되게 유지되는 경우에만 작동합니다. 다시 말해 어셈블리 FOO의 버전 1을 하나의 공개 키로 게시한 다음, 두 번째 공개 키를 사용하여 FOO의 버전 2를 게시해서는 안 됩니다. 어셈블리 공개 키는 장기간 사용해야 하므로 한 공개 키를 선택하여 어셈블리에 적용한 이후에는 어셈블리의 수명이 다할 때까지 모든 버전에 걸쳐 그대로 유지해야 합니다.

이는 PKI(공개 키 인프라) 시스템에서 크게 문제가 되는 키 해지와 정반대입니다. 즉, 개인 키를 잃어 버리거나 개인 키가 노출되었다고 생각되는 경우에는 공개 키를 해지하고 새로 받을 수 있습니다. 그러나 사실 이 과정이 말처럼 쉬운 것은 아닙니다. 그러나 CLR에서 버전 정책 및 GAC를 사용하여 여러 응용 프로그램 간에 공유되는 어셈블리를 관리하는 경우에는 개인 키가 노출되는 경우 버전 지정 및 호환성 면에서 큰 문제가 발생합니다. 새 키 쌍을 만들려면 이전 공개 키를 사용하는 모든 응용 프로그램을 다시 컴파일해야 합니다. 그러면 업그레이드가 어려워지므로 이를 방지하기 위해서라도 개인 키를 잘 보호해야 합니다.

보안이 중요한 문제인 경우에는 키를 오프라인으로 저장할 수 있는 하드웨어를 구입하는 것이 좋습니다. 이 하드웨어를 스마트 카드라고 합니다. 스마트 카드에 대해서는 차후에 자세히 설명하는 문서가 나올 것입니다. 하지만 지금도 서명 연기라는 기술을 사용하여 즉시 보안을 강화할 수 있습니다.

서명 연기를 사용하여 노출 줄이기

개인 키의 노출을 줄이는 가장 간단한 방법 중 하나는 어셈블리를 서명 연기하는 것입니다. 이 기술을 사용하면 컴파일러가 개인 키를 모르는 상태에서 어셈블리를 빌드합니다. 컴파일러에는 비밀 항목이 아닌 공개 키만 필요합니다. 작동 방법은 다음과 같습니다.

첫 단계로 강력한 이름에 대해 하나 이상의 RSA 키 쌍을 생성합니다. 아직 스마트 카드 하드웨어가 없는 경우에는 키를 파일 시스템에 저장해야 하므로 아무런 네트워크에도 연결되어 있지 않은 안전한 컴퓨터에 저장해야 합니다. 다음 명령을 사용하여 각 RSA 키 쌍을 생성합니다.

sn -k pubpriv

SN 도구가 pubpriv라는 파일에 새 키 쌍을 만듭니다. 다음 명령을 곧바로 실행하여 pub라는 두 번째 파일에 공개 키만 복사하십시오.

sn -p pubpriv pub

pub를 이동식 미디어에 복사하여 다른 컴퓨터로 이동합니다. 이제 pubpriv를 컴퓨터에서 제거하고 저장실에 넣습니다. 첫 번째로 서명한 어셈블리를 제품 그룹 외부의 다른 사람에게 전달하기 전에는 이 파일이 필요하지 않습니다. 어셈블리를 컴파일해야 하는 모든 사람에게 pub를 배포합니다. pub의 내용은 비밀이 아니므로 노출될까 걱정하지 않아도 됩니다.

강력한 이름에 사용할 각 키 쌍마다 이 절차를 따르십시오. 그런 다음 모든 개인 키가 저장실에 안전하게 저장되고 손실, 손상 또는 유출의 우려가 없다고 확신하면 개인 키를 생성할 때 사용한 컴퓨터의 하드 드라이브를 파기합니다. 말 그대로 아무도 찾지 못하게 파기하십시오. 물론 스마트 카드를 사용하고 있었다면 하드 드라이브에 개인 키를 저장할 필요가 없기 때문에 저장 및 유지가 간단해집니다. 따라서 스마트 카드 하드웨어는 반드시 구입하는 것이 좋습니다.

어셈블리를 서명 연기하려면 AssemblyKeyFile 특성을 사용하여 필요로 하는 각 개발자의 컴퓨터에 있어야 하는 pub 파일을 참조하십시오. 또한 AssemblyDelaySign 특성을 다음과 같이 적용합니다.

[assembly: AssemblyKeyFile(@"c:\keys\pub")]
[assembly: AssemblyDelaySign(true)]

그러면 컴파일러가 번거롭게 서명을 생성하지 않고, 만드는 어셈블리에 공개 키를 포함시킵니다. 그리고 나중에 서명을 추가할 수 있도록 어셈블리에 공백을 남깁니다.

마지막으로 이렇게 서명되지 않은 어셈블리를 테스트하는 데 사용하는 컴퓨터에서는 해당 공개 키에 대해 강력한 이름 확인을 건너뛰도록 CLR에 지시해야 합니다. 그러기 위해서는 공개 키의 공개 키 토큰, 즉 이전에 설명한 손도장이 필요합니다. 다음 명령을 사용하여 손도장을 확인할 수 있습니다.

sn -t pub

예를 들어 공개 키 토큰이 bc19568c6e03e7e6인 경우 컴퓨터에서 확인을 건너뛰도록 하려면 다음과 같이 토큰을 등록해야 합니다.

sn -Vr *,bc19568c6e03e7e6

그러면 로드할 때 또는 어셈블리를 GAC에 설치할 때 위의 공개 키 토큰이 있는 어셈블리에 대해서는 CLR에서 서명을 확인하지 않습니다.

어셈블리를 개발 팀 외부의 사람에게 전달할 준비가 되었으면 컴파일된 어셈블리를 안전한 컴퓨터로 가져오고, 저장실에서 pubpriv 파일을 가져와 컴퓨터에 설치한 후 다음 명령을 실행합니다.

sn -R assemblyfile

이 명령은 개인 키를 사용하여 어셈블리에 서명함으로써 컴파일러가 남겨 놓은 공백을 채웁니다. 그리고 이제 또 하나의 하드 드라이브를 파기할 차례입니다. 물론 스마트 카드가 있으면 이렇게 하드 드라이브를 파기할 필요가 없습니다.

하드 드라이브를 파기하고 싶지도 않고 100달러 상당의 스마트 카드 하드웨어를 구입하는 것도 부담스럽다면 개인 키를 임시로 저장해야 할 때마다 하드 드라이브 대신 RAM 디스크를 사용하십시오. 작업 완료 후 컴퓨터를 다시 부팅하면 장비를 제대로 갖춘 해커 외에는 비밀 내용에 액세스할 수 없게 됩니다.

개발 팀 보호

서명 연기는 완벽하지 않습니다. 팀에서는 개발 중에 자체 어셈블리를 테스트하기 위해 하나 이상의 공개 키에 대한 강력한 이름 확인 기능을 해제해야 하므로, 확인되지 않은 강력한 이름이 있다는 사실만으로 어셈블리를 신뢰해서는 안 됩니다. 또한 공격자가 공개 키를 알게 되면 마치 사용자가 자신의 어셈블리를 서명 연기하듯이 악의적인 어셈블리를 손쉽게 서명 연기할 수 있습니다. 공개 키는 빌드하는 강력한 이름의 어셈블리마다 메타데이터로 포함되어 있기 때문에 공격자가 공개 키를 알아내는 것은 쉬운 일입니다.

이 문제에 대해서는 팀 구성원에게 반드시 교육해야 합니다. .NET 보안 정책에서 어셈블리를 식별해야 하는 경우 확인되지 않은 강력한 이름은 앞에서 설명한 대로 공격자가 트로이 목마로 쉽게 만들 수 있으므로 사용하지 말아야 합니다. 개인 키를 팀 구성원만 알고 있으며 모든 어셈블리의 서명에 사용되는 내부에서 발급된 임시 코드 서명 인증서(예전의 Authenticode와 유사)를 사용하는 것이 대안이 될 수도 있습니다. 이 경우 개발 및 테스트 도중의 정책에서는 강력한 이름 증거 대신 게시자 증거를 사용하여 어셈블리를 식별합니다.

결론

강력한 이름은 매우 뛰어난 기능이지만 그에 따른 막중한 책임이 따릅니다. CLR에서 강력한 이름을 기준으로 강력한 보안을 유지할 수 있는 기능은 개인 키를 얼마나 잘 보호하는지에 달려 있습니다. 그러므로, 개인 키가 노출되지 않도록 보호하십시오.


[이 자료는 MSDN Library에서 가져왔습니다.]

".NET" 카테고리의 다른 글
  • 닷넷 리모팅 서비스에 대한 이해2 (iis를 호스트로... (0)2007/01/10
  • 닷넷 리모팅 서비스에 대한 이해 (0)2007/01/10
  • .NET Framework의 강력한 이름 및 보안 (0)2007/01/09
  • 닷넷프레임 워크의 이해 (0)2006/11/24
  • .NET Execution Model (0)2006/07/30
2007/01/09 10:28 2007/01/09 10:28
Posted by webdizen
Tags .NET Framework, 강력한 이름, 보안
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/2566

Leave your greetings.

[로그인][오픈아이디란?]

«Prev  1  Next»

RSS HanRSS
Blog Image
webdizen
이 곳은 컴퓨터에 대해 연구하고, 공유하고, 소통하기 위한 연구실입니다. 개인적으로는 OLAP, Data Mining, Semantic Web, Data Modeling에 대해서 연구하고 있습니다.

Categories

전체 (2998)
Webdizen (134)
Life (6)
Diary (16)
Blog (9)
IDEA (1)
Travel (10)
Book (14)
Photo (7)
Movie (7)
Music (13)
Leisure Sports (10)
Funny (5)
Hardware (119)
Software (120)
Windows (5)
Unix & Linux (119)
Installation (4)
Kernel (10)
System (34)
Develop (22)
X-Window (0)
Applicaton (31)
Security (4)
Framework (2)
Hadoop (2)
Programming (805)
Algorithm & Data Structure (1)
Assembly (38)
UNIX/Linux C (95)
C++ (128)
STL (4)
Java (38)
Win32 API (92)
ATL/COM (44)
MFC (151)
.NET (26)
WCF/WPF (4)
C# (28)
Network Programming (17)
Database Programming (12)
OpenGL / DirectX (13)
Multimedia Programming (0)
Game Programming (21)
Parallel Distributed Progra... (0)
Reverse Engineering (0)
Debugging (9)
Python (1)
Ruby (1)
Ruby on Rails (1)
QT (4)
GTK (0)
JSP (0)
PHP (6)
ASP.NET (6)
ASP (3)
Development (28)
Useful Library (2)
Data Modeling (0)
Database (105)
Oracle (4)
MSSQL (41)
MySQL (2)
Data Warehouse (2)
Data Mining (3)
Network (66)
Web (78)
DHTML (4)
XHTML (1)
Javascript (1)
CSS (1)
AJAX (9)
XML (11)
Flex (1)
Silverlight (3)
Security (91)
DoS (1)
Kernel (10)
Scanning (3)
Sniffing (0)
Spoofing (4)
Overflow (28)
Web (11)
Shell (10)
Format String (14)
Window (2)
Embedded (70)
Multimedia (27)
Mobile (14)
Graphic (24)
Management (633)
Knowledge (581)
Hadoop (0)

Notice

  • 메타 블로그 사이트에 등록
  • 새해 맞이 블로그의 변화
  • 블로그 명칭 변경
  • 도메인(www.webdizen.net) 구...
  • TEXTCUBE 1.6.1로 업그레이드...

Tags

  • 시스템 관리자
  • ATOM
  • 형상화
  • 준비물
  • 저장 프로시저
  • Mobile
  • 프로세스
  • Thread 종료
  • Assembly
  • 함수 포인터
  • 리소스
  • renfe
  • 네트워크 라우터
  • PIMPLs
  • 연적지
  • Addin
  • Programming
  • race condition
  • TPC-D
  • FlashWindow

Recent Articles

  • ASCII Code의 CRLF 제거 방법.
  • Hadoop 에서 c++ API 이용시....
  • Ubuntu Linux에서 Hadoop 구....
  • 내 심장을 한껏 뛰게한 "국가....
  • 스타 스키마 데이터베이스 설....

Recent Comments

  • ■ 온라인카지노 ▶ http://L....
    asdf 11/21
  • 그리고 혹시 해외여행자보험....
    kim 11/05
  • ★★실제 바다게임장과 똑같....
    asdf 11/04
  • sbsyama.co.to← 짱5000만당....
    asdf 11/04
  • ♡KicaZ??o(???) 바카라사....
    fdsf3fass 11/03

Recent Trackbacks

  • 파일 열기/저장하기 CFileDialog.
    은마군의 나태블록 02/11
  • World IT Show 2008.
    상우 :: Oranzie's BLOG 2008
  • cvs서버 설치하기.
    3인3색 2008
  • 속속 공개되는 Google Chart....
    PHP와 Web 2.0 2007
  • 마방진을 구하는 프로그램.
    Oranzie's BLOG 3 2007

Archive

  • 2009/09 (3)
  • 2009/08 (1)
  • 2009/03 (1)
  • 2009/02 (9)
  • 2009/01 (13)

Calendar

«   2009/11   »
일 월 화 수 목 금 토
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          

Bookmarks

    • Administration
      • IIS.NET
      • NTFAQ
      • OS의 모든 것
      • 리눅스포털
    • Database
      • SQL Server Central
      • SQL Team
    • Development
      • .NET Heaven
      • ASP Alliance
      • ASP.NET 2.0
      • Bullog.net
      • C# Corner
      • C++ (C PlusPlus.com)
      • C++ Reference
      • CodeGuru
      • CodePlex
      • DebugLab
      • Dev Articles
      • Devpia
      • DotNet Junkies
      • DotNet Zone
      • Driver Online
      • GOSU.NET
      • HOONS 닷넷
      • Joinc 팀블로그
      • KOSR
      • MSDN Home Page
      • OSR Online
      • Sky.ph - 개발자 커뮤니...
      • TAEYO.NET
      • The Code Project
      • WindowsClient.net
      • 김상욱의 개발자 Side
      • 조인시 위키
    • Human Networks
      • belief21c's e-space
      • I think I can
      • Invisible Rover's Blog :D
      • Rodman®
      • ■ Feel So Good~! ■
      • 까만 나비
      • 나를 가꾸는 시간.
      • 나만의 즐거움~~!
      • 단녕
      • 상우 :: Oranzie's BLOG
    • Information Technology
      • Microsoft TechNet
      • 지디넷코리아 - 글로벌...
    • Security
      • FoundStone
      • milw0rm
      • NewOrder
      • OpenRCE
      • Phrack.org
      • Reverse Engineering b1...
      • Reverse Engineering Team
      • RootKit
      • SecurityFocus
      • SecurityXploded by Nag...
      • Wow Hacker
      • Zone-H
Textcube
Louice Studio Inc.
Powered by Textcube. Original designed by Tistory.