|
|
| Zeile 1: |
Zeile 1: |
| = Model Binding & Validation – ASP.NET Core MVC (Spickzettel) = | | ==Schwachstellen== |
| | | ===Sprachmodell=== |
| == Standard-Model-Binding (Query, Route, Form) == | | * [https://airiskdatabase.com AI Risk Database] – Eine Datenbank mit Risiken und Schwachstellen im Bereich Künstliche Intelligenz. |
| | | * [https://github.com/advisories GitHub CVE & Security Advisories] – Offizielle Sicherheitswarnungen und CVE-Meldungen von GitHub für Open-Source-Projekte. |
| <syntaxhighlight lang="csharp">
| | * [https://cve.mitre.org/ MITRE CVE Database] – Zentrale Datenbank für öffentlich bekannte Schwachstellen (Common Vulnerabilities and Exposures, CVE). |
| // Route mit optionalen Parametern (aus Query oder Route gebunden)
| | * [https://nvd.nist.gov/ National Vulnerability Database (NVD)] – Die US-amerikanische nationale Datenbank für Schwachstellen, gepflegt vom NIST. |
| [Route("buchladen/{buchid?}/{eingeloggt?}")] | | * [https://www.cvedetails.com/ CVE Details] – Eine benutzerfreundliche Übersicht und Analyse von CVE-Einträgen. |
| public IActionResult Index(int? buchid, bool? eingeloggt)
| | * [https://www.exploit-db.com/ Exploit Database] – Sammlung von Exploits und Proof-of-Concept-Code für bekannte Schwachstellen. |
| {
| | * [https://www.securityfocus.com/vulnerabilities SecurityFocus Vulnerability Database] – Archiv von Schwachstellen und Sicherheitsmeldungen. |
| return Content($"Buch-ID: {buchid}, Eingeloggt: {eingeloggt}", "text/plain");
| | * [https://www.openwall.com/lists/oss-security/ Open Source Security (oss-security)] – Mailingliste und Archiv zu Schwachstellen in Open-Source-Software. |
| }
| | * [https://vuldb.com VulDB] – Community-basierte Schwachstellendatenbank mit aktuellen Informationen und Analysen. |
| | | * [https://www.zerodayinitiative.com/advisories/published/ Zero Day Initiative Advisories] – Veröffentlichte Schwachstellen und Exploits aus dem Zero Day Initiative Programm. |
| // Route mit festem (required) Parameter (aus Route gebunden)
| |
| [Route("shop/buecher/{id}")] | |
| public IActionResult Buch()
| |
| {
| |
| int id = Convert.ToInt32(Request.RouteValues["id"]);
| |
| return Content($"<h1>Buch-Shop {id}</h1>", "text/html");
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == [FromQuery] und [FromRoute] verwenden ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| [Route("buchladen/{buchid?}/{eingeloggt?}")] | |
| public IActionResult Index([FromQuery] int? buchid, [FromRoute] bool? eingeloggt)
| |
| {
| |
| // Explizites Binding: buchid nur aus Query, eingeloggt nur aus Route
| |
| return Content($"Buch-ID: {buchid}, Eingeloggt: {eingeloggt}");
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == Model Binding mit Modelklassen ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| // Modelklasse | |
| public class Buch
| |
| {
| |
| public int? BuchId { get; set; }
| |
| public string? Autor { get; set; }
| |
| public override string ToString() => $"Buch: {BuchId}, Autor: {Autor}";
| |
| }
| |
| | |
| // Controller
| |
| [Route("buchladen/{buchid?}/{eingeloggt?}")]
| |
| public IActionResult Index([FromQuery] int? buchid, [FromRoute] bool? eingeloggt, Buch buch)
| |
| {
| |
| return Content($"Buch-ID: {buchid}, Buch: {buch}", "text/plain");
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == Model Validation mit DataAnnotations ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| using System.ComponentModel.DataAnnotations;
| |
| | |
| public class Person
| |
| {
| |
| [Required(ErrorMessage = "{0} darf nicht leer sein")]
| |
| public string? Name { get; set; }
| |
| | |
| [EmailAddress]
| |
| public string? Email { get; set; }
| |
| | |
| [Compare("Passwort", ErrorMessage = "Passwörter stimmen nicht überein")]
| |
| public string? PasswortBestätigung { get; set; }
| |
| }
| |
| | |
| // Controller | |
| public IActionResult Erstellen(Person person)
| |
| {
| |
| if (!ModelState.IsValid)
| |
| return View(person);
| |
| // Speicherung etc.
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == Custom Validation Attribute Beispiel ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| // Validator: ToDate >= FromDate | |
| public class DatumsbereichValidatorAttribute : ValidationAttribute
| |
| {
| |
| public string VonProperty { get; }
| |
| public DatumsbereichValidatorAttribute(string vonProperty) => VonProperty = vonProperty;
| |
| protected override ValidationResult? IsValid(object? value, ValidationContext context)
| |
| {
| |
| if (value is DateTime toDate)
| |
| {
| |
| var fromProp = context.ObjectType.GetProperty(VonProperty);
| |
| if (fromProp?.GetValue(context.ObjectInstance) is DateTime fromDate && fromDate > toDate)
| |
| return new ValidationResult(ErrorMessage, new[] { VonProperty, context.MemberName! });
| |
| }
| |
| return ValidationResult.Success;
| |
| }
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == Model-Level Validation mit IValidatableObject ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| public class Person : IValidatableObject
| |
| {
| |
| public DateTime? Geburtsdatum { get; set; }
| |
| public int? Alter { get; set; }
| |
| | |
| public IEnumerable<ValidationResult> Validate(ValidationContext context)
| |
| {
| |
| if (!Geburtsdatum.HasValue && !Alter.HasValue)
| |
| yield return new ValidationResult("Geburtsdatum ODER Alter muss angegeben werden", new[] { nameof(Alter) });
| |
| }
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == [Bind] und [BindNever] Attribute ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| // Nur bestimmte Felder binden | |
| [HttpPost]
| |
| public IActionResult Erstellen([Bind("Titel", "Beschreibung")] Produkt produkt) { ... }
| |
| | |
| // Niemals aus Request binden | |
| public class Produkt
| |
| {
| |
| [BindNever]
| |
| public DateTime ErstelltAm { get; set; }
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == [FromBody]: JSON/XML Body-Parameter binden ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| [Route("registrieren")]
| |
| public IActionResult Index([FromBody] Person person)
| |
| {
| |
| if (!ModelState.IsValid) { ... }
| |
| return Content($"{person}");
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == Collection Binding (Listen/Arrays binden) ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| public class Person
| |
| {
| |
| public List<string?> Interessen { get; set; } = new();
| |
| }
| |
| | |
| // JSON: { "Name": "Anna", "Interessen": ["Musik", "Lesen", "Coding"] }
| |
| public IActionResult Index(Person person)
| |
| {
| |
| return Content($"Person: {person.Name}, Interessen: {string.Join(",", person.Interessen)}");
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == [FromHeader]: Parameter aus HTTP-Header ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| [Route("registrieren")]
| |
| public IActionResult Index(Person person, [FromHeader(Name = "User-Agent")] string userAgent)
| |
| {
| |
| return Content($"{person}, {userAgent}");
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == Input Formatters registrieren (z.B. XML) ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| var builder = WebApplication.CreateBuilder(args);
| |
| builder.Services.AddControllers().AddXmlSerializerFormatters();
| |
| </syntaxhighlight>
| |
| | |
| == Custom Model Binder registrieren ==
| |
| | |
| <syntaxhighlight lang="csharp">
| |
| // Custom Binder implementieren | |
| public class PersonModelBinder : IModelBinder { ... }
| |
| | |
| // BinderProvider registrieren (Startup/Program.cs) | |
| builder.Services.AddControllers(options => {
| |
| options.ModelBinderProviders.Insert(0, new PersonBinderProvider());
| |
| });
| |
| </syntaxhighlight>
| |
| | |
| ----
| |
| | |
| = Übungen / Mini-Aufgaben =
| |
| | |
| * Schreibe eine Controller-Methode, die einen Parameter aus der Query und einen aus der Route bindet.
| |
| * Erstelle ein Model mit mindestens drei Properties und validiere sie mit DataAnnotations. | |
| * Schreibe ein Custom ValidationAttribute, das prüft, ob ein Datum in der Zukunft liegt.
| |
| * Nutze [FromBody], um ein komplettes Model aus JSON im Request-Body zu binden.
| |
| * Verwende [BindNever], um eine Eigenschaft vor Overposting zu schützen. | |
| * Binde eine Liste von Strings im Model und fülle sie über ein Array im Request.
| |
| * Hole den User-Agent per [FromHeader] und gib ihn in der Response aus.
| |