TipsWeb Development

Securing an application against XSS, CSRF, and SQLi attacks

Securing an application against XSS, CSRF, and SQLi attacks

XSS, CSRF, and SQLi remain among the most common attack vectors against web applications. If you’re building an application that handles user data, you’ll run into these sooner or later.

Understanding XSS attacks

Cross-Site Scripting (XSS) lets an attacker inject malicious JavaScript into a web page viewed by other users. The victim’s browser runs that script without question: as far as it’s concerned, it’s legitimate code from the site.

Stored XSS attack

There are three types of XSS: stored, reflected, and DOM-based. Stored XSS is the most problematic. The malicious script gets saved to the database (through a forum comment, a profile field...) and then executes for every user who views that data. A single poisoned forum post can hit thousands of visitors.

Enhanced security for your critical applications

Reflected XSS attack

Reflected XSS works differently: the malicious script is embedded in a URL and executed as soon as the victim clicks it. This is the classic phishing link scenario, sent by email.

DOM-based XSS attack

DOM-based XSS (Document Object Model) happens entirely on the client side. No server interaction needed: the script manipulates the page’s DOM directly through vulnerabilities in the front-end JavaScript code.

All three variants exploit the same principle: browsers trust JavaScript that runs within a page’s context. If malicious code slips in, the browser executes it like everything else.

Preventing XSS attacks

Sanitize and escape input data

Ground rule: never trust user input. Every input must be sanitized (strip out dangerous elements) and escaped (convert special characters into harmless entities before rendering). A <script> tag entered in a form should display as text, not execute.

Implement a Content Security Policy

A Content Security Policy (CSP) is an HTTP header that restricts which resources the browser can load on a page. In practice, it lets you define a whitelist of allowed sources for scripts, styles, images, and so on. An injected script from an unauthorized source gets blocked. It’s an extra layer of protection that narrows the attack surface.

Understanding CSRF attacks

Cross-Site Request Forgery (CSRF) exploits the fact that your browser automatically sends session cookies with every request to a site you’re logged into.

Here’s the typical scenario: you’re logged into your online bank. You visit another site, one rigged by an attacker. That site fires off a transfer request to your bank in the background. Your browser sends it along with your session cookie, as if you’d initiated the transfer yourself. The bank receives an authenticated request and processes it.

The core problem: the server can’t tell a legitimate request from a forged one as long as it relies solely on cookies for authentication. Any sensitive action (profile update, transaction, password change) becomes exploitable.

Preventing CSRF attacks

Anti-CSRF tokens

The most widespread defense mechanism is the anti-CSRF token. The idea: the server generates a unique token tied to the user’s session and includes it in every form (as a hidden field) or in AJAX request headers. When the request comes in, the server checks that the token matches. If it’s missing or wrong, the request gets rejected.

Django ships with this mechanism built into its CSRF middleware, which makes implementation straightforward.

HTTP headers

The SameSite attribute on session cookies is a good complement. Set it to Strict or Lax, and the browser won’t send cookies on requests originating from another site. That shuts down most CSRF scenarios.

Restricting HTTP methods

State-changing actions should never go through GET requests. A GET can be triggered by a simple image tag or a link. Reserve state modifications for POST, PATCH, or DELETE methods, which require explicit user intent.

Understanding SQLi attacks

SQL injection lets an attacker insert SQL code into an application’s input fields to manipulate the queries sent to the database. Possible consequences: reading confidential data, modifying records, dropping tables, or even taking full control of the database.

SQL fragment injection

The textbook example: entering ’ OR ‘1’=’1 in a login field. If the application concatenates that input directly into its SQL query, the condition becomes always true and the attacker gets in without a password.

Error-based injection

There are several variants. Error-based injections exploit SQL error messages to figure out the database structure. Blind injections (blind SQLi) observe the application’s behavior (response time, different responses based on a condition) to extract information bit by bit, even without visible error messages.

Preventing SQLi attacks

Use prepared statements

Parameterized queries (prepared statements) separate SQL code from user data. Instead of concatenating inputs into the query, they pass them as typed parameters. The SQL engine will never interpret them as code. This is the most direct defense against SQLi.

Adopt an ORM

ORMs (Object-Relational Mapping) add an abstraction layer between application code and the database. Developers work with objects rather than raw SQL queries, which mechanically reduces injection risk. One caveat though: most ORMs still let you write raw queries, and those remain vulnerable if inputs aren’t parameterized.

Validate input data

All data received from a user should be validated before use. A field expecting an integer should only accept an integer. An email should match an email format. This validation needs to exist on the client side (for user experience) and on the server side (for security, since client-side validation can be bypassed).

Restrict permissions

The database account used by the application should have the minimum permissions necessary. If the application only needs to read and write to certain tables, don’t give it delete or admin rights. If an injection succeeds, the damage stays limited to what that account is allowed to do.

XSS, CSRF, SQLi: these three attack families have been known for years, are well documented, and yet they still show up regularly in security audits. The protections exist and aren’t hard to implement. What’s usually missing is building them in from the start rather than bolting them on after an incident.

Ready to get started?

From scoping to prototype, to AI integration.

We support your business software projects from start to finish.

Develop my project