Skip to content

Password Exposure Checker is a full stack web application that verifies whether a password appears in known data breaches using privacy focused SHA-1 hashing, secure range based API integration, and responsive client side updates, all without storing or transmitting the full password.

Notifications You must be signed in to change notification settings

FrankJamison/Password-Exposure-Checker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Password Exposure Checker

A small, privacy-minded web utility that checks whether a password appears in the public Have I Been Pwned (HIBP) Pwned Passwords dataset using the k‑Anonymity (Range) API.

This repo is intentionally lightweight (no database, no accounts) and is designed to run locally (Windows/XAMPP or PHP built-in server) and on typical Linux hosting.

What it does

  • Accepts a password in a simple web form.
  • Computes its SHA‑1 hash and queries HIBP using the Range API (only the first 5 hex chars of the hash prefix are sent).
  • Displays how many times the password appears in the dataset (or “not found”).

Important: this checks exposure frequency in the Pwned Passwords dataset. It does not measure general password strength.

How it works (developer overview)

Request flow:

  1. Browser submits the password to the same page (POST).
  2. index.php invokes check_password.py and passes the password as a CLI argument.
  3. check_password.py:
    • SHA‑1 hashes the password (uppercase hex)
    • sends only the first 5 characters to https://api.pwnedpasswords.com/range/{prefix}
    • compares returned suffixes locally to find a match
  4. PHP returns JSON to the browser; the UI renders the returned text.

High-level diagram:

Browser
  | POST / (password)
  v
index.php (PHP)
  | exec python check_password.py <password>
  v
check_password.py (Python)
  | GET https://api.pwnedpasswords.com/range/{first5}
  v
HIBP Range API

HTTP interface (for integration / debugging)

This is a single-endpoint app:

  • GET / returns the HTML UI.
  • POST / expects application/x-www-form-urlencoded or multipart/form-data with a password field.

Response (JSON):

  • Success: {"result": "..."} (HTTP 200)
  • Validation: {"error": "Password is required."} (HTTP 200)
  • Python execution failure: {"error": "Error running Python script."} (HTTP 500)
    • When debug is enabled, the response also includes details, exit_code, and cmd.

Tech stack

  • Frontend: HTML + CSS + vanilla JS
  • Backend (web): PHP (renders page; POST handler executes Python and returns JSON)
  • Backend (logic): Python 3 + requests (calls HIBP Range API)

Requirements

  • PHP 8.0+ (uses str_ends_with())
  • Python 3.x
  • Python package: requests

Install Python dependency:

python -m pip install requests

Local development

Option 1: PHP built-in server (fastest)

From the repo root:

php -S 127.0.0.1:30001 -t .

Then browse to:

  • http://127.0.0.1:30001/

Stop with Ctrl+C.

Option 2: Apache / XAMPP (Windows)

  1. Place the repo in your Apache document root (for XAMPP: C:\xampp\htdocs\Password-Exposure-Checker or similar).
  2. Browse:
    • http://localhost/Password-Exposure-Checker/

VirtualHost (optional)

If you prefer a dedicated hostname (e.g. passwordexposurechecker.localhost):

  1. Ensure VirtualHosts are enabled (XAMPP Apache): Include conf/extra/httpd-vhosts.conf
  2. Add a vhost entry similar to:
<VirtualHost *:80>
    ServerName passwordexposurechecker.localhost
    DocumentRoot "D:/Websites/035-2025-Password-Exposure-Checker"

    <Directory "D:/Websites/035-2025-Password-Exposure-Checker">
        Require all granted
        AllowOverride All
        Options Indexes FollowSymLinks
    </Directory>
</VirtualHost>
  1. Restart Apache.
  2. Browse:
    • http://passwordexposurechecker.localhost/

Notes:

  • Many environments resolve *.localhost to 127.0.0.1 automatically. If yours doesn’t, add a hosts entry mapping it to 127.0.0.1.

Configuration

The app is configuration-light; you can influence runtime behavior with environment variables.

PYTHON_BIN

Absolute path to the Python interpreter to use when executing check_password.py.

  • Windows example: C:\Python312\python.exe
  • Linux example: /usr/bin/python3

Why you might need it:

  • Apache service accounts often do not inherit your interactive shell PATH.
  • If not set, the app tries common defaults:
    • Windows: py -3, then searches common install paths, then python
    • Linux: /usr/bin/python3 or python3

PW_CHECKER_DEBUG

Set to 1 to include Python combined output in error JSON when Python invocation fails.

Notes:

  • For local requests (127.0.0.1 / ::1) debug is enabled automatically.
  • Do not enable this in production.

PW_ALLOW_HTTP

Set to 1 to allow HTTP requests from non-local clients.

By default, index.php will enforce HTTPS when:

  • the request is not local, and
  • the host is not localhost / *.localhost, and
  • PW_ALLOW_HTTP is not 1

If the app is behind a TLS-terminating reverse proxy, ensure it forwards X-Forwarded-Proto: https.

CLI usage (useful for development)

You can run the Python checker directly:

python check_password.py "correct horse battery staple"

This prints a human-readable message to stdout. The PHP app returns this stdout as the result JSON field.

Security & privacy notes (important for developers)

What is protected

  • The app uses HIBP k‑Anonymity: only a 5‑character SHA‑1 prefix is sent to HIBP.
  • No database is used; the app does not intentionally persist submitted passwords.

What you should still be aware of

  • The password is posted to your server; if you expose this beyond localhost, run behind HTTPS.
  • The password is passed to Python as a command-line argument.
    • On some systems, process lists / logs can expose command-line arguments.
    • If you intend to deploy this publicly, refactor to pass the password via stdin or a pipe instead of argv.
  • The current Python output prints the plaintext password back in the response.
    • Fine for a local demo; not recommended for public deployment.

Project structure

.
├─ index.php              # UI + POST handler; security headers; Python invocation
├─ check_password.py      # HIBP Range API integration
├─ js/
│  └─ app.js              # Fetches POST and renders JSON response
├─ css/
│  └─ styles.css          # Styling
└─ README.md

Troubleshooting

Python invocation fails (HTTP 500)

Common causes:

  • Python isn’t installed, or Apache can’t see it via PATH.
  • requests isn’t installed in the Python environment being used.

Fix:

  • Set PYTHON_BIN to your Python executable’s absolute path and restart Apache.
  • Install requests for that same interpreter (python -m pip install requests).

HIBP request fails

The script calls:

  • https://api.pwnedpasswords.com/range/{prefix}

If you’re offline or behind a restrictive proxy/firewall, requests may fail.

Redirects to HTTPS unexpectedly

If you’re testing from another device on your LAN (non-local request), index.php may redirect to HTTPS.

  • Recommended: serve behind HTTPS.
  • Dev-only override: set PW_ALLOW_HTTP=1.

Notes on deployment

If you deploy publicly, consider adding:

  • HTTPS end-to-end
  • rate limiting / request size limits
  • a refactor to avoid passing the password via argv and avoid echoing the password in responses

Known limitations (intentional)

  • No database, no user management.
  • Output is a simple message string; could be extended to structured status codes.

License

No license file is currently included in this repository.

About

Password Exposure Checker is a full stack web application that verifies whether a password appears in known data breaches using privacy focused SHA-1 hashing, secure range based API integration, and responsive client side updates, all without storing or transmitting the full password.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors