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)
13145정성태10/21/20226781오류 유형: 822. db2 - Password validation for user db2inst1 failed with rc = -2146500508
13144정성태10/20/20226624.NET Framework: 2059. ClrMD를 이용해 윈도우 환경의 메모리 덤프로부터 닷넷 모듈을 추출하는 방법파일 다운로드1
13143정성태10/19/20227279오류 유형: 821. windbg/sos - Error code - 0x000021BE
13142정성태10/18/20227528도서: 시작하세요! C# 12 프로그래밍
13141정성태10/17/20227951.NET Framework: 2058. [in,out] 배열을 C#에서 C/C++로 넘기는 방법 - 세 번째 이야기파일 다운로드1
13140정성태10/11/20227188C/C++: 159. C/C++ - 리눅스 환경에서 u16string 문자열을 출력하는 방법 [2]
13139정성태10/9/20226847.NET Framework: 2057. 리눅스 환경의 .NET Core 3/5+ 메모리 덤프로부터 모든 닷넷 모듈을 추출하는 방법파일 다운로드1
13138정성태10/8/20228207.NET Framework: 2056. C# - await 비동기 호출을 기대한 메서드가 동기로 호출되었을 때의 부작용 [1]
13137정성태10/8/20226500.NET Framework: 2055. 리눅스 환경의 .NET Core 3/5+ 메모리 덤프로부터 닷넷 모듈을 추출하는 방법
13136정성태10/7/20227099.NET Framework: 2054. .NET Core/5+ SDK 설치 없이 dotnet-dump 사용하는 방법
13135정성태10/5/20227389.NET Framework: 2053. 리눅스 환경의 .NET Core 3/5+ 메모리 덤프를 분석하는 방법 - 두 번째 이야기
13134정성태10/4/20225866오류 유형: 820. There is a problem with AMD Radeon RX 5600 XT device. For more information, search for 'graphics device driver error code 31'
13133정성태10/4/20226364Windows: 211. Windows - (commit이 아닌) reserved 메모리 사용량 확인 방법 [1]
13132정성태10/3/20226307스크립트: 42. 파이썬 - latexify-py 패키지 소개 - 함수를 mathjax 식으로 표현
13131정성태10/3/20229300.NET Framework: 2052. C# - Windows Forms의 데이터 바인딩 지원(DataBinding, DataSource) [2]파일 다운로드1
13130정성태9/28/20225992.NET Framework: 2051. .NET Core/5+ - 에러 로깅을 위한 Middleware가 동작하지 않는 경우파일 다운로드1
13129정성태9/27/20226230.NET Framework: 2050. .NET Core를 IIS에서 호스팅하는 경우 .NET Framework CLR이 함께 로드되는 환경
13128정성태9/23/20228969C/C++: 158. Visual C++ - IDL 구문 중 "unsigned long"을 인식하지 못하는 #import파일 다운로드1
13127정성태9/22/20227415Windows: 210. WSL에 systemd 도입
13126정성태9/15/20228005.NET Framework: 2049. C# 11 - 정적 메서드에 대한 delegate 처리 시 cache 적용
13125정성태9/14/20228232.NET Framework: 2048. C# 11 - 구조체 필드의 자동 초기화(auto-default structs)
13124정성태9/13/20227993.NET Framework: 2047. Golang, Python, C#에서의 CRC32 사용
13123정성태9/8/20228309.NET Framework: 2046. C# 11 - 멤버(속성/필드)에 지정할 수 있는 required 예약어 추가
13122정성태8/26/20228460.NET Framework: 2045. C# 11 - 메서드 매개 변수에 대한 nameof 지원
13121정성태8/23/20226198C/C++: 157. Golang - 구조체의 slice 필드를 Reflection을 이용해 변경하는 방법
13120정성태8/19/20227907Windows: 209. Windows NT Service에서 UI를 다루는 방법 [3]
... 16  17  18  19  20  [21]  22  23  24  25  26  27  28  29  30  ...