How can I secure my web application against SQL Injection and Cross-Site Scripting (XSS) attacks?

usman alam 0 Reputation points
2026-11-11T16:18:05.0733333+00:00

Hello everyone,

I am developing a web application that allows users to register, log in, and submit data through forms. Before deploying it to production, I want to make sure it is protected against common web security threats.

I would like to know the best practices for preventing:

  • SQL Injection (SQLi)
  • Cross-Site Scripting (XSS)
  • Cross-Site Request Forgery (CSRF)
  • Unauthorized access to sensitive data

I am currently using:

  • Backend: Node.js / Express
  • Database: MySQL
  • Frontend: React What security measures, libraries, or design patterns would you recommend for building a secure production-ready application?

Thank you for your guidance.

Microsoft Security | Microsoft Defender | Microsoft Defender for Cloud
0 comments No comments

2 answers

Sort by: Most helpful
  1. Marcin Policht 113.2K Reputation points MVP Volunteer Moderator
    2026-11-11T18:27:56.1766667+00:00

    Focus on the following measures:

    SQL Injection (SQLi): Use parameterized queries with mysql2 or a secure ORM such as Prisma. Never concatenate user input into SQL statements. Validate inputs and use a MySQL account with minimum required permissions.

    const [rows] = await pool.execute(
      'SELECT * FROM users WHERE id = ?',
      [req.params.id]
    );
    

    Cross-Site Scripting (XSS): React automatically escapes values rendered through JSX. Avoid dangerouslySetInnerHTML with untrusted content. Use DOMPurify when rendering user-submitted HTML and Helmet to configure a Content Security Policy (CSP).

    Cross-Site Request Forgery (CSRF): For cookie-based authentication, use CSRF tokens with a library such as csrf-csrf. Configure cookies with HttpOnly, Secure, and SameSite=Lax or Strict. Validate Origin headers and restrict CORS to trusted frontend domains.

    Unauthorized Access: Implement server-side authorization for every API endpoint. Use role-based access control (RBAC) where necessary and ensure users can only access their own records. Hash passwords using Argon2id or bcrypt. Use secure session management, MFA for administrators, and rate limiting with express-rate-limit.

    Additional production safeguards to consider: Use HTTPS, store secrets in environment variables or a secrets manager, restrict MySQL network access, validate requests with Zod or express-validator, avoid exposing stack traces, and regularly scan dependencies using npm audit.

    Recommended packages:

    • mysql2: Parameterized SQL queries
    • helmet: Security headers
    • express-rate-limit: Brute-force protection
    • zod: Input validation
    • argon2: Password hashing
    • express-session: Session management
    • csrf-csrf: CSRF protection
    • dompurify: HTML sanitization

    For a React SPA with an Express backend hosted under the same domain, I would favor server-side sessions with secure cookies over implementing a custom JWT authentication system.

    OWASP's Cheat Sheet Series provides practical implementation guidance for these controls.


    If the above response helps answer your question, remember to "Accept Answer" so that others in the community facing similar issues can easily find the solution. Your contribution is highly appreciated.

    hth

    Marcin

    Was this answer helpful?

    0 comments No comments

  2. AI answer

    2026-11-11T16:19:13.83+00:00

    Build the application around parameterized MySQL queries, safe React rendering, explicit CSRF protection for cookie-authenticated requests, and server-side authorization on every protected resource; add Azure WAF only as a production defense-in-depth layer.

    1. Prevent SQL injection

    • Use prepared statements or parameterized queries for every value received from forms, URLs, headers, or APIs. Parameters keep external values separate from SQL syntax.^1^
    • Never construct SQL with string concatenation or template literals.
    • Validate type, length, format, and range on the Express server. React validation improves usability but can be bypassed.^2^
    • SQL parameters cannot represent identifiers such as column names or ASC/DESC. Map those values through a fixed allowlist.
    • Give the application's MySQL account only the required permissions—normally no schema-administration or global privileges.

    Example using a MySQL driver that supports placeholders:

    app.post('/api/profile', async (req, res, next) => {
      try {
        const email = String(req.body.email ?? '').trim();
        if (email.length < 3 || email.length > 254) {
          return res.status(400).json({ error: 'Invalid email' });
        }
    
        const [rows] = await pool.execute(
          'SELECT id, email FROM users WHERE email = ? LIMIT 1',
          [email]
        );
        res.json(rows[0] ?? null);
      } catch (error) {
        next(error);
      }
    });
    

    Return a generic error to clients and log an internal correlation ID—not SQL text, connection strings, passwords, or sensitive parameter values. Detailed database exceptions can expose information useful for probing attacks.^1^

    2. Prevent XSS

    Treat form fields, query parameters, headers, API responses, and database content as untrusted.

    • Render user content as text with normal React interpolation, such as <p>{comment}</p>.
    • Do not build markup with innerHTML, document.write(), or untrusted string concatenation.
    • Avoid dangerouslySetInnerHTML. If rich HTML is a requirement, sanitize it with a maintained HTML sanitizer using a restrictive allowlist before rendering.
    • Encode for the destination context: HTML text, HTML attribute, URL, and JavaScript contexts require different handling. Input validation alone does not replace output encoding.^3^
    • Add a Content Security Policy (CSP) that limits permitted script, style, image, frame, and connection sources. Avoid unsafe-inline and unsafe-eval; they significantly weaken CSP.^4^
    • Add standard security headers through maintained Express middleware such as Helmet, then test the resulting CSP against the production React build.

    CSP is a secondary containment layer, not a substitute for safe rendering and sanitization. It controls which resources a page may load or execute and helps limit XSS and clickjacking.^5^

    3. Prevent CSRF

    The correct design depends on how authentication is transported:

    • Session/authentication cookie: require an unpredictable anti-CSRF token on every state-changing POST, PUT, PATCH, and DELETE; validate it server-side. Set the session cookie to Secure, HttpOnly, and preferably SameSite=Lax or Strict.
    • Cross-site application requiring SameSite=None: the cookie must also be Secure, and anti-CSRF token validation remains necessary.
    • Never change server state through GET.
    • Check Origin or Fetch Metadata headers as an additional control, not as the only defense.
    • Restrict CORS to known frontend origins. CORS is not CSRF protection.

    Browsers automatically attach cookies to eligible requests, which creates the CSRF risk. SameSite mitigates many attacks but should be combined with anti-forgery protection for cookie-authenticated applications.^6^

    Bearer [Token] manually placed in an Authorization header are less exposed to traditional CSRF, but browser storage accessible to JavaScript can be stolen through XSS. Do not choose token storage solely to avoid implementing CSRF defenses.

    4. Prevent unauthorized data access

    Authentication identifies the caller; authorization determines whether that caller may perform the requested operation.

    • Apply authentication middleware to every protected API route.
    • Authorize each operation server-side by role, permission, tenant, and resource ownership.
    • Query resources using both the requested identifier and the authorized owner/tenant identifier. Do not fetch by ID and assume that possession of the ID grants access.
    • Default to deny, return 403 for authenticated-but-forbidden requests, and avoid exposing whether another user's resource exists.
    • Hash passwords with a vetted adaptive password-hashing library; never encrypt or store plaintext passwords.
    • Rate-limit login, password-reset, registration, and other abuse-sensitive endpoints.
    • Rotate sessions after login or privilege changes, expire them appropriately, and invalidate them at logout.
    • Keep production database credentials and signing secrets out of source control and client-side React code.

    If hosted in Azure, store production secrets in Azure Key Vault and grant the workload only the minimum required RBAC permissions. Managed identities remove embedded credentials when the target Azure service supports them.^7^

    5. Production hardening

    • Enforce HTTPS and secure cookies.
    • Set strict request-body size limits and accepted content types.
    • Keep Node.js and dependencies patched; run dependency and static-analysis checks in CI.
    • Avoid logging passwords, tokens, cookies, authorization headers, or personal data.
    • Record authentication failures, authorization denials, administrative actions, and suspicious request rates.
    • Test access-control boundaries and malicious inputs in automated integration tests.

    For a public Azure-hosted application, place Azure WAF on Azure Front Door or Application Gateway in front of it. WAF can detect HTTP-layer attacks including SQL injection and XSS, but it does not replace parameterized queries, encoding, authorization, or CSRF controls.^8^ Tune rules with representative traffic, switch production to Prevention mode, send diagnostics to Log Analytics, scrub sensitive log fields, and prevent clients from bypassing Front Door by reaching the origin directly.^8^

    Use the OWASP Node.js, SQL injection, XSS, and CSRF cheat sheets as the implementation checklist for code review and release gates.^9^


    References

    1. Secure data access
    2. SQL injection
    3. Prevent Cross-Site Scripting (XSS) in ASP.NET Core
    4. Unsafe-inline and unsafe-eval - Microsoft Q&A
    5. Glossary
    6. Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks in ASP.NET Core
    7. Secure your Azure Key Vault
    8. Web Application Firewall for Azure networks (cross-cloud)
    9. Introduction - OWASP Cheat Sheet Series
    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.