Indata och utdata
Den vanligaste säkerhetsbristen i dagens program är att de inte kan bearbeta data som tas emot från externa källor korrekt. Detta gäller i synnerhet användarinmatning. Du bör alltid kontrollera indata noggrant för att se till att de verifieras innan de används. Om indata inte undersöks för att identifiera potentiella attacker kan det leda till förlust eller exponering av data, rättighetsökning eller till och med körning av skadlig kod på andra användares datorer.
Tragedin i den här situationen är att det här är ett scenario som är ett enkelt problem att undvika. I den här lektionen går vi igenom hur du behandlar data när de tas emot, när de visas på skärmen och när de lagras för senare användning.
Varför behöver vi verifiera våra indata?
Anta att du skapar ett gränssnitt så att en användare kan skapa ett konto på din webbplats. Våra profildata innehåller ett namn, ett e-postmeddelande och ett smeknamn som vi visar för alla som besöker webbplatsen. Vad händer om en ny användare skapar en profil och anger ett smeknamn som innehåller vissa SQL-kommandon? Tänk till exempel om en obehörig användare anger något som liknar följande utdrag:
Eve'); DROP TABLE Users;--
Om vi utan vidare infogar det här värdet i en databas kan det potentiellt ändra SQL-instruktionen till att köra kommandon som vi absolut inte vill köra. Det här exemplet kallas ”SQL-inmatningsattacker” och är en av de många typer av kryphål som potentiellt kan utnyttjas när användarindata inte hanteras på rätt sätt. Vad kan vi då göra för att åtgärda den här situationen? I den här enheten får du lära dig när indata ska valideras, hur utdata ska kodas samt hur du skapar parametriserade frågor (vilket löser kryphålet ovan). Det här är de tre huvudsakliga försvarsteknikerna som du kan använda mot skadliga indata som matas in i dina program.
När behöver jag verifiera indata?
Svaret är alltid. Du måste verifiera alla indata till ditt program. Detta inkluderar parametrar i URL:en, indata från användaren, data från databasen, data från ett API och allt som skickas i klartext som en användare kan manipulera. Använd alltid en allowlist-metod , vilket innebär att du bara accepterar "kända bra" indata i stället för en blockeringslista (där du specifikt letar efter dåliga indata) eftersom det är omöjligt att tänka på en fullständig lista över potentiellt farliga indata. Gör detta på servern, inte på klientsidan (eller utöver klientsidan), för att säkerställa att ditt försvar inte kan kringgås. Behandla ALLA data som ej betrodda, så skyddar du dig mot de flesta vanliga sårbarheter i webbappen.
Om du använder ASP.NET ger ramverket bra stöd för validering av indata på både klient- och serversidan.
Om du använder ett annat webbramverk finns det några bra tekniker för att utföra indataverifiering på OWASP-indatavalideringsbladet.
Använd alltid parametriserade frågor
SQL-databaser används ofta för att lagra data. Ditt program kan till exempel lagra användarprofilinformation i en databas. Du bör aldrig skapa infogade SQL- eller andra databasfrågor i koden med råa användarindata och skicka dem direkt till databasen. Det här beteendet är ett recept på katastrof, som vi såg tidigare.
Skapa till exempel inte kod som i följande infogade SQL-exempel:
string userName = Request.QueryString["username"]; // receive input from the user BEWARE!
...
string query = "SELECT * FROM [dbo].[users] WHERE userName = '" + userName + "'";
Här sammanfogar vi textsträngar för att skapa frågan. Vi använder indata från användaren och genererar en dynamisk SQL-fråga för att leta upp användaren. Om en illasinnad användare inser att vi gör detta eller helt enkelt provar olika indataformat för att se om det finns en sårbarhet kan det leda till stora problem. Använd istället parametriserade SQL-instruktioner eller lagrade procedurer som den här:
-- Lookup a user
CREATE PROCEDURE sp_findUser
(
@UserName varchar(50)
)
SELECT * FROM [dbo].[users] WHERE userName = @UserName
Med den här metoden kan du anropa proceduren från koden på ett säkert sätt och skicka strängen userName
utan att behöva oroa dig för att den behandlas som en del av SQL-instruktionen.
Koda alltid dina utdata
Alla utdata som du presenterar antingen visuellt eller inom ett dokument ska alltid kodas och undantas. Detta kan skydda dig om något missades i sanitiseringspasset eller om koden oavsiktligt genererar något som kan användas skadligt. Den här designprincipen ser till att allt visas som utdata och inte oavsiktligt tolkas som något som ska köras, vilket är en annan vanlig attackteknik som kallas ”skriptkörning över flera webbplatser” (XSS).
Eftersom skydd mot XSS-attacker är ett vanligt programkrav är den här säkerhetstekniken ytterligare ett område där ASP.NET gör arbetet åt dig. Som standard är alla utdata redan kodade. Om du använder ett annat webbramverk kan du verifiera alternativen för utdatakodning på webbplatser med OWASP XSS Prevention Cheatsheet.
Sammanfattning
Att sanera och verifiera dina indata är ett nödvändigt krav för att se till att dina indata är giltiga och säkra att använda och lagra. De flesta moderna webbramverk erbjuder inbyggda funktioner som kan automatisera en del av arbetet. Du kan kontrollera dokumentationen för ditt önskade ramverk för att se vilka funktioner som erbjuds. Även om webbprogram är den vanligaste plats där det här inträffar så bör du tänka på att andra typer av program kan vara precis lika sårbara. Tro inte att du är säker för att ditt nya program är en skrivbordsapp. Du måste fortfarande hantera användarindata korrekt för att se till att någon inte använder din app för att skada dina data eller skada företagets rykte.