Saved Browser Passwords - 夜莺博客

Saved Browser Passwords

原文:Saved Browser Passwords — theDXT (Daniel Keer)

It’s super convenient to save your passwords to your web browser but it isn’t very secure. In this post, I will show you step-by-step how to easily reveal a saved browser password.

Normally if you want to view a saved password you need to go into settings and click on it, then enter the password of the logged-in user account to view it. This isn’t always true, let me show you how to get around this.

This article expands that demonstration into the full picture: why the trick works, what it means for a threat model, how each browser actually stores the credentials it saves for you, and — more usefully — what to do about it. If you manage endpoints, there is a section on enterprise browser policy; if you are just trying to make your own laptop safer, jump to the hardening checklist near the end.

Why the Trick Works

The browser’s password manager has two quite different jobs, and it is their separation that makes this demonstration possible.

Job one is storage. When you tell Chrome, Edge or Firefox to remember a credential, it writes it to a local store: an encrypted SQLite database on Chromium browsers, and logins.json protected by a key database on Firefox. The browser needs those records to be recoverable without you typing anything, because the whole point of saving a password is that you never have to type it again.

Job two is presentation - and it decides who sees what. The stored credential flows into the page field only after the browser has decided it should. By default that decision happens without a prompt if the page matches the recorded origin. That is why autofill is silent: it is a deliberate usability feature, not a bug.

The demonstration in this article does not attack the encrypted store at all. It attacks the last step: the browser has already handed the credential to the DOM, the input element contains the plaintext, and the type attribute is the only thing stopping it from being displayed. Change one attribute value and the field renders the value it already holds. Nothing was decrypted, nothing was bypassed, no password was cracked - the browser did exactly what it was configured to do, and you simply removed the cosmetic mask.

The developer-tools access in a browser is the important second half. Anyone who can open DevTools on a page where the credential autofilled can read it, unless the browser profile itself is locked behind an operating-system credential. On an unattended and unlocked machine, that means the password is effectively in the clear.

The Process

  • Go to any website that has the login credentials saved.

Image 2

  • Right-click on the password field and select inspect or just inspect the whole page.

Image 3

  • Find the line for the password field this should show up as type="password"

Image 4

  • Change type="password" to be type="text"

Image 5

  • Look at the password field and it is now in plaintext.

Image 6

Many websites that have the show password icon work exactly like this.

View the source code the next time you toggle the show password option and you may see it change the type from password to text in real time.

Image 7

Two details are worth noting about the sequence above. First, the page must have autofilled for this to reveal anything - the browser only puts the saved credential into the field if it recognises the origin and the form. Second, nothing is written back to the site: this is a local change to your own browser’s copy of the page, so no server-side log records it and no notification fires.

The developer tools in Chrome and Edge allow editing the DOM directly in the Elements panel; in Firefox the same edit is possible in the Inspector. In both cases the change applies to the rendered page only - reload and the mask is back, which is exactly why this is a physical-access risk rather than a remote one.

Doing It From the Console Instead of the Inspector

The attribute edit is the most readable version, but the same information is available from the JavaScript console on the page, which is faster if you are auditing several fields. Select the field and ask the DOM what it currently holds:

// reveal every field on the page that is currently masked
document.querySelectorAll('input[type="password"]').forEach(el => {
  el.type = 'text';
  el.style.border = '2px solid red';
});

To read the value without touching the rendering at all — useful on a page whose layout you do not want to disturb:

document.querySelector('input[type="password"]').value
// returns the autofilled plaintext credential, e.g. "Summer2026!"

On a modern Chromium build, most site scripts can no longer read the value straight out of from a password field without a prior user gesture, and browsers restrict reading clipboard contents. Neither restriction is relevant here: DevTools is a first-party context with full page privileges, so it can read and write the DOM freely. That asymmetry is the whole lesson of this article - the protections you can see from a web page are not protections against someone who already has a session on your machine.

How Browsers Actually Store Saved Passwords

Understanding the storage layer is what makes the risk assessment concrete, and it is well documented because every major browser publishes its design.

Chromium-family browsers (Chrome, Edge, Brave, Opera). Saved logins live in a SQLite database in the browser profile directory - Login Data on Windows, and Login Data inside the profile folder on macOS and Linux. The password column is encrypted with a key that is itself protected by the operating system: on Windows, DPAPI, which ties the key to your user account; on macOS, the system Keychain. On Windows the database can therefore be decrypted by any process running as your user account, which is why an unattended unlocked session is the weak point. The profile folder also holds Local State (the encrypted key material) and the rest of your browsing state.

