Hendelser
17. mars, 21 - 21. mars, 10
Bli med i meetup-serien for å bygge skalerbare AI-løsninger basert på virkelige brukstilfeller med andre utviklere og eksperter.
Registrer deg nåDenne nettleseren støttes ikke lenger.
Oppgrader til Microsoft Edge for å dra nytte av de nyeste funksjonene, sikkerhetsoppdateringene og den nyeste tekniske støtten.
This article applies to:
The DataSet and DataTable types are legacy .NET components that allow representing data sets as managed objects. These components were introduced in .NET Framework 1.0 as part of the original ADO.NET infrastructure. Their goal was to provide a managed view over a relational data set, abstracting away whether the underlying source of the data was XML, SQL, or another technology.
For more information on ADO.NET, including more modern data view paradigms, see the ADO.NET documentation.
On all supported versions of .NET Framework, .NET Core, and .NET, DataSet
and DataTable
place the following restrictions on what types of objects may be present in the deserialized data. By default, this list is restricted to:
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
, SqlSingle
, and SqlString
.Type
, Uri
, and BigInteger
.Color
, Point
, PointF
, Rectangle
, RectangleF
, Size
, and SizeF
.Enum
types.If the incoming XML data contains an object whose type is not in this list:
An exception is thrown with the following message and stack trace. Error Message: System.InvalidOperationException : Type '<Type Name>, Version=<n.n.n.n>, Culture=<culture>, PublicKeyToken=<token value>' is not allowed here. Stack Trace: 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)
The deserialization operation fails.
When loading XML into an existing DataSet
or DataTable
instance, the existing column definitions are also taken into account. If the table already contains a column definition of a custom type, that type is temporarily added to the allow list for the duration of the XML deserialization operation.
Obs!
Once you add columns to a DataTable
, ReadXml
will not read the schema from the XML, and if the schema does not match it will also not read in the records, so you will need to add all the columns yourself to use this method.
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
The object type restrictions also apply when using XmlSerializer
to deserialize an instance of DataSet
or DataTable
. However, they may not apply when using BinaryFormatter
to deserialize an instance of DataSet
or DataTable
.
The object type restrictions don't apply when using DataAdapter.Fill
, such as when a DataTable
instance is populated directly from a database without using the XML deserialization APIs.
An app can extend the allowed types list to include custom types in addition to the built-in types listed above. If extending the allowed types list, the change affects all DataSet
and DataTable
instances within the app. Types cannot be removed from the built-in allowed types list.
App.config can be used to extend the allowed types list. To extend the allowed types list:
<configSections>
element to add a reference to the System.Data configuration section.<system.data.dataset.serialization>
/<allowedTypes>
to specify additional types.Each <add>
element must specify only one type by using its assembly qualified type name. To add additional types to the allowed types list, use multiple <add>
elements.
The following sample shows extending the allowed types list by adding the custom type 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>
To retrieve the assembly qualified name of a type, use the Type.AssemblyQualifiedName property, as demonstrated in the following code.
string assemblyQualifiedName = typeof(Fabrikam.CustomType).AssemblyQualifiedName;
If your app targets .NET Framework 2.0 or 3.5, you can still use the above App.config mechanism to extend the allowed types list. However, your <configSections>
element will look slightly different, as shown in the following code:
<?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>
The list of allowed types can also be extended programmatically by using AppDomain.SetData with the well-known key System.Data.DataSetDefaultAllowedTypes, as shown in the following code.
Type[] extraAllowedTypes = new Type[]
{
typeof(Fabrikam.CustomType),
typeof(Contoso.AdditionalCustomType)
};
AppDomain.CurrentDomain.SetData("System.Data.DataSetDefaultAllowedTypes", extraAllowedTypes);
If using the extension mechanism, the value associated with the key System.Data.DataSetDefaultAllowedTypes must be of type Type[]
.
On .NET Framework, the list of allowed types may be extended both with App.config and AppDomain.SetData
. In this case, DataSet
and DataTable
will allow an object to be deserialized as part of the data if its type is present in either list.
In .NET Framework, DataSet
and DataTable
provide an audit mode capability. When audit mode is enabled, DataSet
and DataTable
compare the types of incoming objects against the allowed types list. However, if an object whose type is not allowed is seen, an exception is not thrown. Instead, DataSet
and DataTable
notify any attached TraceListener
instances that a suspicious type is present, allowing the TraceListener
to log this information. No exception is thrown and the deserialization operation continues.
Advarsel
Running an app in "audit mode" should only be a temporary measure used for testing. When audit mode is enabled, DataSet
and DataTable
do not enforce type restrictions, which can introduce a security hole inside your app. For more information, see the sections titled Removing all type restrictions and Safety with regard to untrusted input.
Audit mode can be enabled through App.config:
<configSections>
element.<allowedTypes auditOnly="true">
to enable audit mode, as shown in the following markup.<?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>
Once audit mode is enabled, you can use App.config to connect your preferred TraceListener
to the DataSet
built-in TraceSource.
The name of the built-in trace source is System.Data.DataSet. The following sample demonstrates writing trace events to the console and to a log file on disk.
<?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>
For more information on TraceSource
and TraceListener
, see the document How to: Use TraceSource and Filters with Trace Listeners.
Obs!
Running an app in audit mode is not available in .NET Core or in .NET 5 and later.
If an app must remove all type limiting restrictions from DataSet
and DataTable
:
Advarsel
Removing all type restrictions can introduce a security hole inside the app. When using this mechanism, ensure the app does not use DataSet
or DataTable
to read untrusted input. For more information, see CVE-2020-1147 and the following section titled Safety with regard to untrusted input.
The AppContext
switch, Switch.System.Data.AllowArbitraryDataSetTypeInstantiation
, when set to true
removes all type limiting restrictions from DataSet
and DataTable
.
In .NET Framework, this switch can be enabled via App.config, as shown in the following configuration:
<configuration>
<runtime>
<!-- Warning: setting the following switch can introduce a security problem. -->
<AppContextSwitchOverrides value="Switch.System.Data.AllowArbitraryDataSetTypeInstantiation=true" />
</runtime>
</configuration>
In ASP.NET, the <AppContextSwitchOverrides>
element is not available. Instead, the switch can be enabled via Web.config, as shown in the following configuration:
<configuration>
<appSettings>
<!-- Warning: setting the following switch can introduce a security problem. -->
<add key="AppContext.SetSwitch:Switch.System.Data.AllowArbitraryDataSetTypeInstantiation" value="true" />
</appSettings>
</configuration>
For more information, see the <AppContextSwitchOverrides> element.
In .NET Core, .NET 5, and ASP.NET Core, this setting is controlled by runtimeconfig.json, as shown in the following JSON:
{
"runtimeOptions": {
"configProperties": {
"Switch.System.Data.AllowArbitraryDataSetTypeInstantiation": true
}
}
}
For more information, see ".NET Core runtime configuration settings".
AllowArbitraryDataSetTypeInstantiation
can also be set programmatically via AppContext.SetSwitch instead of using a configuration file, as shown in the following code:
// Warning: setting the following switch can introduce a security problem.
AppContext.SetSwitch("Switch.System.Data.AllowArbitraryDataSetTypeInstantiation", true);
If you choose the preceding programmatic approach, the call to AppContext.SetSwitch
should occur early in the apps startup.
If AppContext
is not available, type limiting checks can be disabled with the Windows registry:
Type | Value |
---|---|
Registry key | HKLM\SOFTWARE\Microsoft\.NETFramework\AppContext |
Value name | Switch.System.Data.AllowArbitraryDataSetTypeInstantiation |
Value type | REG_SZ |
Value data | true |
On a 64-bit operating system, this value my need to be added for both the 64-bit key (shown above) and the 32-bit key. The 32-bit key is located at HKLM\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\AppContext
.
For more information on using the registry to configure AppContext
, see "AppContext for library consumers".
While DataSet
and DataTable
do impose default limitations on the types that are allowed to be present while deserializing XML payloads, DataSet
and DataTable
are in general not safe when populated with untrusted input. The following is a non-exhaustive list of ways that a DataSet
or DataTable
instance might read untrusted input.
DataAdapter
references a database, and the DataAdapter.Fill
method is used to populate a DataSet
with the contents of a database query.DataSet.ReadXml
or DataTable.ReadXml
method is used to read an XML file containing column and row information.DataSet
or DataTable
instance is serialized as part of a ASP.NET (SOAP) web services or WCF endpoint.XmlSerializer
is used to deserialize a DataSet
or DataTable
instance from an XML stream.JsonConvert
is used to deserialize a DataSet
or DataTable
instance from a JSON stream. JsonConvert
is a method in the popular third-party Newtonsoft.Json library.BinaryFormatter
is used to deserialize a DataSet
or DataTable
instance from a raw byte stream.This document discusses safety considerations for the preceding scenarios.
A DataSet
instance can be populated from a DataAdapter
by using the DataAdapter.Fill
method, as shown in the following example.
// 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");
(The code sample above is part of a larger sample found at Populating a DataSet from a DataAdapter.)
Most apps can simplify and assume that their database layer is trusted. However, if you are in the habit of threat modeling your apps, your threat model may consider there to be a trust boundary between the application (client) and database layer (server). Using mutual authentication or AAD authentication between client and server is one way to help address the risks associated with this. The remainder of this section discusses the possible result of a client connecting to an untrusted server.
The consequences of pointing a DataAdapter
at an untrusted data source depend on the implementation of the DataAdapter
itself.
For the built-in type SqlDataAdapter, referencing an untrusted data source could result in a denial of service (DoS) attack. The DoS attack could result in the app becoming unresponsive or crashing. If an attacker can plant a DLL alongside the app, they may also be able to achieve local code execution.
Third-party DataAdapter
implementations must make their own assessments about what security guarantees they provide in the face of untrusted inputs. .NET cannot make any safety guarantees regarding these implementations.
The DataSet.ReadXml
and DataTable.ReadXml
methods are not safe when used with untrusted input. We strongly recommend that consumers instead consider using one of the alternatives outlined later in this document.
The implementations of DataSet.ReadXml
and DataTable.ReadXml
were originally created before serialization vulnerabilities were a well-understood threat category. As a result, the code does not follow current security best practices. These APIs can be used as vectors for attackers to perform DoS attacks against web apps. These attacks might render the web service unresponsive or result in unexpected process termination. The framework does not provide mitigations for these attack categories and .NET considers this behavior "by design".
.NET has released security updates to mitigate some issues such as information disclosure or remote code execution in DataSet.ReadXml
and DataTable.ReadXml
. The .NET security updates may not provide complete protection against these threat categories. Consumers should assess their individual scenarios and consider their potential exposure to these risks.
Consumers should be aware that security updates to these APIs may impact application compatibility in some situations. Furthermore, the possibility exists that a novel vulnerability in these APIs will be discovered for which .NET can't practically publish a security update.
We recommend that consumers of these APIs either:
It is the consumer's sole responsibility to determine whether to utilize these APIs. Consumers should assess any security, technical, and legal risks, including regulatory requirements, that may accompany using these APIs.
It is possible to accept a DataSet
or a DataTable
instance in an ASP.NET (SOAP) web service, as demonstrated in the following code:
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. */
}
}
A variation on this is not to accept DataSet
or DataTable
directly as a parameter, but instead to accept it as part of the overall SOAP serialized object graph, as shown in the following code:
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; }
}
Or, using WCF instead of ASP.NET web services:
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; }
}
In all of these cases, the threat model and security guarantees are the same as the DataSet.ReadXml and DataTable.ReadXml section.
Developers can use XmlSerializer
to deserialize DataSet
and DataTable
instances, as shown in the following code:
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; }
}
In these cases, the threat model and security guarantees are the same as the DataSet.ReadXml and DataTable.ReadXml section.
The third-party Newtonsoft library Json.NET can be used to deserialize DataSet
and DataTable
instances, as shown in the following code:
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; }
}
Deserializing a DataSet
or DataTable
in this manner from an untrusted JSON blob is not safe. This pattern is vulnerable to a denial of service attack. Such an attack could crash the app or render it unresponsive.
Obs!
Microsoft does not warrant or support the implementation of third-party libraries like Newtonsoft.Json. This information is provided for completeness and is accurate as of the time of this writing.
You must never use BinaryFormatter
, NetDataContractSerializer
, SoapFormatter
, or related unsafe formatters to deserialize a DataSet
or DataTable
instance from an untrusted payload:
SerializationBinder
is not sufficient to prevent such an attack.For apps that either:
DataSet
or DataTable
through an .asmx SOAP endpoint or a WCF endpoint.DataSet
or DataTable
.Consider replacing the object model to use Entity Framework. Entity Framework:
For apps that use .aspx
SOAP endpoints, consider changing those endpoints to use WCF. WCF is a more fully featured replacement for .asmx
web services. WCF endpoints can be exposed via SOAP for compatibility with existing callers.
Code analyzer security rules, which run when your source code is compiled, can help to find vulnerabilities related to this security issue in C# and Visual Basic code. Microsoft.CodeAnalysis.FxCopAnalyzers is a NuGet package of code analyzers that's distributed on nuget.org.
For an overview of code analyzers, see Overview of source code analyzers.
Enable the following Microsoft.CodeAnalysis.FxCopAnalyzers rules:
For more information about configuring rules, see Use code analyzers.
The new security rules are available in the following NuGet packages:
Hendelser
17. mars, 21 - 21. mars, 10
Bli med i meetup-serien for å bygge skalerbare AI-løsninger basert på virkelige brukstilfeller med andre utviklere og eksperter.
Registrer deg nåOpplæring
Læringsbane
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Dokumentasjon
Adding a DataTable to a DataSet - ADO.NET
Refer to this example code to learn how to create DataTable objects and add them to an existing DataSet in ADO.NET.
Learn more about: Typed DataSets