Den bedste praksis for håndtering af forbindelsesstrenge og konfiguration er at anvende hemmeligheder eller en konfigurationsserver, som eksempelvis Azure App Configuration. Dette sikrer, at følsomme oplysninger ikke ligger direkte i applikationens konfigurationsfiler. Til undervisningsformål indsættes dog ofte forbindelsesstrengen i appsettings.json-filen, hvor strukturen følger ASP.NET Core 9’s konventioner, og hvor hver forbindelse repræsenteres som en egenskab i ConnectionStrings-objektet.

Entity Framework Core (EF Core) er en ORM (Object-Relational Mapper), som står for den komplekse opgave med at administrere forbindelsen til databasen, kortlægge databasens tabeller til C#-objekter og generere de nødvendige SQL-kommandoer. Kernen i denne funktionalitet er DbContext-klassen, der fungerer som et bindeled mellem domænemodellerne i applikationen og den underliggende database.

DbContext implementerer Unit of Work-designmønsteret, som er centralt for at opretholde konsistens mellem applikationens objekter i hukommelsen og den faktiske tilstand i databasen. Det betyder, at ændringer foretages i objekter først i hukommelsen, og først ved at "committe" disse ændringer til databasen sikres vedvarende lagring. Denne adskillelse af forretningslogik og datamanipulation fremmer en renere arkitektur og øger vedligeholdelsesmulighederne.

I et typisk projekt defineres en kontekstklasse, eksempelvis BankingDbContext, som arver fra DbContext. Denne klasse indeholder DbSet-egenskaber, der repræsenterer tabeller i databasen og muliggør dataadgang og manipulation. Konstruktøren i DbContext-klassen modtager typisk DbContextOptions, hvilket giver mulighed for at konfigurere forbindelsesstrengen og andre parametre via afhængighedsinjektion og det såkaldte options pattern, som er en udbredt konfigurationsmetode i .NET.

Ved brug af EF Core følger navngivningen af tabeller og kolonner som standard konventionerne, hvor klassenavne og egenskaber direkte afspejler databasen. For eksempel forventes en Account-klasse at være mappet til en Account-tabel med kolonner, der svarer til klassens egenskaber. Relationer som fremgår af foreign keys og navigationsegenskaber håndteres automatisk, hvor EF Core afleder relationerne baseret på navngivning og konventioner.

For mere komplekse scenarier, hvor standardkonventionerne ikke passer, kan man benytte Fluent API i DbContext’s OnModelCreating-metode. Her kan man præcist definere tabellernes navne, primærnøgler, kolonnenavne, relationer og andre databaseattributter. Dette giver fuld kontrol over hvordan domænemodellerne kortlægges til den underliggende databasemodel. Dataannotations i domæneklasserne er et alternativ, men Fluent API giver større fleksibilitet og centralisering af mappings.

For at EF Core kan synkronisere applikationens domænemodel med databasen, anvendes migrations. En migration udgør et øjebliksbillede af applikationens datamodel, hvor ændringer i klasserne afspejles i SQL-scripts, der opdaterer databasen. Ved at køre kommandoen til at tilføje en migration skabes en versioneret opdatering, som sikrer, at database og applikation forbliver i overensstemmelse.

Det er væsentligt at forstå, at brugen af DbContext og EF Core ikke blot forenkler dataadgangen, men også fremmer en struktur, hvor ansvaret for datatilgang adskilles fra forretningslogik. Denne adskillelse sikrer, at applikationens domænemodel kan udvikles uafhængigt af de tekniske detaljer omkring databasen, hvilket i høj grad understøtter vedligeholdelse, test og videreudvikling.

Det er samtidig vigtigt at være opmærksom på sikkerhedsaspekterne ved håndtering af forbindelsesstrenge. I produktionsmiljøer bør følsomme oplysninger ikke ligge i konfigurationsfiler, men administreres via sikre mekanismer som f.eks. Azure Key Vault eller miljøvariabler. Desuden skal migrations anvendes med omtanke for at undgå utilsigtede konsekvenser i produktionsdatabaser, og det anbefales at teste migrationer grundigt i testmiljøer før udrulning.

For at maksimere fordelene ved EF Core og opretholde en robust og sikker applikation, er det desuden relevant at forstå mulighederne for performanceoptimering, herunder anvendelse af tracking vs. no-tracking forespørgsler, eksplicit loading af relaterede data, og hvordan man kan håndtere store datamængder effektivt.

Hvordan sikre vi vores applikationer i en DevOps-kultur?

I dagens DevOps-kultur er kontinuerlig værdilevering og tæt samarbejde mellem teams blevet en ny standard. Denne kultur fremmer vidensdeling og fælles læring, hvilket skaber en mere dynamisk og effektiv udviklingsproces. Samtidig er et emne, der fylder mere og mere i udvikleres hverdag, sikkerhed. Sikkerhed har for længst ikke kun været et spørgsmål for cybersecurity-teams; det er nu en integreret del af alle faser af udviklingen, fra den tidlige designfase til den løbende drift af applikationer.

