DataSet 및 DataTable 보안 지침

이 글의 적용 대상:

  • .NET Framework(모든 버전)
  • .NET Core 이상
  • .NET 5 이상

DataSetDataTable 형식은 데이터 집합을 관리형 개체로 나타낼 수 있는 레거시 .NET 구성 요소입니다. 이러한 구성 요소는 원래 ADO.NET 인프라의 일부로 .NET Framework 1.0에서 도입되었습니다. 해당 목표는 관계형 데이터 집합에 대한 관리형 뷰를 제공하여 데이터의 기본 원본이 XML, SQL 또는 다른 기술인지를 추상화하는 것이었습니다.

최신 데이터 뷰 패러다임을 포함하는 ADO.NET에 대한 자세한 내용은 ADO.NET 설명서를 참조하세요.

XML에서 DataSet 또는 DataTable을 역직렬화하는 경우의 기본 제한 사항

지원되는 모든 버전의 .NET Framework, .NET Core 및 .NET에서 DataSetDataTable은 역직렬화된 데이터에 있을 수 있는 개체 유형에 대해 다음과 같은 제한을 적용합니다. 기본적으로 이 목록은 다음으로 제한됩니다.

  • 기본 형식 및 기본 형식과 동등한 형식: bool, char, sbyte, byte, short, ushort, int, uint, long, ulong, float, double, decimal, DateTime, DateTimeOffset, TimeSpan, string, Guid, SqlBinary, SqlBoolean, SqlByte, SqlBytes, SqlChars, SqlDateTime, SqlDecimal, SqlDouble, SqlGuid, SqlInt16, SqlInt32, SqlInt64, SqlMoney, SqlSingleSqlString.
  • 일반적으로 사용되는 비기본 형식: Type, UriBigInteger.
  • 일반적으로 사용되는 System.Drawing 형식: Color,, PointPointF, Rectangle, RectangleFSizeSizeF.
  • Enum 형식
  • 위 형식의 배열 및 목록입니다.

들어오는 XML 데이터에 이 목록에 없는 형식의 개체가 포함된 경우:

  • 다음 메시지 및 스택 추적을 사용하여 예외가 throw됩니다. 오류 메시지: System.InvalidOperationException : Type '<Type Name>, Version=<n.n.n.n>, Culture=<culture>, PublicKeyToken=<token value>'는 여기서 허용되지 않습니다. 스택 추적: at System.Data.TypeLimiter.EnsureTypeIsAllowed(Type type, TypeLimiter capturedLimiter) at System.Data.DataColumn.UpdateColumnType(Type type, StorageType typeCode) at System.Data.DataColumn.set_DataType(Type value)

  • deserialization 작업이 실패합니다.

XML을 기존 DataSet 또는 DataTable 인스턴스로 로드하는 경우 기존 열 정의도 고려됩니다. 테이블에 사용자 지정 형식의 열 정의가 이미 포함되어 있으면 XML 역직렬화 작업 기간 동안 해당 형식이 일시적으로 허용 목록에 추가됩니다.

참고

DataTable에 열을 추가하면 ReadXml는 XML에서 스키마를 읽지 않으며, 일치하는 스키마가 없으면 레코드에서도 읽지 않으므로 이 메서드를 사용하기 위해 모든 열을 직접 추가해야 합니다.

XmlReader xmlReader = GetXmlReader();

// Assume the XML blob contains data for type MyCustomClass.
// The following call to ReadXml fails because MyCustomClass isn't in the allowed types list.

DataTable table = new DataTable("MyDataTable");
table.ReadXml(xmlReader);

// However, the following call to ReadXml succeeds, since the DataTable instance
// already defines a column of type MyCustomClass.

DataTable table = new DataTable("MyDataTable");
table.Columns.Add("MyColumn", typeof(MyCustomClass));
table.ReadXml(xmlReader); // this call will succeed

개체 형식 제한은 XmlSerializer을 사용하여 DataSet 또는 DataTable의 인스턴스를 역직렬화하는 경우에도 적용됩니다. 그렇지만 BinaryFormatter를 사용하여 DataSet 또는 DataTable의 인스턴스를 역직렬화하는 경우에는 적용되지 않을 수 있습니다.

DataTable 인스턴스가 XML 역직렬화 API를 사용하지 않고 데이터베이스에서 직접 채워지는 경우와 같이 DataAdapter.Fill을 사용할 때는 개체 형식 제한이 적용되지 않습니다.

