SQL Server 2000 Desktop Engine(MSDE 2000)을 설치할 때 강력한 SA 암호를 지정하는 방법

기술 자료 번역 기술 자료 번역
기술 자료: 814463 - 이 문서가 적용되는 제품 보기.
모두 확대 | 모두 축소

요약

이 문서에서는 SQL Server Desktop Engine(MSDE 2000)을 설치할 때 강력한 sa 암호를 지정하는 방법을 설명합니다.

추가 정보

SQL Server 2000 Desktop Engine(MSDE 2000) 인스턴스를 설치하는 동안 sa 계정에 강력한 암호를 지정해야 합니다. 인스턴스에서 Windows 인증 모드를 사용하는 경우에도 이렇게 해야 합니다. Windows 인증 모드를 실행할 때는 사용자가 sa 계정을 사용할 수 없지만 인스턴스를 나중에 혼합 모드로 전환할 수 있으며 이때 sa 계정이 활성 로그인이 됩니다.

MSDE 2000을 혼합 모드로 전환할 때 sa 계정의 암호가 Null이거나 비어 있거나 간단하거나 잘 알려져 있을 경우 권한이 없는 사용자가 MSDE 인스턴스를 액세스할 수 있습니다. sa 계정은 삭제할 수 없으며 항상 무단 액세스를 제한하기 위해 강력한 암호로 보호해야 합니다. sa 계정을 사용하여 MSDE 2000의 인스턴스에 액세스하는 모든 사용자는 MSDE 인스턴스에 대해 모든 권한을 가지고 MSDE 서비스 계정이 소유한 모든 리소스에 액세스할 수 있습니다. 기본적으로 MSDE 서비스 계정은 기본 제공되는 LocalSystem 보안 계정입니다.

강력한 암호에 대한 자세한 내용은 다음 Microsoft 웹 사이트를 방문하십시오.

보안 규칙(영문)

사용자 지정 응용 프로그램 코드를 사용하여 MSDE를 설치할 수 있습니다. 응용 프로그램 코드는 sa 암호 설정을 위해 다음 두 방법 중 하나를 사용해야 합니다.
  • 혼합 모드에서 MSDE를 설치하고 sa 계정을 사용하려는 경우 사용자로부터 sa 계정에 대한 강력한 암호를 요구합니다. MSDE 설치에서 해당 암호를 사용합니다.
  • sa 계정을 사용하지 않을 경우 임의의 문자열을 생성한 다음 해당 문자열을 MSDE 설치 프로그램에 sa 암호로 전달합니다.

보안을 강화하려면 설치할 때 지정된 sa 암호를 Setup.ini 파일에 매개 변수로 또는 명령(.cmd) 파일에 명령 프롬프트 스위치로 하드 코딩하지 않아야 합니다. 또한 MSI 파일 또는 암호가 일반 텍스트로 노출될 수 있는 기타 방법에서 속성으로 포함하지 않아야 합니다. 암호는 런타임에 응용 프로그램 설치 프로그램에서 동적으로 생성해야 하며 다음 방법 중 하나를 사용하여 MSDE 설치 프로세스에 전달해야 합니다.
  • 응용 프로그램 설치 코드에서 MSDE setup.exe를 실행하고 인수에 SAPWD 값을 지정합니다.

    예를 들어 .NET Framework Process 클래스를 사용하여 설치 프로그램을 실행한 다음 ProcessStartInfo Arguments 속성에 SAPWD를 지정하거나 Win32 CreateProcess 함수를 사용하여 설치 프로그램을 실행한 다음 lpCommandLine 매개 변수에 SAPWD를 지정합니다.


    SAPWD 명령줄 매개 변수에 대한 자세한 내용은 Microsoft 기술 자료의 다음 문서를 참조하십시오.
    810826 INF: MSDE 서비스 팩 3 설치 프로그램의 새 스위치
  • 사용자 지정 Windows Installer 기반 설치에서 MSDE 병합 모듈을 사용할 때 사용자 지정 작업을 수행하여 강력한 암호를 전달합니다.

참고 MSDE 2000 설치 동안 Windows 인증 모드를 사용하여 sa 계정에 대한 암호를 설정할 수 없습니다. 이 시나리오에서는 설치가 완료된 후에 암호를 설정해야 합니다. 최신 서비스 팩을 사용하여 MSDE 2000을 설치하는 것이 좋습니다.

임의의 암호를 생성하는 가장 좋은 방법은 다음과 같은 Crypto API 함수를 사용하는 것입니다.
  • CryptAcquireContext
  • CryptGenRandom
  • CryptCreateHash
  • CryptHashData

기본 코드를 사용하는 경우 CryptReleaseContext를 사용합니다.

관리 코드를 사용하는 경우 System.Security.Cryptography.RNGCryptoServiceProvider를 사용하여 임의의 인코딩 문자열을 얻은 다음 System.Security.Cryptography.SHA1 클래스의 ComputeHash 메서드를 사용하여 반환된 값을 해싱합니다. 임의의 문자열은 7과 20자 사이의 가변 길이어야 합니다.

sa 암호를 잊었거나 sa 암호가 무엇인지 모르고 인스턴스를 혼합 모드로 변환하는 경우 이전 암호를 알지 못해도 sysadmin 고정 서버 역할의 구성원이 sa 암호를 재설정할 수 있습니다. 기본적으로 로컬 Administrators 그룹의 구성원인 사용자는 모두 sysadmin 역할의 구성원입니다. sysadmin 역할의 구성원은 Windows 인증 모드에서 혼합 모드로, 또는 그 반대로 MSDE 인스턴스를 변경하고 sa 암호를 변경할 수 있습니다. 따라서 보안을 위해 sysadmin 역할에서 Administrators 그룹을 제거할 수 있습니다.

sysadmin 역할에서 Administrators 그룹을 제거하는 방법에 대한 자세한 내용은 Microsoft 기술 자료의 다음 문서를 참조하십시오.
263712 INF: Windows NT 관리자가 클러스터된 SQL Server를 관리하지 못하게 제한하는 방법


sa 계정 암호 변경에 대한 자세한 내용은 Microsoft 기술 자료의 다음 문서를 참조하십시오.
322336 MSDE 시스템 관리자 암호를 확인하고 변경하는 방법

참고 이 문서에 설명되어 있는 설치 동안 sa 암호를 변경하는 방법은 MSDE의 새 설치에만 적용됩니다.

다음 단계에서는 예제 코드를 사용하여 임의의 sa 암호를 생성한 다음 MSDE 설치를 시작합니다.

