<?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>DEV Community: Surulere Chris. I. Abiye </title>
    <description>The latest articles on DEV Community by Surulere Chris. I. Abiye  (@suruabiye).</description>
    <link>https://dev.to/suruabiye</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%2F1136089%2Fd8a6385f-6a3a-42ca-a756-63cba137e4f7.jpeg</url>
      <title>DEV Community: Surulere Chris. I. Abiye </title>
      <link>https://dev.to/suruabiye</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/suruabiye"/>
    <language>en</language>
    <item>
      <title>I Audited a Node.js Project and Found SHA-256 Password Hashing. Here's What I Changed.</title>
      <dc:creator>Surulere Chris. I. Abiye </dc:creator>
      <pubDate>Tue, 09 Jun 2026 10:27:56 +0000</pubDate>
      <link>https://dev.to/suruabiye/i-audited-a-nodejs-project-and-found-sha-256-password-hashing-heres-what-i-changed-3291</link>
      <guid>https://dev.to/suruabiye/i-audited-a-nodejs-project-and-found-sha-256-password-hashing-heres-what-i-changed-3291</guid>
      <description>&lt;h1&gt;
  
  
  I Audited a Node.js Project and Found SHA-256 Password Hashing. Here's What I Changed.
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Or how a simple code audit turned into an authentication upgrade.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Quick Summary&lt;/li&gt;
&lt;li&gt;The Discovery&lt;/li&gt;
&lt;li&gt;What Was Actually Wrong?&lt;/li&gt;
&lt;li&gt;A Surprise Bonus Finding&lt;/li&gt;
&lt;li&gt;Why SHA-256 Isn't Ideal for Passwords&lt;/li&gt;
&lt;li&gt;What Modern Recommendations Say&lt;/li&gt;
&lt;li&gt;Why I Chose bcrypt Instead of Argon2id&lt;/li&gt;
&lt;li&gt;The Migration Challenge&lt;/li&gt;
&lt;li&gt;Building a Seamless Upgrade Path&lt;/li&gt;
&lt;li&gt;Before vs After&lt;/li&gt;
&lt;li&gt;Security Improvements Achieved&lt;/li&gt;
&lt;li&gt;Lessons Learned&lt;/li&gt;
&lt;li&gt;Final Thoughts&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Recently, I was working on a Node.js project and decided to spend some time reviewing parts of the codebase before moving forward with new features.&lt;/p&gt;

&lt;p&gt;I've found that some of the most valuable improvements don't come from adding new functionality. They come from revisiting old decisions and asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If I were building this today, would I still do it this way?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before diving in, I should mention that I'm not a security engineer. I'm a software developer who takes security seriously and tries to follow current best practices when building applications.&lt;/p&gt;

&lt;p&gt;While reviewing a Node.js project recently, I came across a password hashing implementation that used SHA-256. The code wasn't necessarily broken, but after researching modern password-storage recommendations, I realized there was an opportunity to improve it. That investigation eventually led me to migrate the application to bcrypt.&lt;/p&gt;

&lt;p&gt;What started as a quick review of the authentication flow ended up becoming a complete authentication hardening exercise.&lt;/p&gt;




&lt;h1&gt;
  
  
  Quick Summary
&lt;/h1&gt;

&lt;p&gt;During this audit, I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replaced SHA-256 password hashing with bcrypt (12 rounds)&lt;/li&gt;
&lt;li&gt;Implemented automatic password upgrades during login&lt;/li&gt;
&lt;li&gt;Replaced Base64-encoded session tokens with signed JWTs&lt;/li&gt;
&lt;li&gt;Added access and refresh token support&lt;/li&gt;
&lt;li&gt;Introduced token expiration and verification&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  The Discovery
&lt;/h1&gt;

&lt;p&gt;As I followed the authentication flow through the application, I noticed that a single &lt;code&gt;hashPassword()&lt;/code&gt; helper was being used across the system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User registration&lt;/li&gt;
&lt;li&gt;User login&lt;/li&gt;
&lt;li&gt;Password changes&lt;/li&gt;
&lt;li&gt;User creation and updates&lt;/li&gt;
&lt;li&gt;Seed scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation looked roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hashPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app_name_salt_2024&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this doesn't look terrible.&lt;/p&gt;

&lt;p&gt;Passwords weren't stored in plain text.&lt;/p&gt;

&lt;p&gt;A salt was being used.&lt;/p&gt;

&lt;p&gt;Everything appeared to work.&lt;/p&gt;

&lt;p&gt;So what's the problem?&lt;/p&gt;




&lt;h1&gt;
  
  
  What Was Actually Wrong?
&lt;/h1&gt;

&lt;p&gt;The issue wasn't that SHA-256 is insecure.&lt;/p&gt;

&lt;p&gt;SHA-256 is still an excellent cryptographic hash function.&lt;/p&gt;

&lt;p&gt;The issue is that password storage is a completely different problem.&lt;/p&gt;

&lt;p&gt;There was also another detail hiding in plain sight:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app_name_salt_2024&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That salt was static.&lt;/p&gt;

&lt;p&gt;Every single user password was hashed using the same salt.&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users with identical passwords generate identical hashes&lt;/li&gt;
&lt;li&gt;Every account shares the same hashing strategy&lt;/li&gt;
&lt;li&gt;The benefits of salting are significantly reduced&lt;/li&gt;
&lt;li&gt;If the database is leaked, attackers have a much easier target than they would with unique salts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation wasn't broken.&lt;/p&gt;

&lt;p&gt;But it definitely wasn't where I wanted it to be.&lt;/p&gt;




&lt;h1&gt;
  
  
  A Surprise Bonus Finding
&lt;/h1&gt;

&lt;p&gt;While reviewing the password implementation, I stumbled across something else.&lt;/p&gt;

&lt;p&gt;The application's "tokens" looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JwtPayload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;iat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first I laughed.&lt;/p&gt;

&lt;p&gt;Then I stopped laughing.&lt;/p&gt;

&lt;p&gt;Then I realized this code was probably written to solve a problem quickly, and nobody had revisited it since.&lt;/p&gt;

&lt;p&gt;Because technically it worked.&lt;/p&gt;

&lt;p&gt;But Base64 is encoding, not security.&lt;/p&gt;

&lt;p&gt;Anyone could decode the token, modify it, re-encode it, and potentially impersonate another user.&lt;/p&gt;

&lt;p&gt;So while my original goal was improving password security, I ended up modernizing the token implementation as well.&lt;/p&gt;

&lt;p&gt;More on that later.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why SHA-256 Isn't Ideal for Passwords
&lt;/h1&gt;

&lt;p&gt;One thing that surprised me when I started learning more about authentication security is this:&lt;/p&gt;

&lt;p&gt;A secure hash function does not automatically mean secure password storage.&lt;/p&gt;

&lt;p&gt;SHA-256 was designed to be fast.&lt;/p&gt;

&lt;p&gt;For file verification, digital signatures, checksums, and integrity checks, that's fantastic.&lt;/p&gt;

&lt;p&gt;For passwords?&lt;/p&gt;

&lt;p&gt;Not so much.&lt;/p&gt;

&lt;p&gt;Imagine an attacker gets a copy of your database.&lt;/p&gt;

&lt;p&gt;Modern hardware can calculate enormous numbers of SHA-256 hashes every second.&lt;/p&gt;

&lt;p&gt;That's exactly what attackers want.&lt;/p&gt;

&lt;p&gt;Dedicated password hashing algorithms intentionally slow this process down.&lt;/p&gt;

&lt;p&gt;The slower password verification becomes, the more expensive brute-force attacks become.&lt;/p&gt;

&lt;p&gt;And that's exactly what we want.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Modern Recommendations Say
&lt;/h1&gt;