허용되는 형식 목록 확장

앱은 위에 나열된 기본 제공 형식 외에도 사용자 지정 형식을 포함하도록 허용되는 형식 목록을 확장할 수 있습니다. 허용되는 형식 목록을 확장하는 경우 변경 내용은 앱 내의 ‘모든’ DataSetDataTable 인스턴스에 영향을 줍니다. 기본 제공 허용되는 형식 목록에서는 형식을 제거할 수 없습니다.

구성을 통해 확장(.NET Framework 4.0 이상)

App.config를 사용하여 허용되는 형식 목록을 확장할 수 있습니다. 허용되는 형식 목록을 확장하려면 다음을 수행합니다.

  • <configSections> 요소를 사용하여 System.Data 구성 섹션에 대한 참조를 추가합니다.
  • <system.data.dataset.serialization>/<allowedTypes>를 사용하여 추가 형식을 지정합니다.

<add> 요소는 해당 어셈블리 정규화된 형식 이름을 사용하여 하나의 형식만 지정해야 합니다. 허용되는 형식 목록에 추가 형식을 추가하려면 여러 <add> 요소를 사용합니다.

다음 샘플에서는 사용자 지정 형식 Fabrikam.CustomType을 추가하여 허용되는 형식 목록을 확장하는 방법을 보여 줍니다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup name="system.data.dataset.serialization" type="System.Data.SerializationSettingsSectionGroup, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <section name="allowedTypes" type="System.Data.AllowedTypesSectionHandler, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
    </sectionGroup>
  </configSections>
  <system.data.dataset.serialization>
    <allowedTypes>
      <!-- <add type="assembly qualified type name" /> -->
      <add type="Fabrikam.CustomType, Fabrikam, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2b3831f2f2b744f7" />
      <!-- additional <add /> elements as needed -->
    </allowedTypes>
  </system.data.dataset.serialization>
</configuration>

형식의 정규화된 어셈블리 이름을 검색하려면 다음 코드에 설명된 대로 Type.AssemblyQualifiedName 속성을 사용합니다.

string assemblyQualifiedName = typeof(Fabrikam.CustomType).AssemblyQualifiedName;

구성을 통해 확장(.NET Framework 2.0 - 3.5)

앱이 .NET Framework 2.0 또는 3.5를 대상으로 하는 경우에도 위의 App.config 메커니즘을 사용하여 허용되는 형식 목록을 확장할 수 있습니다. 그러나 <configSections> 요소는 다음 코드와 같이 약간 다르게 표시됩니다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <!-- The below <sectionGroup> and <section> are specific to .NET Framework 2.0 and 3.5. -->
    <sectionGroup name="system.data.dataset.serialization" type="System.Data.SerializationSettingsSectionGroup, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <section name="allowedTypes" type="System.Data.AllowedTypesSectionHandler, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
    </sectionGroup>
  </configSections>
  <system.data.dataset.serialization>
    <allowedTypes>
      <!-- <add /> elements, as demonstrated in the .NET Framework 4.0 - 4.8 sample code above. -->
    </allowedTypes>
  </system.data.dataset.serialization>
</configuration>

프로그래밍 방식으로 확장(.NET Framework, .NET Core, .NET 5 이상)

다음 코드와 같이 AppDomain.SetData와 잘 알려진 키 System.Data.DataSetDefaultAllowedTypes를 사용하여 허용되는 형식 목록을 프로그래밍 방식으로 확장할 수도 있습니다.

Type[] extraAllowedTypes = new Type[]
{
    typeof(Fabrikam.CustomType),
    typeof(Contoso.AdditionalCustomType)
};

AppDomain.CurrentDomain.SetData("System.Data.DataSetDefaultAllowedTypes", extraAllowedTypes);

확장 메커니즘을 사용하는 경우 System.Data.DataSetDefaultAllowedTypes 키와 연결된 값은 형식 Type[]이어야 합니다.

.NET Framework 허용되는 형식 목록은 App.configAppDomain.SetData 둘 다를 사용하여 확장할 수 있습니다. 이 경우 DataSetDataTable은 해당 형식이 둘 중 한 목록에 있는 경우 개체를 데이터의 일부로 역직렬화할 수 있습니다.

감사 모드에서 앱 실행(.NET Framework)

.NET Framework에서 DataSetDataTable은 감사 모드 기능을 제공합니다. 감사 모드를 사용하도록 설정하면 DataSetDataTable은 들어오는 개체의 형식을 허용되는 형식 목록과 비교합니다. 그러나 형식이 허용되지 않는 개체가 표시되는 경우 예외가 throw되지 않습니다. 대신 DataSetDataTable은 연결된 TraceListener 인스턴스에 의심스러운 형식이 있음을 알리고 TraceListener가 이 정보를 기록할 수 있도록 허용합니다. 예외가 throw되지 않고 역직렬화 작업이 계속됩니다.

경고

“감사 모드”에서 앱을 실행하는 것은 테스트에 사용되는 임시 방책이어야 합니다. 감사 모드를 사용하도록 설정하면 DataSetDataTable은 형식 제한을 적용하지 않으므로 앱 내부에 보안 허점이 발생할 수 있습니다. 자세한 내용은 모든 형식 제한 제거신뢰할 수 없는 입력과 관련된 안전성 섹션을 참조하세요.

감사 모드는 App.config를 통해 사용하도록 설정할 수 있습니다.

  • <configSections> 요소에 배치할 적절한 값에 대해서는 이 문서의 구성을 통해 확장 섹션을 참조하세요.
  • 다음 태그와 같이 <allowedTypes auditOnly="true">를 사용하여 감사 모드를 사용하도록 설정합니다.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <!-- See the section of this document titled "Extending through configuration" for the appropriate
         <sectionGroup> and <section> elements to put here, depending on whether you're running .NET
         Framework 2.0 - 3.5 or 4.0 - 4.8. -->
  </configSections>
  <system.data.dataset.serialization>
    <allowedTypes auditOnly="true"> <!-- setting auditOnly="true" enables audit mode -->
      <!-- Optional <add /> elements as needed. -->
    </allowedTypes>
  </system.data.dataset.serialization>
</configuration>

감사 모드가 사용하도록 설정되면 App.config를 사용하여 기본 설정 TraceListenerDataSet 기본 제공 TraceSource.에 연결할 수 있습니다. 기본 제공 추적 원본의 이름은 System.Data.DataSet입니다. 다음 샘플에서는 추적 이벤트를 콘솔 ‘및’ 디스크의 로그 파일에 쓰는 방법을 보여 줍니다.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name="System.Data.DataSet"
              switchType="System.Diagnostics.SourceSwitch"
              switchValue="Warning">
        <listeners>
          <!-- write to the console -->
          <add name="console"
               type="System.Diagnostics.ConsoleTraceListener" />
          <!-- *and* write to a log file on disk -->
          <add name="filelog"
               type="System.Diagnostics.TextWriterTraceListener"
               initializeData="c:\logs\mylog.txt" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
</configuration>

TraceSourceTraceListener에 대한 자세한 내용은 방법: 추적 수신기와 함께 TraceSource 및 필터 사용 문서를 참조하세요.

참고

감사 모드에서 앱을 실행하는 것은 .NET Core 또는 .NET 5 이상에서 가능하지 않습니다.

모든 형식 제한 제거

앱이 DataSetDataTable에서 모든 형식 제한을 제거해야 하는 경우:

  • 형식 제한을 표시하지 않는 몇 가지 옵션이 있습니다.
  • 사용 가능한 옵션은 앱이 대상으로 하는 프레임워크에 따라 달라집니다.

경고

모든 형식 제한을 제거하면 앱 내부에 보안 허점이 발생할 수 있습니다. 이 메커니즘을 사용하는 경우 앱이 신뢰할 수 없는 입력을 읽기 위해 DataSet 또는 DataTable을 사용하지 않도록 합니다. 자세한 내용은 CVE-2020-1147신뢰할 수 없는 입력과 관련된 안전성 섹션을 참조하세요.

AppContext 구성을 통해(.NET Framework 4.6 이상, .NET Core 2.1 이상, .NET 5 이상)

AppContext 스위치 Switch.System.Data.AllowArbitraryDataSetTypeInstantiationtrue로 설정되면 DataSetDataTable에서 모든 형식 제한이 제거됩니다.

.NET Framework에서 다음 구성과 같이 App.config를 통해 이 스위치를 사용하도록 설정할 수 있습니다.

<configuration>
   <runtime>
      <!-- Warning: setting the following switch can introduce a security problem. -->
      <AppContextSwitchOverrides value="Switch.System.Data.AllowArbitraryDataSetTypeInstantiation=true" />
   </runtime>
</configuration>

ASP.NET에서 <AppContextSwitchOverrides> 요소는 사용할 수 없습니다. 대신, 다음 구성과 같이 Web.config를 통해 이 스위치를 사용하도록 설정할 수 있습니다.

<configuration>
    <appSettings>
        <!-- Warning: setting the following switch can introduce a security problem. -->
        <add key="AppContext.SetSwitch:Switch.System.Data.AllowArbitraryDataSetTypeInstantiation" value="true" />
    </appSettings>
</configuration>

자세한 내용은 <AppContextSwitchOverrides> 요소를 참조하세요.

.NET Core, .NET 5 및 ASP.NET Core에서 이 설정은 다음 JSON과 같이 runtimeconfig.json을 통해 제어됩니다.

{
  "runtimeOptions": {
    "configProperties": {
      "Switch.System.Data.AllowArbitraryDataSetTypeInstantiation": true
    }
  }
}

자세한 내용은 “.NET Core 런타임 구성 설정”을 참조하세요.

AllowArbitraryDataSetTypeInstantiation은 다음 코드와 같이 구성 파일을 사용하는 대신 AppContext.SetSwitch를 통해 프로그래밍 방식으로 설정할 수도 있습니다.

// Warning: setting the following switch can introduce a security problem.
AppContext.SetSwitch("Switch.System.Data.AllowArbitraryDataSetTypeInstantiation", true);

위의 프로그래밍 방식을 선택하면 앱 시작 초기에 AppContext.SetSwitch 호출이 발생합니다.

머신 전체 레지스트리를 통해(.NET Framework 2.0 - 4.x)

AppContext를 사용할 수 없는 경우 Windows 레지스트리에서 형식 제한 검사를 사용하지 않도록 설정할 수 있습니다.

  • 관리자는 레지스트리를 구성해야 합니다.
  • 레지스트리를 사용하면 머신 전체에 변경 내용이 적용되며 머신에서 실행되는 ‘모든’ 앱에 영향을 줍니다.
형식
레지스트리 키 HKLM\SOFTWARE\Microsoft\.NETFramework\AppContext
값 이름 Switch.System.Data.AllowArbitraryDataSetTypeInstantiation
값 유형 REG_SZ
값 데이터 true

64비트 운영 체제에서는 이 값을 64비트 키(위에 표시됨)와 32비트 키 모두에 추가해야 합니다. 32비트 키는 HKLM\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\AppContext에 있습니다.

레지스트리를 사용하여 AppContext를 구성하는 방법에 대한 자세한 내용은 "라이브러리 소비자를 위한 AppContext"를 참조하세요.

신뢰할 수 없는 입력과 관련된 안전성

DataSetDataTable은 XML 페이로드를 역직렬화하는 동안 존재할 수 있는 형식에 대해 기본 제한을 적용하지만 DataSetDataTable은 신뢰할 수 없는 입력으로 채워지면 일반적으로 안전하지 않습니다. 다음은 DataSet 또는 DataTable 인스턴스가 신뢰할 수 없는 입력을 읽을 수 있는 방법의 일부를 포함하는 목록입니다.

  • DataAdapter는 데이터베이스를 참조하고 DataAdapter.Fill 메서드는 데이터베이스 쿼리의 내용으로 DataSet을 채우는 데 사용됩니다.
  • DataSet.ReadXml 또는 DataTable.ReadXml 메서드는 열 및 행 정보가 포함된 XML 파일을 읽는 데 사용됩니다.
  • DataSet 또는 DataTable 인스턴스는 ASP.NET(SOAP) 웹 서비스 또는 WCF 엔드포인트의 일부로 직렬화됩니다.
  • XmlSerializer와 같은 직렬 변환기는 XML 스트림에서 DataSet 또는 DataTable 인스턴스를 역직렬화하는 데 사용됩니다.
  • JsonConvert와 같은 직렬 변환기는 JSON 스트림에서 DataSet 또는 DataTable 인스턴스를 역직렬화하는 데 사용됩니다. JsonConvert는 인기 있는 타사 Newtonsoft.Json 라이브러리의 메서드입니다.
  • BinaryFormatter와 같은 직렬 변환기는 원시 바이트 스트림에서 DataSet 또는 DataTable 인스턴스를 역직렬화하는 데 사용됩니다.