Microsoft Visual C++ .NET 사용

  1. 시작을 누르고 모든 프로그램, Microsoft Visual Studio .NET, Visual Studio .NET 도구를 차례로 가리킨 다음 Visual Studio .NET 명령 프롬프트를 누릅니다.
  2. 메모장을 엽니다.
  3. 메모장에 아래 코드를 붙여 넣습니다.
    #pragma once
    
    #define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers.
    #define UNICODE
    #include <stdio.h>
    #include <windows.h>
    #include <wincrypt.h>
    
    #ifdef UNICODE
    	#define STRNCPY	wcsncpy
    #else
    	#define STRNCPY strncpy
    #endif
    
    #include <atlenc.h>
    
    #define SAPWDSWITCH _T("SAPWD=")
    #define INSTANCENAME _T("INSTANCENAME=MSDETEST")
    
    
    BOOL GenPwd(TCHAR*, int);
    void DisplayError (DWORD);
    
    int main(void)
    {	
    	//Generate random length for password, between 7 and 20 characters.
    	int nPwdLen = ((rand() % 20) + 7) + 1;	//Extra character for null terminator
    	TCHAR* pPwd = new TCHAR[nPwdLen];
    	UINT uRes = 0;
    	DWORD dwRes = 0;
    	if (!GenPwd(pPwd, nPwdLen))
    	{
    		//Failed to generate a password, log the error and return failure.
    		dwRes = GetLastError();
    		DisplayError(dwRes);
    
    		return dwRes;
    	}
    
    
            STARTUPINFO si;
            PROCESS_INFORMATION pi;
    
            ZeroMemory( &si, sizeof(si) );
            si.cb = sizeof(si);
            ZeroMemory( &pi, sizeof(pi) );
    
    	//Allocate a string for the command line.
    	LPTSTR lpCommand = new TCHAR[nPwdLen + _tcslen(INSTANCENAME) + _tcslen(SAPWDSWITCH) + 2];
    
    	_stprintf(lpCommand, _T("%s %s%s"),INSTANCENAME,  SAPWDSWITCH, pPwd);
    // Specify the complete path of Setup.exe.
    	if (!CreateProcess(_T("setup.exe"), lpCommand, NULL, NULL, FALSE, 
    				0, NULL, NULL, &si, &pi))
    	{
    		dwRes = GetLastError();
    		DisplayError(dwRes);
    	}
    	return 0;
    }
    
    
    //Generates a Random string of length nLen - 1.  Buffer ppwd must allocate an extra character for null terminator.
    //Returns TRUE if successful, FALSE if fails.
    //Extended error information can be obtained from GetLastError().
    BOOL GenPwd(TCHAR* ppwd, int nLen)
    {
    	BOOL bResult = FALSE;	//assume failure
    	HCRYPTPROV hProv = NULL;
    	HCRYPTHASH hHash = NULL;
    	
    	//Storage for random string 4 times longer than the resulting password.
    	DWORD dwBufSize = nLen*4;
    	DWORD dwSize = Base64EncodeGetRequiredLength((int)dwBufSize);
    	LPSTR pEncodedString = NULL;
    	LPBYTE pRandomBuf = NULL;
    	TCHAR* pTRandomPwd = NULL;
    	
    	try
    	{
    		pEncodedString = new char[dwSize];
    		pRandomBuf = new BYTE[dwBufSize];
    		
    		// Try to acquire context to Crypto provider.
    		if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT))
    		{
    			if (GetLastError() == NTE_BAD_KEYSET) //Test for non-existent keyset
    			{
    				if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_NEWKEYSET))
    					throw(GetLastError());
    			}
    			else
    				throw(GetLastError());
    		}
    
    		//Generate a random sequence.
    		if (!CryptGenRandom(hProv, dwBufSize, pRandomBuf))
    		{
    			throw(GetLastError());
    		}
    
    		//Get a handle to a hash, then hash the random stream.
    		if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
    		{
    			throw(GetLastError());
    		}
    
    		if (!CryptHashData(hHash, pRandomBuf, dwBufSize, NULL))
    		{
    			throw(GetLastError());
    		}
    	
    		//Destroy the hash object.
    		CryptDestroyHash(hHash);
    		//Release Provider context
    		CryptReleaseContext(hProv, 0);	
    	
    		//Encode the hash value to base64.
    		if (!Base64Encode(pRandomBuf, dwBufSize, pEncodedString, (int*) &dwSize, 0))
    		{
    			throw(GetLastError());
    		}
    	
    		//Determine how many tchars you need to convert string to base64.
    		int nTchars = (int) strlen(pEncodedString);
    	
    		pTRandomPwd = new TCHAR[nTchars];
    	
    #ifdef UNICODE
    		if (MultiByteToWideChar(CP_UTF8, 0, pEncodedString, nTchars, pTRandomPwd, nTchars) == 0)
    		{
    			throw(GetLastError());
    		}
    #else
    		STRNCPY( pTRandomPwd, pEncodedString, nLen);
    #endif
    
    		//Copy the first x characters of random string to output buffer.
    		STRNCPY(ppwd, pTRandomPwd, nLen);
    		//Add null terminator to ppwd string.
    		ppwd[nLen] = _T('\0');
    
    		bResult = TRUE;
    
    	}
    	catch (DWORD)
    	{
    		//Set return value to false.
    		bResult = FALSE;
    	}
    	catch (...)
    	{
    		//Unknown error, throw. 
    		throw;
    	}
    
    	//Clean up memory.
    	if (pRandomBuf)
    	{
    		delete pRandomBuf;
    		pRandomBuf = NULL;
    	}
    
    	if (pEncodedString)
    	{
    		delete pEncodedString;
    		pEncodedString = NULL;
    	}
    
    	if (pTRandomPwd)
    	{
    		delete pTRandomPwd;
    		pTRandomPwd = NULL;
    	}
    
    	return bResult;
    }
    
    
    void DisplayError (DWORD dwError)
    {
    	//Resolve the error code to a message string.
    	LPCTSTR MessageBuffer;
    	DWORD dwBufferLength = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
    		NULL, // module to get message from (NULL == system)
    		dwError,
    		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.
    		(LPTSTR) &MessageBuffer,
    		0,
    		NULL
    		);
    
    	DWORD dwBytesWritten;
    	// Output message string on stderr.
    	WriteFile(
    		GetStdHandle(STD_ERROR_HANDLE),
    		MessageBuffer,
    		dwBufferLength,
    		&dwBytesWritten,
    		NULL
    		);
    }
    
  4. 파일을 StrongSA.cpp로 저장합니다.
  5. 명령 프롬프트에서 다음 명령을 입력하여 코드를 컴파일합니다.

    cl strongSA.cpp
  6. 명령 프롬프트에서 다음 명령을 입력하여 코드를 실행합니다.

    strongSA.exe

