Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)

음... 요즘 devpia에서 Q&A를 하다 보니, 다소 기초적인 내용들을 올리게 되는군요. ^^

그나저나, 너무 빈번한 질문들에 대해서 매번 타자 치기도 그렇고, 간단한 말로 끝내는 것도 질문한 분께 예의가 아닌 것 같아서, 아예 이런 식으로 제 홈피에 정리해 봅니다.

암튼, 아래와 같은 오류가 나는 경우가 있습니다. 이런 부분은 사실 .NET 보안과 Windows의 보안이 다르기 때문에 발생하게 됩니다.


'/KR_KORITECH_03_31' 응용 프로그램에 서버 오류가 있습니다.


레지스트리 키 HKEY_CLASSES_ROOT\... 에 대한 액세스가 거부되었습니다.

설명: 현재 웹 요청을 실행하는 동안 처리되지 않은 예외가 발생했습니다. 스택 추적을 검토하여 발생한 오류 및 코드에서 오류가 발생한 위치에 대한 자세한 정보를 확인하십시오.

예외 정보: System.UnauthorizedAccessException: 레지스트리 키 HKEY_CLASSES_ROOT\... 에 대한 액세스가 거부되었습니다.

ASP.NET에는 요청한 리소스에 액세스할 권한이 없습니다. ASP.NET 요청 ID에 리소스 액세스 권한을 부여하십시오. ASP.NET에는 응용 프로그램이 가장하지 않을 때 사용되는 기본 프로세스 ID(일반적으로 IIS 5에서는 {MACHINE}\ASPNET, IIS 6에서는 Network Service)가 있습니다. 응용 프로그램이 <identity impersonate="true"/>를 통해 가장하고 있는 경우에는 ID가 익명 사용자(일반적으로 IUSR_MACHINENAME) 또는 인증된 요청 사용자가 됩니다.

파일에 대한 쓰기 권한을 ASP.NET에 부여하려면 탐색기에서 파일을 마우스 오른쪽 단추로 클릭하고 [속성]을 선택한 다음 [보안] 탭을 선택합니다. [추가]를 클릭하여 적절한 사용자나 그룹을 추가합니다. ASP.NET 계정을 강조 표시한 다음 원하는 액세스를 선택합니다.

소스 오류:

줄 200:			string chk5="";
줄 201:
줄 202:			using (....FileUpload fileUpload = new ....FileUpload())
줄 203:			{
줄 204:

소스 파일: c:\inetpub\wwwroot\kr_koritech_03_31\admin\pr\pr_news_write.aspx.cs    줄: 202

스택 추적:

[UnauthorizedAccessException: 레지스트리 키 HKEY_CLASSES_ROOT\... 에 대한 액세스가 거부되었습니다.]
   Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str) +74
   Microsoft.Win32.RegistryKey.CreateSubKey(String subkey) +503
   System.Runtime.InteropServices.RegistrationServices.RegisterManagedType(Type type, String strAsmName, String strAsmVersion, String strAsmCodeBase, String strRuntimeVersion) +216
   System.Runtime.InteropServices.RegistrationServices.RegisterAssembly(Assembly assembly, AssemblyRegistrationFlags flags) +258
   System.EnterpriseServices.RegistrationDriver.ClassicRegistration(Assembly asm)

[RegistrationException: 'TestModule.NET, Version=3.0.3.0, Culture=neutral, PublicKeyToken=d71d611ccd9cc3c0' 어셈블리를 등록하지 못했습니다.]
   System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +264
   System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +877
   System.EnterpriseServices.RegistrationHelperTx.InstallAssemblyFromConfig(RegistrationConfig& regConfig, Object sync)
   System.EnterpriseServices.RegistrationHelper.TryTransactedInstall(RegistrationConfig regConfig)
   System.EnterpriseServices.RegistrationHelper.InstallAssemblyFromConfig(RegistrationConfig& regConfig)
   System.EnterpriseServices.RegistrationHelper.InstallAssembly(String assembly, String& application, String partition, String& tlb, InstallationFlags installFlags)
   System.EnterpriseServices.RegistrationHelper.InstallAssembly(String assembly, String& application, String& tlb, InstallationFlags installFlags)
   System.EnterpriseServices.RegistrationHelper.System.EnterpriseServices.Thunk.IThunkInstallation.DefaultInstall(String asm)
   System.EnterpriseServices.Thunk.Proxy.RegisterAssembly(Assembly assembly)
   System.EnterpriseServices.Thunk.Proxy.LazyRegister(Guid id, Type serverType, Boolean checkCache)
   System.EnterpriseServices.Thunk.Proxy.CoCreateObject(Type serverType, Boolean bQuerySCInfo, Boolean& bIsAnotherProcess, String& uri)
   System.EnterpriseServices.ServicedComponentProxyAttribute.CreateInstance(Type serverType)
   System.Runtime.Remoting.Activation.ActivationServices.IsCurrentContextOK(Type serverType, Object[] props, Boolean bNewObj) +74
   koritech.admin.pr.pr_news_write.InsertData() in c:\inetpub\wwwroot\kr_koritech_03_31\admin\pr\pr_news_write.aspx.cs:202
   koritech.admin.pr.pr_news_write.ImageButton1_Click(Object sender, ImageClickEventArgs e) in c:\inetpub\wwwroot\kr_koritech_03_31\admin\pr\pr_news_write.aspx.cs:340
   System.Web.UI.WebControls.ImageButton.OnClick(ImageClickEventArgs e)
   System.Web.UI.WebControls.ImageButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
   System.Web.UI.Page.ProcessRequestMain()


