Get a Pentest and security assessment of your IT network.

Cyber Security

Browser Javascript & Private Keys: Security Risks

TL;DR

Storing private keys directly in browser javascript is extremely insecure. It’s a very bad idea and should be avoided at all costs. This guide explains why, and what you should do instead.

Why it’s a Bad Idea

Javascript runs on the user’s computer, meaning anyone with access to their browser (or malicious software running on it) can potentially steal your keys. Here’s a breakdown of the risks:

  • XSS Attacks: Cross-Site Scripting (XSS) allows attackers to inject malicious javascript into your website. This injected code could then access and exfiltrate your private key.
  • Keylogging: Malicious software can record keystrokes, potentially capturing keys if they are ever entered directly into Javascript code.
  • Browser Extensions: Rogue browser extensions have full access to javascript running on websites and can easily steal keys.
  • Developer Tools: Anyone can open the developer tools in their browser and view your source code, including any embedded private keys.
  • Storage Vulnerabilities: Even if you try to obfuscate or encrypt the key within Javascript, it’s likely vulnerable to being cracked or reverse-engineered.

What You Should Do Instead

Here are several much safer alternatives:

1. Use a Backend Server

  1. Store Keys on the Server: The most secure option is to store your private keys on a dedicated backend server that you control.
  2. API Access: Your Javascript code should communicate with this server via a secure API (HTTPS) to perform operations requiring the private key. Never expose the key directly to the client-side javascript.
  3. Example (Conceptual):
    // Client-Side Javascript
    fetch('/api/sign_message', {
      method: 'POST',
      body: JSON.stringify({ message: 'Your Message' }),
    }) 
    .then(response => response.json()) 
    .then(data => console.log(data.signature));
    
    // Server-Side (e.g., Node.js)
    app.post('/api/sign_message', (req, res) => {
      const message = req.body.message;
      const signature = signMessageWithPrivateKey(message);
      res.json({ signature });
    });

2. WebAuthn/Passkeys

WebAuthn allows users to authenticate using hardware security keys (like YubiKeys) or platform authenticators (fingerprint scanners, facial recognition). This avoids storing private keys in Javascript altogether.

  • Browser API: Use the Web Authentication API (https://webauthn.io/) to register and authenticate users.
  • No Key Storage: The private key never leaves the user’s device or hardware security key.

3. Secure Enclaves (WebAssembly with WASM-based cryptography)

This is a more advanced option, but can provide client-side cryptographic operations without exposing keys directly.

  • WASM Modules: Use WebAssembly modules compiled from languages like Rust or C++ that utilise secure enclave features (if available in the browser).
  • Limited Exposure: The key is still on the client, but protected within a more isolated environment. This isn’t foolproof and requires careful implementation.

4. Hardware Security Modules (HSMs)

Similar to backend servers, but using dedicated hardware for key storage and cryptographic operations.

  • Tamper-Resistant: HSMs are designed to be highly resistant to tampering and physical attacks.

Important Considerations

  • HTTPS is Essential: Always use HTTPS for all communication between your Javascript code and any backend server.
  • Regular Security Audits: Regularly audit your code and infrastructure for vulnerabilities.
  • Principle of Least Privilege: Only grant the necessary permissions to your Javascript code.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation