<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Eden</title>
    <description>The latest articles on Forem by Eden (@eande171).</description>
    <link>https://forem.com/eande171</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3861026%2F71b94582-0dc7-4382-ab4d-4a3bb7d35e27.png</url>
      <title>Forem: Eden</title>
      <link>https://forem.com/eande171</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/eande171"/>
    <language>en</language>
    <item>
      <title>How HaveIBeenPwned Checks Your Password Without Ever Seeing It</title>
      <dc:creator>Eden</dc:creator>
      <pubDate>Fri, 17 Apr 2026 13:54:09 +0000</pubDate>
      <link>https://forem.com/eande171/how-haveibeenpwned-checks-your-password-without-ever-seeing-it-1244</link>
      <guid>https://forem.com/eande171/how-haveibeenpwned-checks-your-password-without-ever-seeing-it-1244</guid>
      <description>&lt;p&gt;Maybe you've seen "check if your password has been breached" features scattered across the web. Maybe you've used &lt;a href="https://haveibeenpwned.com" rel="noopener noreferrer"&gt;haveibeenpwned.com&lt;/a&gt; yourself.&lt;/p&gt;

&lt;p&gt;But there's an uncomfortable question sitting under all of it... how does a breach checking service verify your password against a database of billions of leaked credentials without you just... handing them your password?&lt;/p&gt;

&lt;p&gt;The naive implementation would just be awful. You send your password to a server, the server checks it against a list, the server tells you the result. Congratulations! You've just handed a third party your plaintext password to "solve" a security problem.&lt;/p&gt;

&lt;p&gt;I'm sure we both know the issue with that (at least I hope I do...).&lt;/p&gt;

&lt;p&gt;The way HIBP does it is actually rather clever, and worth understanding. Both as a user and as a developer building anything that touches authentication.&lt;/p&gt;




&lt;h2&gt;
  
  
  Overview of K-Anonymity
&lt;/h2&gt;

&lt;p&gt;K-anonymity is a privacy concept that's been around since the late nineties. A piece of data satisfies k-anonymity if it's indistinguishable from at least k-1 other pieces of data. In other words, you can't be singled out from a crowd of at least k people.&lt;/p&gt;

&lt;p&gt;The classic example is medical records. If you release a dataset where every patient shares their age, postcode, and gender with at least k-1 other patients in the set, no individual record can be uniquely identified. The data is still useful, but the individuals are still protected.&lt;/p&gt;

&lt;p&gt;Unfortunately, k-anonymity is susceptible to homogeneity attacks (where all k people share sensitive information, revealing a group) and background knowledge attacks (where an attacker uses additional information to narrow possibilities).&lt;/p&gt;

&lt;p&gt;HIBP applies this same idea to password checking, and their implementation is surprisingly straightforward. Luckily for us, our passwords on HIBP aren't nearly as susceptible to these weaknesses.&lt;/p&gt;




&lt;p&gt;Before we get into how, it's worth understanding what HIBP is. Troy Hunt (creator of HIBP) has spent years collecting password data from data breaches (like RockYou, LinkedIn or Adobe). All of these entries have been hashed, indexed and made queryable. The issue then becomes: "How do you check this data without exposing your own password?"&lt;/p&gt;

&lt;p&gt;When you want to check if a password has appeared in a breach, you don't send the password. You don't even send a full hash of the password. You send the first five characters of its SHA-1 hash.&lt;/p&gt;