이 문서에서는 이전 시나리오에 대한 안전 고려 사항을 설명합니다.

DataAdapter.Fill을 사용하여 신뢰할 수 없는 데이터 원본에서 DataSet을 채웁니다.

다음 예제와 같이 DataAdapter.Fill 메서드를 사용하여 DataAdapter에서 DataSet 인스턴스를 채울 수 있습니다.

// Assumes that connection is a valid SqlConnection object.
string queryString =
  "SELECT CustomerID, CompanyName FROM dbo.Customers";
SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

DataSet customers = new DataSet();
adapter.Fill(customers, "Customers");

(위의 코드 샘플은 DataAdapter에서 DataSet 채우기에 포함된 더 큰 샘플의 일부입니다.)

대부분의 앱은 단순화될 수 있고 데이터베이스 계층을 신뢰한다고 가정할 수 있습니다. 그러나 앱에 대해 위협 모델링을 수행하는 경향이 있는 경우 위협 모델은 애플리케이션(클라이언트)과 데이터베이스 계층(서버) 간에 신뢰 경계가 있다고 간주할 수 있습니다. 클라이언트와 서버 간에 상호 인증 또는 AAD 인증을 사용하면 이와 관련된 위험을 해결하는 데 도움이 될 수 있습니다. 이 섹션의 나머지 부분에서는 클라이언트가 신뢰할 수 없는 서버에 연결할 때 발생할 수 있는 결과에 대해 설명합니다.

신뢰할 수 없는 데이터 원본에서 DataAdapter를 가리킬 때의 결과는 DataAdapter 자체의 구현에 따라 달라집니다.

SqlDataAdapter

기본 제공 형식 SqlDataAdapter의 경우 신뢰할 수 없는 데이터 원본을 참조하면 DoS(서비스 거부) 공격이 발생할 수 있습니다. DoS 공격으로 인해 앱이 응답하지 않거나 충돌할 수 있습니다. 공격자가 앱을 따라 DLL을 심을 수 있는 경우 로컬 코드 실행을 달성할 수도 있습니다.

기타 DataAdapter 형식

타사 DataAdapter 구현은 신뢰할 수 없는 입력에 대비해서 제공하는 보안 보장에 대한 자체 평가를 수행해야 합니다. .NET은 이러한 구현과 관련하여 어떠한 안전도 보장할 수 없습니다.

DataSet.ReadXml 및 DataTable.ReadXml

DataSet.ReadXmlDataTable.ReadXml 메서드는 신뢰할 수 없는 입력과 함께 사용할 때 안전하지 않습니다. 대신, 이 문서의 뒷부분에서 설명하는 대체 방법 중 하나를 사용하는 것이 좋습니다.

원래 DataSet.ReadXmlDataTable.ReadXml 구현은 serialization 취약성이 잘 이해되는 위협 범주가 되기 전에 만들어졌습니다. 따라서 해당 코드는 현재 보안 모범 사례를 따르지 않습니다. 이러한 API는 공격자가 웹앱에 대해 DoS 공격을 수행하기 위한 벡터로 사용할 수 있습니다. 해당 공격으로 인해 웹 서비스가 응답하지 않거나 예기치 않게 프로세스가 종료될 수 있습니다. 프레임워크는 이러한 공격 범주에 대한 완화를 제공하지 않으며 .NET은 이 동작을 “의도적인 것”으로 간주합니다.

.NET은 DataSet.ReadXmlDataTable.ReadXml에서 정보 공개 또는 원격 코드 실행과 같은 몇 가지 문제를 완화하기 위해 보안 업데이트를 릴리스했습니다. .NET 보안 업데이트는 이러한 위협 범주에 대한 완전한 보호를 제공하지 않을 수도 있습니다. 소비자는 개별 시나리오를 평가하고 이러한 위험에 노출될 가능성을 고려해야 합니다.

소비자는 이러한 API에 대한 보안 업데이트가 일부 상황에서 애플리케이션 호환성에 영향을 줄 수 있음을 알고 있어야 합니다. 그뿐 아니라 이러한 API에서 .NET이 보안 업데이트를 실제로 게시할 수 없는 새로운 취약성이 발견될 가능성이 있습니다.

