Preface: Why Security is Not an Option, but Basic Hygiene
\n\nImagine: you are writing a cool web service in C#. Everything works perfectly — users register, leave comments, search for products. And then "hacker Vasya" (who actually just copied a script from the internet) shows up — and dumps the entire database. Or, even worse, injects a script into your page that steals cookies from all visitors.
\n\nSounds like a horror movie scenario? Yet this happens every day. According to OWASP statistics, injections (SQL, XSS, LDAP) are among the top 3 most dangerous web application vulnerabilities. And C#, for all its reliability, does not give you an immunity shield by default.
\n\nIn this article, we will break down the two hottest attacks — SQL injections and XSS (Cross-Site Scripting). You will get not just theory, but battle-tested protection techniques in C# with real code examples. Let's go!
\n\nSQL Injections: When the User Becomes a Hacker
\n\nWhat It Looks Like in Practice
\n\nLet's say you have a simple login system. The user enters a login and password, and you form the query like this:
\n\nstring login = txtLogin.Text;\nstring password = txtPassword.Text;\nstring query = "SELECT * FROM Users WHERE Login = '" + login + "' AND Password = '" + password + "'";\nSqlCommand cmd = new SqlCommand(query, connection);\n\nLooks logical? Mistake! If an attacker enters into the login field: ' OR 1=1 --, the query turns into:
SELECT * FROM Users WHERE Login = '' OR 1=1 --' AND Password = '...'\n\nEverything after -- is a comment. The condition 1=1 is always true. The query returns all users, and authentication is bypassed. And what if instead of a comment, they insert DROP TABLE Users? Goodbye, database.
Defense #1: Parameterized Queries (Your Main Shield)
\n\nThe best defense against SQL injections is to never concatenate strings manually. Use parameters. The SQL server will escape dangerous characters itself, and your database receives data as values, not as code.
\n\nstring login = txtLogin.Text;\nstring password = txtPassword.Text;\n\nstring query = "SELECT * FROM Users WHERE Login = @Login AND Password = @Password";\n\nusing (SqlConnection conn = new SqlConnection(connectionString))\n{\n SqlCommand cmd = new SqlCommand(query, conn);\n cmd.Parameters.AddWithValue("@Login", login);\n cmd.Parameters.AddWithValue("@Password", password);\n \n conn.Open();\n SqlDataReader reader = cmd.ExecuteReader();\n // process the result\n}\n\nNote: @Login and @Password are parameters. Even if the user enters '; DROP TABLE Users; --, the DBMS will treat it as an ordinary string, not as code. Safe and elegant.
Defense #2: Stored Procedures
\n\nAnother powerful tool is stored procedures. They not only protect against injections but also improve performance (query plans are cached).
\n\n-- SQL Server\nCREATE PROCEDURE GetUserByLogin\n @Login NVARCHAR(50)\nAS\nBEGIN\n SELECT * FROM Users WHERE Login = @Login\nEND\n\n// C# code\nusing (SqlConnection conn = new SqlConnection(connectionString))\n{\n SqlCommand cmd = new SqlCommand("GetUserByLogin", conn);\n cmd.CommandType = CommandType.StoredProcedure;\n cmd.Parameters.AddWithValue("@Login", inputLogin);\n \n conn.Open();\n // ...\n}\n\nDefense #3: Entity Framework and ORM
\n\nIf you are using Entity Framework (or any other ORM), you are already partially protected. EF generates parameterized queries automatically. But there is a nuance: raw SQL queries via EF (the FromSqlRaw method) — this is the same concatenation. Be vigilant!
// BAD:\nvar users = context.Users.FromSqlRaw("SELECT * F