Microsoft C#.NET 사용

  1. Visual Studio .NET에서 새 Visual C# 콘솔 응용 프로그램 프로젝트를 만듭니다.
  2. Main 함수를 포함하고 있는 클래스 파일에 다음 코드를 붙여 넣습니다.

    코드가 파일에 있는 모든 기존 코드를 바꾸는지 확인합니다.
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Resources;
    using Microsoft.Win32;
    using System.Security.Cryptography;
    
    
    class InstMSDE
    {
    	static void Main(string[] args)
    	{
    		try
    		{   
    			
    
    			// Generate random password.
    			RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    			byte[] encodedSeed = new byte[512];
    			rng.GetBytes(encodedSeed);
    			SHA1 sha1 = SHA1.Create();
    			byte[] hashval = sha1.ComputeHash(encodedSeed);
    			String base64HashVal = Convert.ToBase64String(hashval);
    			// Trim "=" off the end.
    			base64HashVal = base64HashVal.TrimEnd('=');
    				
    			string msdeINI = "setup.ini";
    
    			// You have to set startInfo parameters values as appropriate for your installation.
    			ProcessStartInfo startInfo = new ProcessStartInfo();
    
    			// Setup.exe for MSDE sp3.
    			startInfo.FileName = "setup.exe"; 
    
    			// Pass the SA password to the setup program.
    			startInfo.Arguments = "/settings \"" + msdeINI + "\"" + " SAPWD=" + base64HashVal + " /qr+ "; 
    			startInfo.WindowStyle = ProcessWindowStyle.Normal;
    			// Substitute the workdir with complete path of installation folder. 
    			startInfo.WorkingDirectory = "c:\\Workingdir";
    				
    			Process.Start(startInfo);
    			
    			
    		}
    		catch (Exception e)
    		{
    			Console.WriteLine("Unable to execute program due to the following error: " + e.Message);
    			return;
    		}  
    	}
    }
    
  3. F5 키를 눌러 프로그램을 컴파일하고 실행합니다.

참조

사용자 지정 응용 프로그램 설치에 MSDE를 포함하는 방법에 대한 자세한 내용은 다음 Microsoft 웹 사이트를 방문하십시오.

사용자 지정 응용 프로그램의 설치 프로그램에 MSDE 2000 설치 프로그램 포함(영문)



Microsoft 제품 관련 기술 전문가들과 온라인으로 정보를 교환하시려면 Microsoft 뉴스 그룹에 참여하시기 바랍니다.

속성

기술 자료: 814463 - 마지막 검토: 2005년 7월 11일 월요일 - 수정: 1.3
본 문서의 정보는 다음의 제품에 적용됩니다.
  • Microsoft SQL Server 2000 Desktop Engine (Windows)
키워드:?
kbsetup kbsecurity kblogin kbauthentication kbsample kbguidelines kbcode kbinfo KB814463
더 이상 지원되지 않는 제품의 KB 내용에 대한 고지 사항
이 문서에서는 Microsoft에서 더 이상 지원하지 않는 제품에 대해 설명합니다. 따라서 이 문서는 "있는 그대로" 제공되며 업데이트되지 않습니다.

피드백 보내기

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com