&lt;p&gt;Today, password storage recommendations generally point developers toward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Argon2id&lt;/li&gt;
&lt;li&gt;bcrypt&lt;/li&gt;
&lt;li&gt;PBKDF2&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unlike SHA-256, these algorithms are specifically designed for password hashing.&lt;/p&gt;

&lt;p&gt;They provide features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configurable work factors&lt;/li&gt;
&lt;li&gt;Automatic salting&lt;/li&gt;
&lt;li&gt;Increased resistance to brute-force attacks&lt;/li&gt;
&lt;li&gt;Better protection against modern hardware&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Argon2id is generally considered the current gold standard.&lt;/p&gt;

&lt;p&gt;If I were building a completely new authentication system from scratch today, that's probably where I'd start.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why I Chose bcrypt Instead of Argon2id
&lt;/h1&gt;

&lt;p&gt;While researching these options, I realized the challenge wasn't choosing the "best" algorithm on paper.&lt;/p&gt;

&lt;p&gt;It was choosing the best option for the project's current environment.&lt;/p&gt;

&lt;p&gt;This was actually the part that took the most thought.&lt;/p&gt;

&lt;p&gt;My first choice was Argon2id.&lt;/p&gt;

&lt;p&gt;After evaluating the application's infrastructure and performance requirements, however, I decided to migrate password hashing to bcrypt.&lt;/p&gt;

&lt;p&gt;Not because bcrypt is better.&lt;/p&gt;

&lt;p&gt;Not because Argon2id is bad.&lt;/p&gt;

&lt;p&gt;But because engineering decisions are often about practicality.&lt;/p&gt;

&lt;p&gt;I wanted a solution that would:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work well in the current environment&lt;/li&gt;
&lt;li&gt;Require minimal deployment changes&lt;/li&gt;
&lt;li&gt;Be easy to maintain&lt;/li&gt;
&lt;li&gt;Provide a significant security improvement immediately&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;bcrypt checked all those boxes.&lt;/p&gt;

&lt;p&gt;I settled on a cost factor of 12.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BCRYPT_ROUNDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hashPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BCRYPT_ROUNDS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One thing I particularly like about bcrypt is that it automatically generates a unique salt for every password.&lt;/p&gt;

&lt;p&gt;No manual salt management.&lt;/p&gt;

&lt;p&gt;No shared salt values.&lt;/p&gt;

&lt;p&gt;No accidental mistakes.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Migration Challenge
&lt;/h1&gt;

&lt;p&gt;Switching algorithms was easy.&lt;/p&gt;

&lt;p&gt;Migrating users was not.&lt;/p&gt;

&lt;p&gt;Password hashes are one-way functions.&lt;/p&gt;

&lt;p&gt;You can't simply convert:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SHA-256 Hash → bcrypt Hash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user's original password is required.&lt;/p&gt;

&lt;p&gt;At this point I had two options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 1
&lt;/h2&gt;

&lt;p&gt;Force everybody to reset their password.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 2
&lt;/h2&gt;

&lt;p&gt;Build a migration path.&lt;/p&gt;

&lt;p&gt;I chose Option 2.&lt;/p&gt;




&lt;h1&gt;
  
  
  Building a Seamless Upgrade Path
&lt;/h1&gt;

&lt;p&gt;The solution was a helper called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;verifyAndUpgradePassword&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The logic is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User logs in&lt;/li&gt;
&lt;li&gt;Check whether the stored hash is bcrypt&lt;/li&gt;
&lt;li&gt;If it is, verify normally&lt;/li&gt;
&lt;li&gt;If it's SHA-256:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Verify using the legacy method&lt;/li&gt;
&lt;li&gt;Generate a bcrypt hash&lt;/li&gt;
&lt;li&gt;Update the database&lt;/li&gt;
&lt;li&gt;Continue login&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;verifyAndUpgradePassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;storedHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storedHash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;storedHash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oldHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;LEGACY_SALT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldHash&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;storedHash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BCRYPT_ROUNDS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;updatedHash&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ended up being my favorite part of the migration.&lt;/p&gt;