이러한 API의 소비자는 다음 중 하나를 수행하는 것이 좋습니다.

  • 이 문서 뒷부분에 설명된 대안 중 하나를 사용하는 것이 좋습니다.
  • 앱에서 개별 위험 평가를 수행합니다.

이러한 API를 활용할지 여부를 결정하는 것은 전적으로 소비자의 책임입니다. 소비자는 이러한 API를 사용할 때 수반될 수 있는 모든 보안, 기술 및 법적 위험(규정 요구 사항 포함)을 평가해야 합니다.

ASP.NET 웹 서비스 또는 WCF를 통한 DataSet 및 DataTable

다음 코드와 같이 ASP.NET(SOAP) 웹 서비스에서 DataSet 또는 DataTable 인스턴스를 수락할 수 있습니다.

using System.Data;
using System.Web.Services;

[WebService(Namespace = "http://contoso.com/")]
public class MyService : WebService
{
    [WebMethod]
    public string MyWebMethod(DataTable dataTable)
    {
        /* Web method implementation. */
    }
}

이에 대한 변형은 DataSet 또는 DataTable을 매개 변수로 직접 수락하는 것이 아니라, 다음 코드와 같이 전체 SOAP 직렬화 개체 그래프의 일부로 수락하는 것입니다.

using System.Data;
using System.Web.Services;

[WebService(Namespace = "http://contoso.com/")]
public class MyService : WebService
{
    [WebMethod]
    public string MyWebMethod(MyClass data)
    {
        /* Web method implementation. */
    }
}

public class MyClass
{
    // Property of type DataTable, automatically serialized and
    // deserialized as part of the overall MyClass payload.
    public DataTable MyDataTable { get; set; }
}

또는 ASP.NET 웹 서비스 대신 WCF를 사용합니다.

using System.Data;
using System.ServiceModel;

[ServiceContract(Namespace = "http://contoso.com/")]
public interface IMyContract
{
    [OperationContract]
    string MyMethod(DataTable dataTable);
    [OperationContract]
    string MyOtherMethod(MyClass data);
}

public class MyClass
{
    // Property of type DataTable, automatically serialized and
    // deserialized as part of the overall MyClass payload.
    public DataTable MyDataTable { get; set; }
}

이러한 모든 경우에서 위협 모델 및 보안 보장은 DataSet.ReadXml 및 DataTable.ReadXml 섹션과 동일합니다.

XmlSerializer를 통해 DataSet 또는 DataTable 역직렬화

개발자는 다음 코드와 같이 XmlSerializer를 사용하여 DataSetDataTable 인스턴스를 역직렬화할 수 있습니다.

using System.Data;
using System.IO;
using System.Xml.Serialization;

public DataSet PerformDeserialization1(Stream stream) {
    XmlSerializer serializer = new XmlSerializer(typeof(DataSet));
    return (DataSet)serializer.Deserialize(stream);
}

public MyClass PerformDeserialization2(Stream stream) {
    XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
    return (MyClass)serializer.Deserialize(stream);
}

public class MyClass
{
    // Property of type DataTable, automatically serialized and
    // deserialized as part of the overall MyClass payload.
    public DataTable MyDataTable { get; set; }
}

이러한 경우에서 위협 모델 및 보안 보장은 DataSet.ReadXml 및 DataTable.ReadXml 섹션과 동일합니다.

JsonConvert를 통해 DataSet 또는 DataTable 역직렬화

다음 코드와 같이 인기 있는 타사 Newtonsoft 라이브러리 Json.NET을 사용하여 DataSetDataTable 인스턴스를 역직렬화할 수 있습니다.

using System.Data;
using Newtonsoft.Json;

public DataSet PerformDeserialization1(string json) {
    return JsonConvert.DeserializeObject<DataSet>(data);
}

public MyClass PerformDeserialization2(string json) {
    return JsonConvert.DeserializeObject<MyClass>(data);
}

public class MyClass
{
    // Property of type DataTable, automatically serialized and
    // deserialized as part of the overall MyClass payload.
    public DataTable MyDataTable { get; set; }
}

신뢰할 수 없는 JSON Blob에서 이러한 방식으로 DataSet 또는 DataTable을 역직렬화하는 것은 안전하지 않습니다. 이 패턴은 서비스 거부 공격에 취약합니다. 이러한 공격은 앱을 충돌하거나 응답하지 않게 렌더링할 수 있습니다.

참고