I takt med at både applikationer og data bliver mere værdifulde, er det essentielt at overveje sikkerheden tidligt i udviklingsprocessen. Trusler mod applikationer og håndtering af data er blevet et centralt punkt, ikke kun for udviklere, men også for virksomheder og deres kunder. Databehandlingsstandarder, som for eksempel GDPR i Europa, stiller krav om, at sikkerhed håndteres på højeste niveau, hvilket understreger betydningen af at beskytte både personlige oplysninger og virksomhedens data.

ASP.NET Core 9 er et af de værktøjer, der tilbyder flere mekanismer til at håndtere de sikkerhedsudfordringer, der opstår i moderne webapplikationer. Det er vigtigt at forstå, hvordan sikkerhedsaspekter implementeres i webapplikationer og hvordan ASP.NET Core 9 arbejder for at forhindre de mest almindelige trusler.

En webapplikation består grundlæggende af to hovedkomponenter: frontend og backend. Frontend er ansvarlig for interaktionen med brugeren, mens backend håndterer forretningslogik, kontrol og kommunikation med datalaget. Mange webapplikationer, både client-server og single-page applications (SPA), anvender en lignende arkitektur. Her ses flere komponenter, som er vigtige at forstå i forhold til sikkerhed: kommunikationsprotokoller, HTTP-headers, cookies, lokale lagringer i browseren og meget mere.

Selvom disse komponenter muliggør funktionalitet, åbner de samtidig op for en række potentielle sårbarheder. Et eksempel på dette er SQL injection, som kan opstå, hvis en udvikler laver en hurtig ændring i koden uden at tage højde for sikkerhedsaspekterne. Lad os tage et konkret eksempel. Hvis en udvikler hurtigt laver en SQL-forespørgsel ved at sammenkæde brugerinput med SQL-strenge, kan en angriber udnytte dette ved at indsætte skadelig kode i inputtet. Et simpelt eksempel kan være:

csharp
using System; using System.Data.SqlClient; public class VulnerableDataAccess { private string connectionString = "TheConnectionString";
public void GetUserData(string username)
{
string query = "SELECT * FROM Users WHERE Username = '" + username + "'"; using (SqlConnection connection = new SqlConnection(connectionString)) { SqlCommand command = new SqlCommand(query, connection); try { connection.Open(); SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { Console.WriteLine(String.Format("{0}, {1}", reader["Username"], reader["Email"])); } reader.Close(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } }

I ovenstående kode er der risiko for, at en angriber kan manipulere SQL-forespørgslen ved at ændre username-variablen. Et input som '; DROP TABLE users; -- kunne resultere i, at hele tabellen "Users" bliver slettet. Dette er et konkret eksempel på, hvordan hurtige løsninger kan føre til alvorlige sikkerhedsbrister.

For at forhindre denne type angreb bør man implementere bedste praksis som kodegennemgang og statisk kodeanalyse. Kodegennemgang sikrer, at andre medlemmer af udviklingsteamet har mulighed for at vurdere og godkende koden, inden den bliver fusioneret med hovedkoden. Dette gør det muligt at fange potentielle sikkerhedsfejl og vurdere kodekvaliteten, inden den når produktionsmiljøet. Statisk kodeanalyse, der kan automatiseres, giver en ekstra beskyttelse ved at sikre, at koden opfylder både sikkerheds- og kvalitetskriterier. Der findes flere værktøjer til statisk kodeanalyse, herunder SonarQube, som kan bruges til at identificere og rette fejl i koden, inden den deployeres.

Det er også vigtigt at forstå forskellen mellem autentificering og autorisation, to grundlæggende processer i applikationssikkerhed. Autentificering handler om at bekræfte, at en bruger er den, de udgiver sig for at være, mens autorisation handler om at give brugeren adgang til bestemte ressourcer baseret på deres rettigheder. Begge disse processer kræver sikker implementation, da fejl kan få alvorlige konsekvenser for applikationens integritet og de brugeres data, som applikationen håndterer. Et godt eksempel på dette er login-funktioner i applikationer som online banking, hvor en sikker loginproces er uundværlig. Hvis login-systemet er sårbart, kan det føre til store problemer både for brugerne og for organisationen bag applikationen.

For at sikre en høj sikkerhed i applikationer skal udviklere tage sikkerheden alvorligt fra starten af udviklingsprocessen. Det kræver, at alle aspekter – fra den indledende designfase til den daglige drift – behandles med omhu og opmærksomhed. Implementeringen af statisk kodeanalyse og kodegennemgange er væsentlige elementer, der kan reducere risikoen for sårbarheder, mens det samtidig bidrager til at skabe en kultur af sikker udvikling.