&lt;p&gt;No password reset emails.&lt;/p&gt;

&lt;p&gt;No support tickets.&lt;/p&gt;

&lt;p&gt;No downtime.&lt;/p&gt;

&lt;p&gt;Users simply log in as usual and get upgraded automatically.&lt;/p&gt;




&lt;h1&gt;
  
  
  Before vs After
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Before
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;SHA-256 password hashing&lt;/li&gt;
&lt;li&gt;Static salt&lt;/li&gt;
&lt;li&gt;Base64 encoded tokens&lt;/li&gt;
&lt;li&gt;No token signatures&lt;/li&gt;
&lt;li&gt;No token expiration&lt;/li&gt;
&lt;li&gt;No migration strategy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  After
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;bcrypt password hashing&lt;/li&gt;
&lt;li&gt;Unique salt per password&lt;/li&gt;
&lt;li&gt;bcrypt cost factor of 12&lt;/li&gt;
&lt;li&gt;Signed JWTs using HS256&lt;/li&gt;
&lt;li&gt;15-minute access tokens&lt;/li&gt;
&lt;li&gt;7-day refresh tokens&lt;/li&gt;
&lt;li&gt;Cryptographic token verification&lt;/li&gt;
&lt;li&gt;Token expiration&lt;/li&gt;
&lt;li&gt;Automatic password upgrades&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Looking at it side-by-side, the difference is quite significant.&lt;/p&gt;




&lt;h1&gt;
  
  
  Security Improvements Achieved
&lt;/h1&gt;

&lt;p&gt;The migration delivered several immediate improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unique Salts
&lt;/h2&gt;

&lt;p&gt;Each password now receives its own salt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Better Brute Force Resistance
&lt;/h2&gt;

&lt;p&gt;bcrypt is intentionally slow.&lt;/p&gt;

&lt;p&gt;Attackers hate that.&lt;/p&gt;

&lt;p&gt;Developers love that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adjustable Security
&lt;/h2&gt;

&lt;p&gt;The cost factor can be increased as hardware improves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stronger Authentication
&lt;/h2&gt;

&lt;p&gt;JWTs are now signed and verified cryptographically rather than simply encoded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Better User Experience
&lt;/h2&gt;

&lt;p&gt;Users never had to reset their passwords.&lt;/p&gt;




&lt;h1&gt;
  
  
  Lessons Learned
&lt;/h1&gt;

&lt;p&gt;The biggest lesson from this experience wasn't that SHA-256 is bad.&lt;/p&gt;

&lt;p&gt;It wasn't.&lt;/p&gt;

&lt;p&gt;The lesson was that authentication code tends to sit untouched for years simply because it works.&lt;/p&gt;

&lt;p&gt;Once login works, developers rarely revisit it.&lt;/p&gt;

&lt;p&gt;But security recommendations evolve.&lt;/p&gt;

&lt;p&gt;Hardware evolves.&lt;/p&gt;

&lt;p&gt;Attack techniques evolve.&lt;/p&gt;

&lt;p&gt;Periodically revisiting old decisions can reveal opportunities for meaningful improvements without requiring a complete rewrite.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;One thing I enjoy about reviewing existing code is discovering areas where small improvements can have a big impact.&lt;/p&gt;

&lt;p&gt;The original implementation wasn't malicious.&lt;/p&gt;

&lt;p&gt;It wasn't reckless.&lt;/p&gt;

&lt;p&gt;It worked.&lt;/p&gt;

&lt;p&gt;But after spending time understanding the trade-offs and modern recommendations, I felt there was a better approach.&lt;/p&gt;

&lt;p&gt;Would I choose Argon2id for a brand-new project today?&lt;/p&gt;

&lt;p&gt;Probably.&lt;/p&gt;

&lt;p&gt;Was bcrypt the right choice for this project's current environment?&lt;/p&gt;

&lt;p&gt;Absolutely.&lt;/p&gt;

&lt;p&gt;As developers, we don't need to be security experts to make better security decisions.&lt;/p&gt;

&lt;p&gt;Sometimes all it takes is curiosity, a willingness to question old assumptions, and a desire to leave the codebase a little better than we found it.&lt;/p&gt;

&lt;p&gt;The most interesting thing about this audit wasn't discovering SHA-256. It was realizing how easy it is for security-related code to remain unchanged for years simply because it works. Authentication code is often written once and rarely revisited. Taking time to periodically review those decisions can reveal opportunities for meaningful improvements without requiring major architectural changes.&lt;/p&gt;

&lt;p&gt;For me, this audit started with SHA-256.&lt;/p&gt;

&lt;p&gt;It ended with a stronger authentication system, a smoother migration strategy, and a reminder that "working" and "secure" aren't always the same thing.&lt;/p&gt;

</description>
      <category>node</category>
      <category>security</category>
      <category>sha256</category>
    </item>
    <item>
      <title>A Django Tale: Outsmarting the Port Predicament</title>
      <dc:creator>Surulere Chris. I. Abiye </dc:creator>
      <pubDate>Wed, 09 Aug 2023 14:03:21 +0000</pubDate>
      <link>https://dev.to/suruabiye/a-django-tale-outsmarting-the-port-predicament-1kbm</link>
      <guid>https://dev.to/suruabiye/a-django-tale-outsmarting-the-port-predicament-1kbm</guid>
      <description>&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;Once upon a time, in the bustling world of web development, a passionate developer named Suru(Yeah, that’s me) or Chris to some people. So, I was on this big mission to create a revolutionary web application using Django (A python framework).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After winning the battle of self doubt and procrastination, I was armed to teeth with the knowledge of Python and a vision, I embarked on the coding adventure, eager to conquer the digital realm.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, as I fired up the Django development server, an unexpected hurdle appeared: “Error: You don’t have permission to access that port.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 1: The Port Paradox
&lt;/h2&gt;

&lt;p&gt;I was perplexed but undeterred, I knew that the error meant another process had taken over port 8000 — the default port Django uses. It was like an apartment with no entrance door! Frowning at the screen, and I pondered on my next line of action which is the first step to victory.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After giving it much thought, I realized there are two ways to fix this!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Chapter 2: The Crafty swerve (Changing to Another Port)
&lt;/h2&gt;

&lt;p&gt;I decided to act on the first steps which is to outwit the predicament by changing to another port — 8001, that sounds like a great choice right? Armed with determination, and without much ado I swiftly ran the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Windows
python manage.py runserver 8001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lo and behold, the Django development server came alive, and the web application was now accessible on port 8001. Success!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: You should use a dedicated virtual environment for each new Python project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Chapter 3: The Mighty Conqueror(Terminating the Current Process)
&lt;/h2&gt;

&lt;p&gt;The second method is to find and terminate the process using the port. I will not explain why you should or not terminate a process, but, if there’s need to terminate the process, you can do so. Open your terminal and run the below code&lt;/p&gt;

&lt;p&gt;For Windows, open terminal with Win + R, type cmd to open terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Windows
netstat -ano | findstr :8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;taskkill /PID 12345&lt;br&gt;
Note: Replace 12345 with the port ID using the port you wish to replace.&lt;/p&gt;

&lt;p&gt;For Linux/macOS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Identify the process using port 8000
lsof -i :8000

# Kill the process using port 8000 (replace &amp;lt;PID&amp;gt; with the actual process ID)
kill &amp;lt;PID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conclusion: A Big Victory&lt;br&gt;
The story “A Django Tale: Outsmarting the Port Predicament”, teaches us that as we journeyed through software development, there are bound to be challenges that’ll want to make us quit, but, we should remember, that they just stepping stones to greatness.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have insights, better ways, or suggestions, I wholeheartedly encourage you to share them. Let’s make this space a collaborative one where ideas flourish, and knowledge is freely exchanged. Together, we’ll not only master the art of software development but also uncover the limitless possibilities technology offers.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>terminal</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