Microsoft는 Newtonsoft.Json과 같은 타사 라이브러리의 구현을 보증하거나 지원하지 않습니다. 이 정보는 완전성을 위해 제공되며 작성할 당시의 정확한 내용을 포함합니다.

BinaryFormatter를 통해 DataSet 또는 DataTable 역직렬화

신뢰할 수 없는 페이로드에서 DataSet 또는 DataTable 인스턴스를 역직렬화하기 위해 BinaryFormatter, NetDataContractSerializer, SoapFormatter 또는 관련된 안전하지 않은 포맷터를 사용하면 안 됩니다.

  • 전체 원격 코드 실행 공격에 취약합니다.
  • 사용자 지정 SerializationBinder를 사용하는 것만으로 이러한 공격을 방지하기에 충분하지 않습니다.

안전한 교체

다음과 같은 앱의 경우:

  • .asmx SOAP 엔드포인트 또는 WCF 엔드포인트를 통해 DataSet 또는 DataTable을 수락합니다.
  • 신뢰할 수 없는 데이터를 DataSet 또는 DataTable 인스턴스로 역직렬화합니다.

Entity Framework를 사용하도록 개체 모델을 바꾸는 것이 좋습니다. Entity Framework:

  • 관계형 데이터를 나타낼 수 있는 풍부한 최신 개체 지향 프레임워크입니다.
  • Entity Framework 개체 모델을 통해 데이터베이스 쿼리를 쉽게 프로젝션할 수 있도록 데이터베이스 공급자의 다양한 에코시스템을 제공합니다.
  • 신뢰할 수 없는 원본에서 데이터를 역직렬화할 때 기본 제공 보호를 제공합니다.

.aspx SOAP 엔드포인트를 사용하는 앱의 경우 WCF를 사용하도록 해당 엔드포인트를 변경하는 것이 좋습니다. WCF는 완벽한 기능으로 .asmx 웹 서비스를 대체합니다. WCF 엔드포인트는 기존 호출자와 호환되면서 SOAP를 통해 노출될 수 있습니다.

코드 분석기

소스 코드가 컴파일될 때 실행되는 코드 분석기 보안 규칙은 C# 및 Visual Basic 코드에서 이 보안 문제와 관련된 취약성을 찾는 데 도움이 될 수 있습니다. Microsoft.CodeAnalysis.FxCopAnalyzers는 nuget.org에 배포되는 코드 분석기의 NuGet 패키지입니다.

코드 분석기의 개요는 소스 코드 분석기 개요를 참조하세요.

다음 Microsoft.CodeAnalysis.FxCopAnalyzers 규칙을 사용하도록 설정합니다.

  • CA2350: DataTable.ReadXml()을 신뢰할 수 없는 데이터와 함께 사용 안 함
  • CA2351: DataSet.ReadXml()을 신뢰할 수 없는 데이터와 함께 사용 안 함
  • CA2352: 직렬화 가능 형식의 안전하지 않은 DataSet 또는 DataTable은 원격 코드 실행 공격에 취약할 수 있음
  • CA2353: 직렬화 가능 형식의 안전하지 않은 DataSet 또는 DataTable
  • CA2354: 역직렬화된 개체 그래프의 안전하지 않은 DataSet 또는 DataTable은 원격 코드 실행 공격에 취약할 수 있음
  • CA2355: 역직렬화 가능 개체 그래프의 안전하지 않은 DataSet 또는 DataTable 형식
  • CA2356: 웹 역직렬화 가능 개체 그래프의 안전하지 않은 데이터 세트 또는 DataTable 형식
  • CA2361: DataSet.ReadXml()을 포함하는 자동 생성된 클래스가 신뢰할 수 없는 데이터와 함께 사용되지 않도록 하기
  • CA2362: 자동 생성된 직렬화 가능 형식의 안전하지 않은 DataSet 또는 DataTable은 원격 코드 실행 공격에 취약할 수 있음

규칙 구성에 대한 자세한 내용은 코드 분석기 사용을 참조하세요.

새 보안 규칙은 다음 NuGet 패키지에서 사용할 수 있습니다.

  • Microsoft.CodeAnalysis.FxCopAnalyzers 3.3.0: Visual Studio 2019 버전 16.3 이상
  • Microsoft.CodeAnalysis.FxCopAnalyzers 2.9.11: Visual Studio 2017 버전 15.9 이상