&lt;p&gt;Say your password hashes to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(in this case the password is &lt;code&gt;password&lt;/code&gt;... don't judge I needed a good example)&lt;/p&gt;

&lt;p&gt;You send &lt;code&gt;5BAA6&lt;/code&gt; to the HIBP range API. HIBP responds with every hash suffix in their database that starts with those five characters, along with a count of how many times each one appeared in breach data.&lt;/p&gt;

&lt;p&gt;You get back something like a list of hundreds of entries:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4i87t34hsq74o4gql5wa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4i87t34hsq74o4gql5wa.png" alt="A screenshot of a few entries HaveIBeenPwned returns" width="640" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You then check whether your full hash suffix (&lt;code&gt;1E4C9B93F3F0682250B6CF8331B7EE68FD8&lt;/code&gt;) appears in that list. If it does, and the count next to it is greater than zero, that password has been in a breach. The count tells you how many times.&lt;/p&gt;

&lt;p&gt;The privacy guarantee here is k-anonymity. Any given 5-character SHA-1 prefix matches hundreds to thousands of different hashes in the HIBP dataset. HIBP's server receives your prefix and has no way of knowing which of those hashes you actually care about. Neither your password, nor its hash, ever leave your computer.&lt;/p&gt;

&lt;p&gt;It's important to be honest here though... this method isn't perfect. You still end up sending the first 20 bits of your hash. There are 16^5 (~1 million) possible prefixes, so you often end up narrowing the results down to a couple hundred. This is a reasonable trade-off, but it certainly isn't perfect. It's k-anonymity, not zero-knowledge.&lt;/p&gt;




&lt;h2&gt;
  
  
  Isn't SHA-1 Broken?
&lt;/h2&gt;

&lt;p&gt;SHA-1 is indeed a "broken" hashing algorithm (proven to be feasibly susceptible to hash collisions). For digital signatures, certificates and authentication, this is a serious problem.&lt;/p&gt;

&lt;p&gt;In this use case though, it's not really important. You're not trying to store or protect this password on their servers. SHA-1 provides exactly what is required; a consistent, one way transformation to a fixed length string. K-anonymity is what's actually doing the privacy work, nobody is trying to reverse the hash or forge a hash collision.&lt;/p&gt;

&lt;p&gt;That being said, &lt;em&gt;never&lt;/em&gt; use SHA-1 (or any fast or broken hash) to &lt;em&gt;store&lt;/em&gt; passwords (I'm looking at you). That's what bcrypt, scrypt, and Argon2 are for. The HIBP use case and the password storage use case are different problems with different requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  In Practice
&lt;/h2&gt;

&lt;p&gt;Checking if passwords have been exposed in a breach is becoming an increasing concern, including organisations like &lt;strong&gt;NIST&lt;/strong&gt; (the National Institute of Standards and Technology), that recommend checking new passwords against these breach lists.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;shameless self promotion&lt;/em&gt;. This is the mechanism behind the breach detection in &lt;a href="https://eande171.github.io/bastion" rel="noopener noreferrer"&gt;Bastion&lt;/a&gt;, the API I built. When you send a password to the endpoint, it is hashed on the worker, and only sends the first 5-characters of the SHA-1 hash to HIBP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9agce95ajkct2hbhf0kv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9agce95ajkct2hbhf0kv.png" alt="A screenshot of the Bastion demo testing out the password: " width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Checking out the free &lt;a href="https://eande171.github.io/bastion/demo" rel="noopener noreferrer"&gt;demo&lt;/a&gt;, or supporting me on &lt;a href="https://ko-fi.com/eande171" rel="noopener noreferrer"&gt;Ko-Fi&lt;/a&gt; would mean the world to me :D Thank you for reading this far!!&lt;/p&gt;




&lt;p&gt;If you're building anything that touches user credentials, breach checking via the range API (or my own &lt;em&gt;COUGH COUGH&lt;/em&gt;) is low-effort, high-value. There's no excuse not to.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>privacy</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why Your Signup Form Is Less Secure Than You Think (And How to Fix It)</title>
      <dc:creator>Eden</dc:creator>
      <pubDate>Wed, 08 Apr 2026 04:22:00 +0000</pubDate>
      <link>https://forem.com/eande171/why-your-signup-form-is-less-secure-than-you-think-and-how-to-fix-it-3m3f</link>
      <guid>https://forem.com/eande171/why-your-signup-form-is-less-secure-than-you-think-and-how-to-fix-it-3m3f</guid>
      <description>&lt;p&gt;You've seen those password rules. &lt;em&gt;"Must be more than 8 characters. Must include a symbol. Must contain a number."&lt;/em&gt; They have good intentions, but have one fatal flaw. Us.&lt;/p&gt;

&lt;p&gt;You would hope everyone uses something more than "&lt;code&gt;P@ssword1&lt;/code&gt;" (or any of its many variants), but unfortunately, you'd be wrong.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4a1su87rodk0xjl54h5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4a1su87rodk0xjl54h5b.png" width="800" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo of the&lt;/em&gt; &lt;a href="https://eande171.github.io/bastion/demo/" rel="noopener noreferrer"&gt;&lt;em&gt;Bastion Demo&lt;/em&gt;&lt;/a&gt; &lt;em&gt;that shows the password: "P@ssword1" being included in 442,781 known breaches.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So what is actually happening, and what can we do about it?&lt;/p&gt;




&lt;p&gt;These "traditional" password rules weren't &lt;em&gt;wrong&lt;/em&gt; to exist, but they focus on the wrong thing. Primarily, they focus on what makes a password &lt;em&gt;look&lt;/em&gt; complex, rather than what a machine considers "complex".&lt;/p&gt;

&lt;p&gt;That'd be fine, except most attacks don't work that way. Most passwords susceptible to this are brute forced, rather than recreated from over your shoulder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NIST&lt;/strong&gt; (the National Institute of Standards and Technology) actually updated their guidelines recently, recommending longer minimum lengths and preventing the use of common, expected and compromised passwords.&lt;/p&gt;

&lt;p&gt;Most people, understandably (my younger self included), took shortcuts, prioritising short, simple passwords (usually for memorisation) over complexity.&lt;/p&gt;

&lt;p&gt;Now databases are littered with these "valid", but trivial passwords that can take machines minutes, if that, to crack (obviously this is still better than NO rules... "&lt;code&gt;123456&lt;/code&gt;" has been found an embarrassingly large number of times in breaches).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6qrb1vx3rznpw6lbb385.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6qrb1vx3rznpw6lbb385.png" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo of the&lt;/em&gt; &lt;a href="https://eande171.github.io/bastion/demo/" rel="noopener noreferrer"&gt;&lt;em&gt;Bastion Demo&lt;/em&gt;&lt;/a&gt; &lt;em&gt;that shows the password: "123456" being included in 209,972,844 known breaches.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What we &lt;strong&gt;actually&lt;/strong&gt; want to measure is the complexity of guessing (or brute forcing) said password, which is a very different problem.&lt;/p&gt;




&lt;p&gt;zxcvbn (I only just realised now, while writing this, that it's the bottom row of the QWERTY keyboard... never clicked when I was using it for the API ;-;) was built by Dropbox and takes a very different approach to password strength. Rather than checking for these rules, it uses more complex pattern matching to estimate the number of guesses it would take to crack a password.&lt;/p&gt;

&lt;p&gt;zxcvbn checks against things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Most common passwords, names, and dates&lt;/li&gt;
&lt;li&gt;  Keyboard patterns (&lt;code&gt;qwerty&lt;/code&gt;, &lt;code&gt;123456&lt;/code&gt;, and even &lt;code&gt;zxcvbn&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;  Common substitutions (&lt;code&gt;@&lt;/code&gt; for &lt;code&gt;a&lt;/code&gt; or &lt;code&gt;3&lt;/code&gt; for &lt;code&gt;e&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;  Repeating/reversed characters or strings (&lt;code&gt;aaabbbccc&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is a score, crack times against multiple scenarios (throttled online, offline fast hash, etc.), as well as warnings and suggestions for weaker passwords.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bad password example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frc75mm1fhj0l0lmim29g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frc75mm1fhj0l0lmim29g.png" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo of the&lt;/em&gt; &lt;a href="https://eande171.github.io/bastion/demo/" rel="noopener noreferrer"&gt;&lt;em&gt;Bastion Demo&lt;/em&gt;&lt;/a&gt; &lt;em&gt;that shows the password: "P@ssword1" being included in 442,781 known breaches. It also shows the estimated crack time ranging from 4 days to less than a second. Below that is a warning with a list of suggestions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good password example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdjoz4pxkrvw7t5z60a2x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdjoz4pxkrvw7t5z60a2x.png" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo of the&lt;/em&gt; &lt;a href="https://eande171.github.io/bastion/demo/" rel="noopener noreferrer"&gt;&lt;em&gt;Bastion Demo&lt;/em&gt;&lt;/a&gt; &lt;em&gt;that shows the password: "correct-horse-battery-staple" being included in no known breaches. It also shows the estimated crack time ranging from centuries to 57 years.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  In Practice:
&lt;/h2&gt;

&lt;p&gt;Here's what it looks like to actually check a password against an API that uses zxcvbn:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST https://bastion.eande171.workers.dev/v1/evaluate 
BODY { "password": "P@ssword1" }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Weak"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"entropy_bits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;13.425215903299385&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"crack_times"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"online_throttled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4 days"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"online_unthrottled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"18 minutes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"offline_slow_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1 second"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"offline_fast_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"less than a second"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"warning"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is similar to a commonly used password."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"suggestions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Add another word or two. Uncommon words are better."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Capitalization doesn't help very much."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Predictable substitutions like '@' instead of 'a' don't help very much."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This response gives you a lot of information to work with. The &lt;code&gt;score&lt;/code&gt; and &lt;code&gt;strength&lt;/code&gt; fields give you a numerical and human-readable version of the password strength.&lt;/p&gt;

&lt;p&gt;An attacker with throttled attempts would find this password in 4 days (likely because the form would start rejecting too many attempts). This drops to 18 minutes without any throttling, and if they got access to the database, they could calculate it in no time at all.&lt;/p&gt;

&lt;p&gt;The warning and suggestion fields are an addition given to weak passwords to give users clear, actionable feedback to improve the quality of their passwords.&lt;/p&gt;

&lt;p&gt;This can be compared to a password (or passphrase), which is just a little bit longer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST https://bastion.eande171.workers.dev/v1/evaluate 
BODY { "password": "correct-horse-battery-staple" }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Very Strong"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"entropy_bits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"crack_times"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"online_throttled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"centuries"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"online_unthrottled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"centuries"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"offline_slow_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"centuries"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"offline_fast_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"57 years"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"warning"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"suggestions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fills me with much more confidence, knowing that even if someone did get access to a database, it would take them 57 years (or possibly centuries) to crack it (unless it's stored in plain text... but that's a separate issue- although just as bad).&lt;/p&gt;




&lt;p&gt;Password rules certainly aren't useless, but genuine protection requires measuring complexity, not enforcing arbitrary rules. zxcvbn (still can't believe I didn't get that) gives you a way to do that without reinventing the wheel.&lt;/p&gt;

&lt;p&gt;Unfortunately, this is only one half of the problem... what happens if a password is strong but is already in a breach? &lt;em&gt;It's more common than you think.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If any of you made it to this bit... THANK YOU!!! If you want to poke around the API I made for this &lt;strong&gt;exact&lt;/strong&gt; purpose, you can find it &lt;a href="https://eande171.github.io/bastion" rel="noopener noreferrer"&gt;here.&lt;/a&gt; It would really mean a lot if you could check it out (even just the free/demo versions).&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>api</category>
      <category>cybersecurity</category>
    </item>
  </channel>
</rss>
