Browser storage mechanisms like localStorage and sessionStorage are convenient for storing data on the client side but can expose sensitive information if used improperly. This demo shows how insecure use of browser storage can lead to security issues.
Feature | localStorage | sessionStorage | Cookies |
---|---|---|---|
Persistence | Permanent until cleared | Tab session only | Configurable expiration |
Size Limit | ~5-10MB | ~5-10MB | ~4KB |
Sent with Requests | No | No | Yes (increases request size) |
HttpOnly Flag | No (always accessible to JS) | No (always accessible to JS) | Yes (can block JS access) |
Secure Flag | No | No | Yes (HTTPS only) |
SameSite Attribute | No | No | Yes (controls cross-site sending) |
This form demonstrates insecure storage of sensitive data in localStorage.
No data in localStorage yet.
Browser Console (try these commands):
> localStorage.getItem('user_credentials')
No data stored yet.
Try this: After logging in, execute localStorage.getItem('user_credentials')
in your browser console to see your saved credentials.
This form demonstrates more secure ways to store authentication data.
No data in storage yet.
Browser Console:
> localStorage.getItem('auth_token')
No data stored yet.
This demo shows how localStorage can amplify XSS attacks by storing malicious payloads that execute on every page load.
Your preferences will be applied here.
Enter these in the "Custom CSS" field:
}
to break out of the CSS context} <img src=x onerror="alert('XSS via localStorage')">
} <script>document.body.innerHTML = "Site hacked via localStorage"</script>
These payloads will be stored in localStorage and executed on every page load, amplifying the XSS attack.
This tool shows you the current contents of localStorage, sessionStorage, and cookies in your browser for this domain.
Using browser developer tools, you can inspect storage in any website:
Many websites store sensitive information in client-side storage. Always check what data is stored when performing security audits.
The safest approach is to avoid storing sensitive data in client-side storage entirely:
For authentication tokens, HttpOnly cookies offer better protection:
// Setting an HttpOnly cookie in PHP setcookie('auth_token', $token, [ 'expires' => time() + 3600, 'path' => '/', 'domain' => 'example.com', 'secure' => true, // HTTPS only 'httponly' => true, // Inaccessible to JavaScript 'samesite' => 'Strict' // No cross-site sending ]); // Setting an HttpOnly cookie in Node.js with Express res.cookie('auth_token', token, { maxAge: 3600000, httpOnly: true, secure: true, sameSite: 'strict' });
If you must store authentication data in localStorage or sessionStorage, use short-lived tokens:
// Store only short-lived tokens, not credentials localStorage.setItem('auth_token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'); // Check for token expiration before use function getStoredToken() { const tokenData = JSON.parse(localStorage.getItem('auth_token')); if (tokenData && new Date() < new Date(tokenData.expiresAt)) { return tokenData.token; } return null; // Expired or not found }
sessionStorage is cleared when the tab is closed, reducing the persistence of any sensitive data:
// Using sessionStorage instead of localStorage sessionStorage.setItem('temp_data', JSON.stringify({ userId: 123, username: 'user123', sessionExpiresAt: new Date().getTime() + (60 * 60 * 1000) // 1 hour }));
If you absolutely must store sensitive data, encrypt it before storing:
// Using the Web Crypto API to encrypt data before storage async function encryptAndStore(key, data) { const encoder = new TextEncoder(); const dataBuffer = encoder.encode(JSON.stringify(data)); // Generate a random initialization vector const iv = crypto.getRandomValues(new Uint8Array(12)); // Encrypt the data const encryptedData = await crypto.subtle.encrypt( { name: 'AES-GCM', iv }, key, dataBuffer ); // Store the encrypted data and IV localStorage.setItem('encrypted_data', JSON.stringify({ iv: Array.from(iv), data: Array.from(new Uint8Array(encryptedData)) })); }
Always validate and sanitize data when retrieving it from storage to prevent stored XSS:
// Sanitize data retrieved from storage function getSafePreference(key) { const data = localStorage.getItem(key); if (!data) return null; // Use a library like DOMPurify return DOMPurify.sanitize(data); } // Apply preferences safely document.getElementById('userPreferences').innerHTML = getSafePreference('customCSS');
Always clear stored data during logout:
function logout() { // Clear localStorage localStorage.removeItem('auth_token'); localStorage.removeItem('user_preferences'); // Clear sessionStorage sessionStorage.clear(); // Expire cookies document.cookie = 'auth_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; // Redirect to login page window.location.href = '/login'; }