Firefox. Credentials are stored in logins.json in the profile directory, encrypted with a key stored in key4.db. If you set a Primary Password, that key is additionally derived from a password you type, so nobody can decrypt the store without it - which is precisely why the Primary Password setting matters. Without it, the key database alone is enough for anyone with file access.

Safari. Credentials are stored in the macOS Keychain and protected by the login keychain, so the operating system account password is the gate.

Read across those three and a pattern appears: every one of them is designed to protect against a different user or a stolen disk, and none of them is designed to protect against someone who is already logged in as you. Full-disk encryption plus a screen lock is what turns "someone plugged in a USB drive" into a non-event; it does nothing at all against a colleague sitting down at your unlocked desk.

It Is Not Only the Login Form

The same class of exposure shows up wherever a browser saves something on your behalf, and the login page is only the most obvious case:

  • Autofill profiles. Chromium and Firefox will fill name, address, phone and email into any form that looks like a checkout - and those values are visible in the DOM exactly the same way.
  • Card data. Saved payment details are gated behind an OS prompt before they are released, which is a deliberate difference from logins. That is the model everyone else should copy.
  • Saved Wi-Fi and VPN credentials. On Windows, netsh wlan show profile name="CORP" key=clear prints the pre-shared key for a stored wireless profile from a normal command prompt. On macOS the equivalent secrets live in the System keychain and require an unlock.
  • Browser sync. If you sign the browser into a sync account, every saved credential is also on the vendor’s servers and on every other device you signed in - a single point of failure multiplied by however many devices that is.

Those four lines explain most real-world credential leaks on managed laptops: the secret was never stolen from the server, it was sitting on the endpoint in a place the owner thought was protected.

Who Can Actually Do This? A Threat Model

Being precise about the attacker keeps the fix proportionate:

  • Someone with 30 seconds of physical access to an unlocked machine. The highest-probability case in an office, a shared lab bench, a demo room or a conference. They need no tools, no privilege and no malware - only the article you are reading.
  • Local malware running as your user. No interaction required. It can read the same stores, with the same limits: DPAPI-bound on Windows and Keychain-bound on macOS, so it works as your account and fails when the device is locked or the profile is not there.
  • A shared or hand-me-down computer. A profile that was never wiped still contains credentials for whoever used it previously. This is a common finding on second-hand laptops and on machines recycled between staff.
  • Someone with your disk. Blocked by full-disk encryption, which is why FileVault and BitLocker are baseline requirements and not optional.
  • A remote attacker with no access to the endpoint. Not affected by any of this. Their credential-theft path is phishing, password reuse and breach dumps - a different problem, with different defences.

Notice that the browser itself is not the weak link in the first three cases. The unlocked session is.

Enterprise Controls for Browser Password Managers

At fleet scale you do not rely on individual users to get this right; you configure it. All of the major browsers read an administrative policy file or registry key, and Chromium browsers share almost the same policy names:

# Windows registry (Chromium: Chrome / Edge / Brave)
# HKLM\SOFTWARE\Policies\Google\Chrome
PasswordManagerEnabled        = 0   ; disable saving passwords in the browser
AutofillCreditCardEnabled     = 0   ; block card autofill outside the approved manager
BrowserSignin                 = 0   ; block sync, keep credentials off vendor cloud
PasswordManagerBlocklist      = ['*']  ; block the built-in manager for all origins
# macOS managed preferences (Chrome)
defaults write com.google.Chrome PasswordManagerEnabled -bool false
defaults write com.google.Chrome BrowserSignin -int 0
# Firefox (policies.json in the distribution directory)
{ "policies": { "PasswordManagerEnabled": false, "OfferToSaveLogins": false } }

The three settings that do most of the work are: disable the built-in manager, force the credentials into an enterprise password manager instead, and disable browser sync so that saved credentials are never replicated to a personal account you do not control. Enforce the policy so users cannot override it, and monitor the same signal from your endpoint management tool - a device that reports the built-in manager disabled is a verified configuration, not a hope. Where authentication is centralised, the identity side matters too: a directory service such as RADIUS or TACACS+ for AAA gives you a single place to revoke access, and a consistent Microsoft 365 sign-in page makes the phishing side of credential theft easier for users to spot.

Defences That Actually Help

This shows how important it is to use things like a password manager. Multifactor authentication can provide some protection against this by adding another factor before a successful login but, nothing is perfect. It might even be worth starting the exploration of migrating towards passwordless authentication.

Ordered by effort against benefit, the defences that matter are:

  1. Lock the screen. Every one of the physical-access scenarios above collapses the moment the session is locked and requires a credential to resume. Short idle timeout, lock on lid close, and never leave a workstation unlocked in a shared space.
  2. Turn on full-disk encryption. FileVault, BitLocker or the Linux equivalent. This closes the lost-laptop case completely.
  3. Use a dedicated password manager. A manager whose vault is unlocked by a master secret you type - not merely by your OS session - separates "someone is at my keyboard" from "someone has my passwords". Use the browser extension with autofill rather than saving into the browser itself.
  4. Stop reusing passwords. Storage exposure on the endpoint is survivable if that credential is unique to one site; it is catastrophic if the same password opens your email, your bank and your employer’s VPN.
  5. Turn on multi-factor authentication everywhere it is offered. MFA does not stop the local reveal - the attacker reads the password, not the second factor - but it does stop the password from being immediately useful, and it is the only control that helps against the phishing case as well. Prefer app-based or hardware factors over SMS.
  6. Move to passkeys where supported. A passkey is a private key that never leaves the device’s secure hardware, so there is no plaintext to display in a browser field. This is the durable answer to the class of problem in this article, and it is progressively available on the sites that matter most.
  7. Give Firefox a Primary Password if you save credentials there at all, and enable a master password equivalent wherever the browser offers one.

Hardening Checklist You Can Run Today

Concrete actions, in the order that gives the best coverage per minute spent:

# 1. See what your Chromium browser has stored (Windows)
#    Settings then Autofill and passwords then Password Manager
#    Use "Checkup" to flag weak and reused passwords

# 2. See what macOS has in your login keychain
security dump-keychain -d ~/Library/Keychains/login.keychain-db | grep -i "svce" | head -50

# 3. Check stored Wi-Fi keys on Windows
netsh wlan show profiles
netsh wlan show profile name="CORP-SSID" key=clear

# 4. Export nothing, delete what you do not need
#    browser settings, Password Manager, remove stale entries for old employers and old sites

# 5. Confirm disk encryption
# Windows:  manage-bde -status C:
# macOS:    fdesetup status

Then close the loop on the identity side: change any password that you found in a browser store and have since reused anywhere else, starting with email. An email account is the reset path for everything else, so it is always the first credential to rotate and the first one to protect with a hardware key.

Frequently Asked Questions

Is this a browser vulnerability? No, and that is the uncomfortable part. The behaviour described here is a consequence of autofill working as designed. The type attribute is presentation, not access control, and DevTools is by definition a privileged context. The browser vendors cannot really fix this without breaking autofill, which is why the fix belongs at the endpoint and identity layers.

Does this work in Firefox or Safari too? The type="password" edit is a DOM operation, so it works in any browser that has autofilled the field. Firefox has an additional layer - a Primary Password can protect the stored key database - but once the credential is in the page, the field behaves the same. Safari gates the reveal differently but the DOM is still the DOM.

Can a website do this to my visitors? A page can read the value of a password field it controls, which is why browsers restrict scripts from reading fields the user has not interacted with, and why phishing kits that try to auto-exfiltrate autofilled credentials are unreliable. The realistic defence remains: check the origin before you log in, and let the password manager - not the page - decide where a credential may be filled.

Does an incognito window protect saved passwords? No. Incognito prevents new history and cookie writes; if you choose to autofill a credential in that window, it is in the page exactly as before.

Should I stop saving passwords in the browser completely? Not necessarily - save them in a purpose-built manager instead, and keep the browser’s built-in store empty. Convenience is legitimate; convenience without a lock on the vault is not.

What if I have already been exposed? Assume the credential in question is known. Rotate it, rotate anything it was reused on, enable MFA, and check the account’s recent sign-in history for sessions you do not recognise. For network devices with local accounts, the same logic applies and the recovery path is the console or the password-recovery procedure for that platform, such as the Huawei S5700 password recovery guide.

The Takeaway

Revealing a saved browser password takes fewer than ten seconds and no tools beyond the developer console the browser ships with. That does not make browsers bad software; it makes the assumption "my session is mine alone" load-bearing. Lock the screen, encrypt the disk, move credentials into a manager that asks for a master secret, turn on MFA, and adopt passkeys where they are available. Do those five things and this demonstration stops being a story about your accounts.

Related reading on this site: Microsoft 365 sign-in page branding, RADIUS vs TACACS+ for Cisco AAA, and diagnosing TLS certificate chain problems with OpenSSL.

原文链接:https://thedxt.ca/2024/02/saved-browser-passwords/