버전 정보: Microsoft .NET Framework 버전:1.1.4322.2032; ASP.NET 버전:1.1.4322.2032 SP.NET Version:1.1.4322.2300

위의 오류 화면은, 한마디로 .NET COM+ 개체가 레지스트리에 자신을 등록해야 하는데 해당 레지스트리 키를 만들 수 있는 권한이 없다는 것입니다. 아시는 것처럼, 일반적으로 Registry는 상당히 중요한 시스템 리소스입니다. 아마도 이 글 읽으시는 분들 중에는 레지스트리를 잘못 편집했다가 시스템이 엉망이 된 경우도 있으실 텐데요. 따라서, 레지스트리를 함부로 편집하지 못하도록 레지스트리 자체에도 Win32 보안이 적용되어져 있습니다.

실제로 COM+ 개체의 경우, 일반적으로 HKEY_CLASSES_ROOT 하위에 자신을 등록하려고 하는데요. 아래의 그림에서 보는 것처럼, 보안이 제법 강력하게 적용되어져 있습니다.

HKEY_CLASSES_ROOT 보안

살펴 보시면, "쓰기 권한"은 "Administrators", "SYSTEM"만이 가능하며, 나머지는 읽기 권한일 뿐입니다.

자, 이제 문제가 분명해 진것 같습니다. "액세스가 거부되었습니다."가 나오는 원인은 ASP.NET 작업자 프로세스가 (등록 코드를 실행하는 스레드까지도) "Administrators", "SYSTEM"에 속해 있지 않기 때문에 발생하는 것입니다.

그렇다면, 답은 2가지가 있을 수 있겠습니다.
첫 번째, HKEY_CLASSES_ROOT 권한에 현재의 ASP.NET 작업자 프로세스의 계정을 추가하는 것입니다. 해당 계정은 "작업관리자" 등을 통해서 확인할 수 있지요. 대개의 경우, IIS 5.0에서는 "ASPNET" 계정이고, IIS 6.0에서는 "Network Service" 계정입니다. 따라서, 그에 맞게 regedit.exe를 이용해서 HKEY_CLASSES_ROOT에 권한을 추가해 주면 됩니다.

두 번째, ASP.NET 작업자 프로세스 계정을 "Administrators"에 가입된 계정이나, "SYSTEM" 계정으로 설정하는 것입니다. 이것 역시, IIS 버전에 따라 틀린데요. IIS 5.0에서는 .NET Framework이 설치되어져 있는 폴더의 Machine.config에서 processModel 요소를 수정해 주면 됩니다. 일례로, .NET 1.1의 경우에,

C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\CONFIG\machine.config

위의 파일을 열어서,

<processModel enable="true" ..... userName="SYSTEM" password="AutoGenerate" ... maxIoThreads="20" />

위와 같이 userName 속성에 적절한 계정을 넣어주시면 됩니다.

IIS 6.0의 경우에는 해당 웹 사이트 또는 가상 디렉토리가 Application Pool의 적용을 받기 때문에 해당 App Pool의 ID 탭에서 계정을 설정해 주시면 됩니다 다음과 같은 화면처럼.

Application Pool 계정 설정


첫 번째 방식과, 두 번째 방식의 장단점을 비교해 보면.

첫 번째의 레지스트리 키에 직접 보안이 낮은 계정을 추가하는 것은 오히려 보안 위험도를 높일 수가 있는 점이 있습니다. 물론, 두 번째의 설정은 오히려 더 보안 위험도가 높을 수 있는 것입니다. 레지스트리 하나 보호하려고 Front-End 단에서 (무작위) 사용자 코드 실행을 담당하는 Web Application의 권한을 높여주는 것이기 때문입니다. 즉, Web Application의 보안에 구멍이 뚫리기 시작하면, 레지스트리 하나 정도로 끝날 문제는 아니라는 거죠.

이런 문제로 인해, MS에서 제시하는 것은 Web Application을 구동하는 별도의 계정을 만들어서 적절한 권한만을 주는 것입니다. 하지만, 애플리케이션을 작성하다 보면, 도저히 일반 계정으로는 일일이 보안 설정을 다 못하는 경우가 있습니다. 일반 계정 하나 만들어 놓고, 그걸 가지고 필요한 보안 설정을 하다 보면, 결국 Administrator나 SYSTEM 계정과 권한이 비슷한 수위에 올라오게 되는 것인데요.

어쨌든, 선택은 여러분들 또는 그 위의 보안 담당자 및 운영자와 적절하게 상의를 하셔야 할 것이고요.

저에게 물으신다면... 아래와 같이 답하고 싶습니다.
만약, 위와 같이 COM+ 개체 하나 정도의 등록 때문이라면, 첫 번째 및 두 번째 방식을 모두 선택하지 않을 것입니다. 왜냐면, 결국 COM+ 등록은 레지스트리에 최초 한 번만 씌여지면 그만이므로, 한 번의 등록시에만 권한이 있는 사용자로 로그인해서 등록을 시키고, 이후에는 다시 "Network Service" 등의 계정으로 구동을 시킬 것입니다.
[연관 글]






[최초 등록일: ]
[최종 수정일: 6/24/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 16  17  18  19  20  21  22  23  24  25  26  27  28  29  [30]  ...
NoWriterDateCnt.TitleFile(s)
13187정성태12/8/202215290개발 환경 구성: 654. openssl - CA로부터 인증받은 새로운 인증서를 생성하는 방법 (2)
13186정성태12/6/202213066오류 유형: 831. The framework 'Microsoft.AspNetCore.App', version '...' was not found.
13185정성태12/6/202214039개발 환경 구성: 653. Windows 환경에서의 Hello World x64 어셈블리 예제 (NASM 버전)
13184정성태12/5/202212629개발 환경 구성: 652. ml64.exe와 link.exe x64 실행 환경 구성 [1]
13183정성태12/4/202212456오류 유형: 830. MASM + CRT 함수를 사용하는 경우 발생하는 컴파일 오류 정리 [1]
13182정성태12/4/202214255Windows: 217. Windows 환경에서의 Hello World x64 어셈블리 예제 (MASM 버전)
13181정성태12/3/202212776Linux: 54. 리눅스/WSL - hello world 어셈블리 코드 x86/x64 (nasm)
13180정성태12/2/202213563.NET Framework: 2074. C# - 스택 메모리에 대한 여유 공간 확인하는 방법파일 다운로드1
13179정성태12/2/202212296Windows: 216. Windows 11 - 22H2 업데이트 이후 Terminal 대신 cmd 창이 뜨는 경우
13178정성태12/1/202213384Windows: 215. Win32 API 금지된 함수 - IsBadXxxPtr 유의 함수들이 안전하지 않은 이유파일 다운로드1
13177정성태11/30/202213963오류 유형: 829. uwsgi 설치 시 fatal error: Python.h: No such file or directory
13176정성태11/29/202211511오류 유형: 828. gunicorn - ModuleNotFoundError: No module named 'flask'
13175정성태11/29/202215816오류 유형: 827. Python - ImportError: cannot import name 'html5lib' from 'pip._vendor'
13174정성태11/28/202212525.NET Framework: 2073. C# - VMMap처럼 스택 메모리의 reserve/guard/commit 상태 출력파일 다운로드1
13173정성태11/27/202213448.NET Framework: 2072. 닷넷 응용 프로그램의 스레드 스택 크기 변경
13172정성태11/25/202212946.NET Framework: 2071. 닷넷에서 ESP/RSP 레지스터 값을 구하는 방법파일 다운로드1
13171정성태11/25/202212476Windows: 214. 윈도우 - 스레드 스택의 "red zone"
13170정성태11/24/202213358Windows: 213. 윈도우 - 싱글 스레드는 컨텍스트 스위칭이 없을까요?
13169정성태11/23/202214670Windows: 212. 윈도우의 Protected Process (Light) 보안 [1]파일 다운로드2
13168정성태11/22/202212561제니퍼 .NET: 31. 제니퍼 닷넷 적용 사례 (9) - DB 서비스에 부하가 걸렸다?!
13167정성태11/21/202213033.NET Framework: 2070. .NET 7 - Console.ReadKey와 리눅스의 터미널 타입
13166정성태11/20/202212950개발 환경 구성: 651. Windows 사용자 경험으로 WSL 환경에 dotnet 런타임/SDK 설치 방법
13165정성태11/18/202211990개발 환경 구성: 650. Azure - "scm" 프로세스와 엮인 서비스 모음
13164정성태11/18/202213910개발 환경 구성: 649. Azure - 비주얼 스튜디오를 이용한 AppService 원격 디버그 방법
13163정성태11/17/202214239개발 환경 구성: 648. 비주얼 스튜디오에서 안드로이드 기기 인식하는 방법
13162정성태11/15/202215723.NET Framework: 2069. .NET 7 - AOT(ahead-of-time) 컴파일 [1]
... 16  17  18  19  20  21  22  23  24  25  26  27  28  29  [30]  ...