TGViewer
Библиотека шарписта | C#, F#, .NET, ASP.NET Библиотека шарписта | C#, F#, .NET, ASP.NET @csharpproglib · 21.7K subscribers
Post #7023 3.27K
📎 JsonSerializerOptions: дефолты vs продакшен в .NET 10

System.Text.Json работает из коробки, но умолчания выбирались для удобства, а не безопасности. Разбираем пять настроек, которые стоит менять перед релизом.

Дублирующиеся ключи

{"role":"user","role":"admin"}


По умолчанию десериализатор молча возьмёт admin. Именно это эксплуатировал CVE-2022-25757: шлюз видел одно значение, бэкенд — другое. Фикс: AllowDuplicateProperties = false.

Неизвестные поля

Поля, которых нет в модели, тихо выбрасываются. Переименовали свойство в DTO и забыли обновить клиент — данные исчезают без ошибки. Фикс: UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow.

required компилятора ≠ required для десериализатора

C# 11 следит, чтобы объект нельзя было создать без обязательных полей. Десериализатор работает через рефлексию и обходит этот контроль — запишет null туда, где поля нет в JSON. Баг всплывёт на три слоя глубже в виде NullReferenceException. Фикс: RespectRequiredConstructorParameters = true.

Регистр не важен — по умолчанию

ASP.NET Core включает PropertyNameCaseInsensitive = true в веб-дефолтах. IsAdmin, isadmin и ISADMIN — одно и то же. Если рядом есть middleware с проверкой строк по сырому JSON — они уже видят разные вещи. Фикс: PropertyNameCaseInsensitive = false.

Nullable-аннотации игнорируются

string Name говорит, что поле не может быть null. Десериализатор это не соблюдает — запишет null без предупреждений. Фикс: RespectNullableAnnotations = true.

В .NET 10 всё это одна строка:
var options = JsonSerializerOptions.Strict;


Для ASP.NET Core пайплайна JsonOptions.SerializerOptions не заменяется целиком, флаги выставляются вручную:
builder.Services.Configure<JsonOptions>(o =>
{
var s = o.SerializerOptions;
s.AllowDuplicateProperties = false;
s.UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow;
s.PropertyNameCaseInsensitive = false;
s.RespectNullableAnnotations = true;
s.RespectRequiredConstructorParameters = true;
});


Для прямых вызовов JsonSerializer.Deserialize вне MVC-пайплайна — передавайте JsonSerializerOptions.Strict напрямую.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#il_люминатор
  • 👍 23
  • ❤ 3
  • 😁 1
More from @csharpproglib
  1. Sep 22, 2026💡 Replace, Regex или StringBuilder? Для замены текста в C# есть несколько инструментов. И…
  2. Sep 21, 2026⚙️ Настоящие атомарные операции Если Volatile решает проблему видимости, то Interlocked ре…
  3. Sep 20, 2026💪 Разминка перед трудовыми буднями Что произойдёт? ❤️ — список станет [1, 3] 🔥 — Invalid…
  4. Sep 19, 2026🧩 Middleware в ASP.NET Core: 3 ловушки Middleware — звено HTTP pipeline: app.Use(async (c…
  5. Sep 18, 2026📍 Навигация: Вакансии • Задачи • Собесы 🐸Библиотека шарписта #garbage_collector
  6. Sep 17, 2026🦆 Duck typing в C# — почти как в TypeScript В TypeScript достаточно, чтобы у объекта был…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →