Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ostrzeżenie
BinaryFormatter wsparcie nie jest zalecane. Używaj go tylko jako tymczasowego pomostu migracyjnego dla aplikacji starszego typu, które nie mogą natychmiast migrować do nowych typów interfejsów API bezpiecznych. Takie podejście niesie ze sobą znaczące zagrożenia bezpieczeństwa.
W tym artykule pokazano, jak skonfigurować obsługę operacji schowka Windows Forms w ograniczonym zakresie w .NET 10. Mimo że BinaryFormatter zostało usunięte ze środowiska uruchomieniowego platformy .NET 9 z powodu luk w zabezpieczeniach, przywróć ograniczoną funkcjonalność poprzez jawną konfigurację dla starszych aplikacji, które potrzebują czasu na migrację.
Aby uzyskać pełne wskazówki dotyczące migracji do nowych interfejsów API bezpiecznych typów, zobacz Schowek formularzy systemu Windows i zmiany obiektu DataObject na platformie .NET 10.
Ważne
Ta zawartość dotyczy tylko nowoczesnej platformy .NET, a nie .NET Framework, chyba że określono inaczej.
Wymagania wstępne
Przed kontynuowaniem zapoznaj się z następującymi pojęciami:
- Sposób, w jaki aplikacja obecnie używa
BinaryFormatterw operacjach schowka. - Luki w zabezpieczeniach, które doprowadziły do usunięcia elementu
BinaryFormatter. - Oś czasu migracji do nowych interfejsów API schowka bezpiecznego typu.
Aby uzyskać więcej informacji, zobacz następujące artykuły:
- Ryzyko deserializacji w użyciu klasy BinaryFormatter i powiązanych typów
- Przewodnik migracji BinaryFormatter
Ostrzeżenia i zagrożenia dotyczące zabezpieczeń
BinaryFormatter jest z natury niezabezpieczony i przestarzały z następujących powodów:
- Luki w zabezpieczeniach dotyczące dowolnego wykonywania kodu: osoby atakujące mogą wykonywać złośliwy kod podczas deserializacji, ujawniając aplikację na ataki zdalne.
- Ataki typu "odmowa usługi": złośliwe dane schowka mogą zużywać nadmiarną ilość pamięci lub zasobów CPU, powodując awarie lub niestabilność.
- Ryzyko ujawnienia informacji: osoby atakujące mogą wyodrębniać poufne dane z pamięci.
- Brak granic zabezpieczeń: format jest zasadniczo niebezpieczny, a ustawienia konfiguracji nie mogą go zabezpieczyć.
Włącz tę obsługę tylko jako most tymczasowy podczas aktualizowania aplikacji, aby korzystać z nowych bezpiecznych typów interfejsów API.
Instalowanie pakietu zgodności
Dodaj niewspierany pakiet zgodności BinaryFormatter do swojego projektu. Ten pakiet zapewnia wymaganą obsługę środowiska uruchomieniowego dla BinaryFormatter operacji:
<ItemGroup>
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0*-*"/>
</ItemGroup>
Uwaga / Notatka
Ten pakiet jest oznaczony jako nieobsługiwany i przestarzały. Używaj go tylko w celu zapewnienia zgodności tymczasowej podczas migracji.
Włączanie niebezpiecznej serializacji w projekcie
Ustaw właściwość EnableUnsafeBinaryFormatterSerialization na true w pliku twojego projektu. Ta właściwość nakazuje kompilatorowi zezwolenie na BinaryFormatter użycie:
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>
Bez tego ustawienia aplikacja generuje błędy kompilacji podczas próby użycia BinaryFormatter interfejsów API.
Skonfiguruj przełącznik środowiska uruchomieniowego formularzy systemu Windows
Utwórz lub zaktualizuj plik aplikacji runtimeconfig.json , aby włączyć przełącznik schowka specyficzny dla formularzy systemu Windows. Ta konfiguracja umożliwia wykonywanie operacji schowka w razie potrzeby, przełączając się na BinaryFormatter.
{
"runtimeOptions": {
"configProperties": {
"Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization": true
}
}
}
Ważne
Bez tego konkretnego przełącznika środowiska uruchomieniowego operacje schowka nie wrócą do BinaryFormatter, nawet jeśli włączono obsługę serializacji ogólnej. Przełącznik ten jest niezbędny konkretnie dla funkcjonalności schowka w Windows Forms i WPF.
Implementowanie rozpoznawania typów skoncentrowanych na zabezpieczeniach
Nawet przy włączonym BinaryFormatter zaimplementuj metody rozpoznawania typów, aby ograniczyć deserializację do jawnie zatwierdzonych typów. Programy rozpoznawania typów zapewniają jedyną ochronę przed złośliwymi atakami ładunku.
Utwórz bezpieczny rozwiązywacz typów
// Create a security-focused type resolver
private static Type SecureTypeResolver(TypeName typeName)
{
// Explicit allow-list of permitted types—add only what you need
var allowedTypes = new Dictionary<string, Type>
{
["MyApp.Person"] = typeof(Person),
["MyApp.AppSettings"] = typeof(AppSettings),
["System.String"] = typeof(string),
["System.Int32"] = typeof(int),
// Add only the specific types your application requires
};
// Only allow explicitly listed types - exact string match required
if (allowedTypes.TryGetValue(typeName.FullName, out Type allowedType))
{
return allowedType;
}
// Reject any type not in the allow-list with clear error message
throw new InvalidOperationException(
$"Type '{typeName.FullName}' is not permitted for clipboard deserialization");
}
' Create a security-focused type resolver
Private Shared Function SecureTypeResolver(typeName As TypeName) As Type
' Explicit allow-list of permitted types—add only what you need
Dim allowedTypes As New Dictionary(Of String, Type) From {
{"MyApp.Person", GetType(Person)},
{"MyApp.AppSettings", GetType(AppSettings)},
{"System.String", GetType(String)},
{"System.Int32", GetType(Integer)}
} ' Add only the specific types your application requires
' Only allow explicitly listed types - exact string match required
Dim allowedType As Type = Nothing
If allowedTypes.TryGetValue(typeName.FullName, allowedType) Then
Return allowedType
End If
' Reject any type not in the allow-list with clear error message
Throw New InvalidOperationException(
$"Type '{typeName.FullName}' is not permitted for clipboard deserialization")
End Function
Użyj narzędzia rozpoznawania typów z operacjami schowka
// Use the resolver with clipboard operations
private static Type SecureTypeResolver(TypeName typeName)
{
// Implementation from SecureTypeResolver example
// ... (allow-list implementation here)
throw new InvalidOperationException($"Type '{typeName.FullName}' is not permitted");
}
public static void UseSecureTypeResolver()
{
// Retrieve legacy data using the secure type resolver
if (Clipboard.TryGetData("LegacyData", SecureTypeResolver, out MyCustomType data))
{
ProcessLegacyData(data);
}
else
{
Console.WriteLine("No compatible data found on clipboard");
}
}
' Use the resolver with clipboard operations
Private Shared Function SecureTypeResolver(typeName As TypeName) As Type
' Implementation from SecureTypeResolver example
' ... (allow-list implementation here)
Throw New InvalidOperationException($"Type '{typeName.FullName}' is not permitted")
End Function
Public Shared Sub UseSecureTypeResolver()
' Retrieve legacy data using the secure type resolver
Dim data As MyCustomType = Nothing
If Clipboard.TryGetData("LegacyData", AddressOf SecureTypeResolver, data) Then
ProcessLegacyData(data)
Else
Console.WriteLine("No compatible data found on clipboard")
End If
End Sub
Wytyczne dotyczące zabezpieczeń dla rozpoznawania typów
Postępuj zgodnie z tymi podstawowymi wytycznymi dotyczącymi zabezpieczeń podczas implementowania rozpoznawania typów:
Używanie jawnych list dozwolonych
- Odrzuć domyślnie: Zezwalaj tylko na jawne typy.
- Nie używaj symboli wieloznacznych: unikaj dopasowywania wzorców lub stosowania uprawnień opartych na przestrzeni nazw.
- Dokładne dopasowanie: Wymagaj dokładnego dopasowania ciągów znaków dla nazw typów.
Weryfikowanie wszystkich danych wejściowych
- Sprawdzanie poprawności nazwy typu: upewnij się, że nazwy typów są zgodne z oczekiwanymi formatami.
- Ograniczenia zestawów: ogranicz typy znanych, zaufanych zestawów.
- Sprawdzanie wersji: rozważ ograniczenia typu specyficzne dla wersji.
Bezpieczna obsługa nieznanych typów
- Zgłaszanie wyjątków: zawsze zgłaszaj nieautoryzowane typy.
- Próby rejestrowania: rozważ rejestrowanie nieautoryzowanych prób dostępu.
- Wyczyść komunikaty o błędach: podaj konkretne przyczyny odrzucenia debugowania.
Regularna konserwacja
- Regularnie przeprowadzaj inspekcję: Przejrzyj i zaktualizuj listę dozwolonych typów.
- Usuń nieużywane typy: eliminowanie uprawnień dla typów, które nie są już potrzebne.
- Decyzje dotyczące dokumentów: zachowaj wyraźną dokumentację, dlaczego każdy typ jest dozwolony.
Testowanie konfiguracji
Po skonfigurowaniu obsługi przetestuj aplikację BinaryFormatter, aby upewnić się, że działa prawidłowo.
- Sprawdź operacje schowka: przetestuj zarówno przechowywanie, jak i pobieranie danych przy użyciu typów niestandardowych.
- Program rozpoznawania typów testów: upewnij się, że nieautoryzowane typy są prawidłowo odrzucane.
- Monitorowanie zabezpieczeń: obserwuj wszelkie nieoczekiwane próby rozwiązania typu.
- Testowanie wydajności: Upewnij się, że program rozpoznawania typów nie ma znaczącego wpływu na wydajność.
public static void TestBinaryFormatterConfiguration()
{
// Test data to verify configuration
var testPerson = new Person { Name = "Test User", Age = 30 };
try
{
// Test storing data (this should work with proper configuration)
Clipboard.SetData("TestPerson", testPerson);
Console.WriteLine("Successfully stored test data on clipboard");
// Test retrieving with type resolver
if (Clipboard.TryGetData("TestPerson", SecureTypeResolver, out Person retrievedPerson))
{
Console.WriteLine($"Successfully retrieved: {retrievedPerson.Name}, Age: {retrievedPerson.Age}");
}
else
{
Console.WriteLine("Failed to retrieve test data");
}
// Test that unauthorized types are rejected
try
{
Clipboard.TryGetData("TestPerson", UnauthorizedTypeResolver, out Person _);
Console.WriteLine("ERROR: Unauthorized type was not rejected!");
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"SUCCESS: Unauthorized type properly rejected - {ex.Message}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Configuration test failed: {ex.Message}");
}
}
private static Type SecureTypeResolver(TypeName typeName)
{
var allowedTypes = new Dictionary<string, Type>
{
["ClipboardExamples.Person"] = typeof(Person),
};
if (allowedTypes.TryGetValue(typeName.FullName, out Type allowedType))
{
return allowedType;
}
throw new InvalidOperationException($"Type '{typeName.FullName}' is not permitted");
}
private static Type UnauthorizedTypeResolver(TypeName typeName)
{
// Intentionally restrictive resolver to test rejection
throw new InvalidOperationException($"No types are permitted by this test resolver");
}
Public Shared Sub TestBinaryFormatterConfiguration()
' Test data to verify configuration
Dim testPerson As New Person With {.Name = "Test User", .Age = 30}
Try
' Test storing data (this should work with proper configuration)
Clipboard.SetData("TestPerson", testPerson)
Console.WriteLine("Successfully stored test data on clipboard")
' Test retrieving with type resolver
Dim retrievedPerson As Person = Nothing
If Clipboard.TryGetData("TestPerson", AddressOf SecureTypeResolver, retrievedPerson) Then
Console.WriteLine($"Successfully retrieved: {retrievedPerson.Name}, Age: {retrievedPerson.Age}")
Else
Console.WriteLine("Failed to retrieve test data")
End If
' Test that unauthorized types are rejected
Try
Dim testResult As Person = Nothing
Clipboard.TryGetData("TestPerson", AddressOf UnauthorizedTypeResolver, testResult)
Console.WriteLine("ERROR: Unauthorized type was not rejected!")
Catch ex As InvalidOperationException
Console.WriteLine($"SUCCESS: Unauthorized type properly rejected - {ex.Message}")
End Try
Catch ex As Exception
Console.WriteLine($"Configuration test failed: {ex.Message}")
End Try
End Sub
Private Shared Function SecureTypeResolver(typeName As TypeName) As Type
Dim allowedTypes As New Dictionary(Of String, Type) From {
{"ClipboardExamples.Person", GetType(Person)}
}
Dim allowedType As Type = Nothing
If allowedTypes.TryGetValue(typeName.FullName, allowedType) Then
Return allowedType
End If
Throw New InvalidOperationException($"Type '{typeName.FullName}' is not permitted")
End Function
Private Shared Function UnauthorizedTypeResolver(typeName As TypeName) As Type
' Intentionally restrictive resolver to test rejection
Throw New InvalidOperationException($"No types are permitted by this test resolver")
End Function
Planowanie strategii migracji
Chociaż obsługa BinaryFormatter zapewnia tymczasową zgodność, opracuj plan migracji dla przejścia do nowych interfejsów API z bezpiecznymi typami.
- Identyfikowanie użycia: Kataloguj wszystkie operacje schowka przy użyciu typów niestandardowych.
- Priorytet migracji: najpierw skoncentruj się na najbardziej wrażliwych na zabezpieczeniach operacjach.
- Aktualizuj przyrostowo: przeprowadź migrację jednej operacji naraz, aby zmniejszyć ryzyko.
- Dokładnie przetestuj: Upewnij się, że nowe implementacje zapewniają równoważne funkcje.
- Usuń binaryFormatter: Wyłącz obsługę po zakończeniu migracji.
Uprzątnij zasoby
Po przeprowadzeniu migracji do nowych interfejsów API schowka bezpiecznego typu usuń konfigurację BinaryFormatter w celu zwiększenia bezpieczeństwa:
- Usuń odwołanie do
System.Runtime.Serialization.Formatterspakietu. -
EnableUnsafeBinaryFormatterSerializationUsuń właściwość z pliku projektu. - Usuń ustawienie
Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerializationzruntimeconfig.json. - Usuń implementacje rozpoznawania typów, które nie są już potrzebne.
Treści powiązane
.NET Desktop feedback