<?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: Shivram Sambhus</title>
    <description>The latest articles on DEV Community by Shivram Sambhus (@shividotio).</description>
    <link>https://dev.to/shividotio</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%2F640862%2F345e1b0f-6d12-4cb8-b70f-3e66bdb9ed33.jpg</url>
      <title>DEV Community: Shivram Sambhus</title>
      <link>https://dev.to/shividotio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shividotio"/>
    <language>en</language>
    <item>
      <title>Surfing the Web Like It's 1992 (Lynx Browser)</title>
      <dc:creator>Shivram Sambhus</dc:creator>
      <pubDate>Thu, 24 Jul 2025 17:49:09 +0000</pubDate>
      <link>https://dev.to/shividotio/surfing-the-web-like-its-1992-lynx-browser-f2j</link>
      <guid>https://dev.to/shividotio/surfing-the-web-like-its-1992-lynx-browser-f2j</guid>
      <description>&lt;p&gt;In an age where web browsers are practically mini operating systems, complete with GPU acceleration, sandboxed processes, and memory footprints that rival AAA games, there's something refreshing about using a browser that simply &lt;em&gt;displays content&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://lynx.browser.org/" rel="noopener noreferrer"&gt;Lynx&lt;/a&gt;, a text-based browser that's been quietly doing its job since 1992. No tabs, no ads, no JavaScript... no nonsense.&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%2F75tr6a3wl0ldva4dwxd9.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%2F75tr6a3wl0ldva4dwxd9.png" alt="Lynx Browser Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It feels genuinely nostalgic to use. Plus, there's a certain charm in telling people you browse the web from the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Lynx?
&lt;/h2&gt;

&lt;p&gt;Lynx is a terminal-based web browser that runs in plaintext environments. It supports browsing over HTTP, HTTPS, FTP, and, yes, even Gopher. Designed originally at the University of Kansas, Lynx predates many of the web's now-essential features. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It doesn't support JavaScript.&lt;/li&gt;
&lt;li&gt;It doesn't render images (though it &lt;em&gt;can&lt;/em&gt; show alternate text).&lt;/li&gt;
&lt;li&gt;It does support cookies, basic forms, and SSL.&lt;/li&gt;
&lt;li&gt;Keyboard navigation is the only way to interact with it, making it a pure text experience.&lt;/li&gt;
&lt;li&gt;It can browse Gopher sites natively, making it a rare modern tool for "&lt;a href="https://en.wikipedia.org/wiki/Gopher_(protocol)" rel="noopener noreferrer"&gt;gopherspace&lt;/a&gt;."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite its limitations, it remains one of the fastest and most resource-efficient tools for consuming written content on the web, perfect when you're SSH'ed into a server or working on legacy hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Lynx in 2025?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Speed&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Lynx is fast, not "Chrome on a new MacBook" fast, but "loads-before-you-let-go-of-Enter" fast. By skipping over images, scripts, and layout styling, pages render in milliseconds. Even modern sites like Wikipedia or plain blogs open almost instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Minimal Distractions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;No pop-ups, autoplay videos, cookie banners, modals, newsletter popovers, or "Accept our Privacy Terms" screens. Just pure HTML content and links. In Lynx, websites forget how to annoy you.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Built-in Resilience&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Lynx laughs at broken layouts, unresponsive scripts, and bloated frameworks. Most modern websites degrade into something readable when JavaScript is turned off. Lynx makes that default behavior.&lt;/p&gt;

&lt;p&gt;(That React app with 12MB of JS? Let's just say Lynx won't be impressed.)&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Works Virtually Anywhere&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Got an old ThinkPad? Raspberry Pi Zero? A VM running with 128MB RAM? Lynx runs there. As long as the system boots and has a terminal, Lynx will quietly do its job.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Privacy by Simplicity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Lynx doesn't run JavaScript, and therefore can't execute most tracking scripts, fingerprinting code, or third-party analytics. You're effectively invisible to the modern marketing stack.&lt;/p&gt;

&lt;p&gt;Cookies are optional and can be toggled off. (Yes, it asks politely.)&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Surprisingly Functional&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fill out basic forms.&lt;/li&gt;
&lt;li&gt;Follow relative and absolute links.&lt;/li&gt;
&lt;li&gt;View plain downloads and text attachments.&lt;/li&gt;
&lt;li&gt;Connect over HTTPS just fine.&lt;/li&gt;
&lt;li&gt;Customize bookmarks.&lt;/li&gt;
&lt;li&gt;Use keybindings for just about everything.&lt;/li&gt;
&lt;li&gt;Browse Gopher directories and menus, for when you want to see the web as it was before the web was the web.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sure, you can't shop on Amazon or edit Google Docs, but you &lt;em&gt;can&lt;/em&gt; read Hacker News, parse blog posts, or browse your own local HTML notes.&lt;/p&gt;

&lt;p&gt;Also, Lynx is a great way to read documentation:&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%2F61x5kj2u3e5ric5evemb.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%2F61x5kj2u3e5ric5evemb.png" alt="Lynx Browser Reading Docs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Lynx
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;On Arch Linux: &lt;code&gt;sudo pacman -S lynx&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;On Ubuntu/Debian: &lt;code&gt;sudo apt install lynx&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;On macOS (via Homebrew): &lt;code&gt;brew install lynx&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;On Windows: &lt;em&gt;I don't really know...&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basic Usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lynx example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Arrow keys move around.&lt;/li&gt;
&lt;li&gt;Enter selects a link.&lt;/li&gt;
&lt;li&gt;Left arrow goes back.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;(&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt; to jump half-page up or down.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Q&lt;/code&gt; quits.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;o&lt;/code&gt; opens options (yes, lowercase 'o').&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;/&lt;/code&gt; to search for text on a page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Customize it via &lt;code&gt;~/.lynxrc&lt;/code&gt; or &lt;code&gt;~/lynx.cfg&lt;/code&gt; to tweak privacy, rendering, and key behavior.&lt;/p&gt;

&lt;p&gt;This is mine for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ~/lynx.cfg
INCLUDE:/etc/lynx.cfg

# edits by shivi
SET_COOKIES:FALSE
ACCEPT_ALL_COOKIES:FALSE
COLOR:6:blue:black
USERAGENT:"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(yes, I set my user agent to Googlebot, don't ask why)&lt;/p&gt;

&lt;h3&gt;
  
  
  Gopher Support
&lt;/h3&gt;

&lt;p&gt;Lynx makes it simple to visit Gopher servers, just enter a Gopher URL, e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lynx gopher://gopher.floodgap.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll get the famed Gopher directory-listing interface, with classic ASCII navigation. It's the closest you can get to digital time travel in your terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quirks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No tabs. You browse one page at a time (though &lt;code&gt;tmux&lt;/code&gt; or &lt;code&gt;screen&lt;/code&gt; helps).&lt;/li&gt;
&lt;li&gt;No mouse support, arrow keys and shortcuts only.&lt;/li&gt;
&lt;li&gt;Many modern websites may not work or may be entirely blank due to reliance on JavaScript.&lt;/li&gt;
&lt;li&gt;Some HTTPS configurations (especially with modern TLS protocols) may not be compatible out of the box.&lt;/li&gt;
&lt;li&gt;It can't display PDFs, images, video, or anything that isn't basically HTML, plaintext, or Gopher content. But, you can download those files and view them on a client that supports them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But this is what makes Lynx useful. It strips away the modern web's complexity and lets you focus on the content. If you need to fill out a form or read a blog post, Lynx is there for you. It often allows you to bypass paywalls and other content restrictions that rely on JavaScript.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Rc9ajtdNn8k"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;So, there are a lot of great use cases for Lynx, especially if you want to read content quickly without distractions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Lynx is a great fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reading Wikipedia at terminal speed&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checking server status over SSH&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browsing from a headless Raspberry Pi&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quickly skimming documentation&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Digging through Gopher menus&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watching YouTube or using banking apps&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I should mention, there are other text-based browsers like &lt;a href="https://w3m.sourceforge.net/" rel="noopener noreferrer"&gt;w3m&lt;/a&gt; and &lt;a href="http://links.twibright.com/" rel="noopener noreferrer"&gt;Links&lt;/a&gt;, but I enjoy using Lynx most.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tweaks &amp;amp; Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Disable all cookies by default:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lynx &lt;span class="nt"&gt;-accept_all_cookies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;FALSE
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set a homepage:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;~/.lynxrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STARTFILE:https://duckduckgo.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set up a quick alias:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;lynxsafe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'lynx -accept_all_cookies=FALSE'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Read local documentation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lynx /usr/share/doc/bash/README
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;View man pages as HTML:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Convert a man page to HTML and open in Lynx.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# man page of ls&lt;/span&gt;
man &lt;span class="nt"&gt;-Hlynx&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="c"&gt;# yes, without a space in between -H and lynx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  DuckDuckGo Searches with Lynx + ddgr
&lt;/h2&gt;

&lt;p&gt;For a handy, privacy-friendly search workflow, you can combine Lynx with &lt;a href="https://github.com/jarun/ddgr" rel="noopener noreferrer"&gt;ddgr&lt;/a&gt;, a command-line DuckDuckGo search utility. Simply set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BROWSER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lynx
ddgr query
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ddgr will let you quickly search results and open them in Lynx, so you can zip around the web (and Gopherspace) without ever touching a graphical browser.&lt;/p&gt;

&lt;p&gt;Let me show you an example of how I use it. I use fish shell, so I added this to my &lt;code&gt;config.fish&lt;/code&gt; together with the &lt;code&gt;lynx.cfg&lt;/code&gt; file I mentioned earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/config.fish&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;search &lt;span class="nt"&gt;--wraps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ddgr'&lt;/span&gt; &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s1"&gt;'DuckDuckGo search with Lynx using custom config'&lt;/span&gt;
    &lt;span class="nb"&gt;env &lt;/span&gt;&lt;span class="nv"&gt;LYNX_CFG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/lynx.cfg &lt;span class="nv"&gt;BROWSER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lynx ddgr &lt;span class="nv"&gt;$argv&lt;/span&gt;
end

&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"search"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Lynx is not trying to compete with Chrome or Firefox (&lt;a href="https://dev.to/posts/firefox-addons-2025"&gt;that you should customize...&lt;/a&gt;). It's focused on a narrow use case: fast, reliable access to content, especially text, when every byte and cycle counts. Whether you're a sysadmin, a minimalist, or just someone who appreciates tools that do one thing well, Lynx is worth exploring.&lt;/p&gt;

&lt;p&gt;Will it replace your main browser? Probably not.&lt;/p&gt;

&lt;p&gt;Will it make you nostalgic for a simpler, quieter web? Absolutely.&lt;/p&gt;

&lt;p&gt;So give it a spin, hell you could even read this blog post in Lynx...&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%2F9wq5key3dcgg2h4qdmsr.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%2F9wq5key3dcgg2h4qdmsr.png" alt="Lynx Browser Reading This Blog"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>terminal</category>
      <category>browser</category>
      <category>lynx</category>
      <category>nostalgia</category>
    </item>
    <item>
      <title>Storing Passwords Securely - A Journey from Plain Text to Secure Password Storage</title>
      <dc:creator>Shivram Sambhus</dc:creator>
      <pubDate>Thu, 27 Jun 2024 09:31:00 +0000</pubDate>
      <link>https://dev.to/shividotio/storing-passwords-securely-a-journey-from-plain-text-to-secure-password-storage-17n8</link>
      <guid>https://dev.to/shividotio/storing-passwords-securely-a-journey-from-plain-text-to-secure-password-storage-17n8</guid>
      <description>&lt;h2&gt;
  
  
  From Plain Text to Secure Password Storage
&lt;/h2&gt;

&lt;p&gt;Password storage has come a long way since its early days as an afterthought in computing. In the past, passwords were often stored without encryption, making them vulnerable to unauthorized access. However, storing passwords securely is no longer enough; it's equally important to ensure that they're stored in a manner that limits their potential impact if compromised.&lt;/p&gt;

&lt;p&gt;In this post, we'll delve into the evolution of password storage, from its insecure origins to modern practices that prioritize user safety and security.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Naive Approach: Storing Secrets in Plain Text
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How it Works (Don't Try This at Home!)
&lt;/h3&gt;

&lt;p&gt;Imagine you're storing passwords in a database table called &lt;code&gt;users&lt;/code&gt;. Each row represents a user, and the &lt;code&gt;password&lt;/code&gt; column contains their login credentials. In this naive approach, you simply store the password as is, without any encryption or hashing.&lt;/p&gt;

&lt;p&gt;For example, if John Smith's password is "Sup3rSecure123", his entry in the &lt;code&gt;users&lt;/code&gt; table would look like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;username&lt;/th&gt;
&lt;th&gt;password&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;johnsmith&lt;/td&gt;
&lt;td&gt;Sup3rSecure123&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why This Approach is a Recipe for Disaster
&lt;/h3&gt;

&lt;p&gt;Storing passwords in plain text may seem convenient, but it's an open invitation to attackers. If an attacker gains access to your database or file system, they can simply read the password column and gain unauthorized access to all user accounts. This approach also makes it trivial for malicious insiders or developers to obtain users' passwords.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It was the 2000s, and a popular social networking site had stored its users' passwords in plain text. One day, an attacker managed to gain access to their database and stole all the passwords. The attackers then used these stolen credentials to log in to the site and steal sensitive information from millions of users.&lt;/p&gt;

&lt;p&gt;If only the developers had used hashing to store the passwords, this disaster could have been avoided. But &lt;strong&gt;they&lt;/strong&gt; didn't, and the consequences were severe. (&lt;a href="https://reusablesec.blogspot.com/2016/07/cracking-myspace-list-first-impressions.html" rel="noopener noreferrer"&gt;Myspace 2008&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Storing other sensitive information in plain text
&lt;/h3&gt;

&lt;p&gt;You should also avoid storing other sensitive information in plain text, such as API keys or access tokens in plain text in your codebase. If an attacker gains access to your source code or configuration files, they can easily extract these secrets and use them to compromise your systems. Instead, consider using secure storage solutions like environment variables, configuration files, or secret management tools to store sensitive information securely.&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%2Fs0360y82noqmu55ipd9l.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%2Fs0360y82noqmu55ipd9l.png" alt="Insecure API Keys" width="784" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hashing Passwords: A Step in the Right Direction
&lt;/h2&gt;

&lt;p&gt;You realized that storing plain text passwords isn't a good idea, so what do you do instead? The next logical step would be scrambling or "hashing" the password. Hashing is a fundamental step that can significantly improve security.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hashing... What's That?
&lt;/h3&gt;

&lt;p&gt;Imagine you're hosting a party with special guests. You want to make sure only the right people get in, so you create a secret system to check their names. You take each name and run it through a machine that scrambles the letters into a unique code. That's kind of like what hashing does for passwords!&lt;/p&gt;

&lt;p&gt;Hashing is a way to take an input (like a password) and turn it into a fixed-size output (the hashed password). It's like a secret code that can only be read one way, so you can't figure out the original password from the hashed one. There are different hashing algorithms, Sha-256 is pretty popular. It generates a 256-bit hash value, which is a long string of characters that looks like random gibberish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example
&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MyPassword&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mh"&gt;0xdc1e7c03e162397b355b6f1c895dfdf3790d98c10b920c55e91272b8eecada2a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example of an authentication system using hashing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;

&lt;span class="n"&gt;secrets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hash_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hashed_password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hash_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashed_password&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;stored_password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stored_password&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;stored_password&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;hash_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authentication successful&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authentication failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage
&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter your username: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter your password: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Hide the password input from the terminal
&lt;/span&gt;&lt;span class="nf"&gt;save_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: Authentication successful
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  You're on the Right Track, But...
&lt;/h3&gt;

&lt;p&gt;You might think that hashing is enough to keep your passwords safe, but unfortunately, there are some serious vulnerabilities lurking in the shadows. While hashing is an essential step towards securing passwords, it's not a foolproof solution on its own.&lt;/p&gt;

&lt;p&gt;One major weakness is rainbow tables, which are precomputed lists of common passwords and their corresponding hash values. If an attacker gains access to your hashed passwords, they can simply look them up in the table and recover the original password. This is known as a dictionary attack, and it's a popular way for hackers to crack hashed passwords.&lt;/p&gt;

&lt;p&gt;Another issue is collision attacks, where two different passwords produce the same hash value. Imagine having two users with the same password - if their hashed passwords are identical, an attacker can exploit this vulnerability to log in as either user using the same hash value. This is a critical security flaw that can compromise your entire authentication system.&lt;/p&gt;

&lt;p&gt;Finally, there's the threat of brute-force attacks, where powerful computers are used to try different combinations of characters until they find the right password. Even with a robust hashing algorithm like SHA-256, attackers can still use their computational power to crack hashed passwords in a relatively short amount of time.&lt;/p&gt;

&lt;p&gt;It's essential to recognize that hashing itself is not flawed, rather it's how hashing is implemented for password storage that's the problem. By combining hashing with additional security measures, you can create a more robust password storage system that keeps your users' sensitive information safe from prying eyes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Some Flavor to Your Passwords with Salting
&lt;/h2&gt;

&lt;p&gt;To address the vulnerabilities of plain hashing, you can introduce a technique called salting. Salting involves adding a unique random value to each password before hashing it. By adding a unique random value (salt) to each password before hashing, we're making it way harder for attackers to use precomputed tables or find collisions. Because who wants their passwords to be easily searchable online or accidentally match someone else's because they chose the same weak password?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;secrets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_salt&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hash_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hashed_password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hashed_password&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;salt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_salt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;stored_password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hash_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;salt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hashed_password&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;stored_password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;stored_credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stored_credentials&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;stored_credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;salt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;generate_salt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;stored_credentials&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hashed_password&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;hash_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stored_credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;salt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authentication successful&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authentication failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage
&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter your username: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter your password: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;save_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: Authentication successful
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While salting is effective in preventing collisions and defending against rainbow table attacks, it's not a foolproof solution. Modern computers can perform brute-force attacks quickly, making commonly used passwords vulnerable to extraction. For example, popular tools like Hashcat and John the Ripper can crack salted and hashed passwords by trying different combinations of characters at high speeds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expensive Algorithms
&lt;/h2&gt;

&lt;p&gt;The next logical step in securing your password storage is to use algorithms that are specifically designed to resist brute-force attacks. These algorithms are designed to be slow and computationally expensive, making it much harder for attackers to perform brute-force attacks. Some examples of such algorithms include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Argon2: A widely-used password hashing algorithm that is designed to be slow and resistant to parallelization.&lt;/li&gt;
&lt;li&gt;PBKDF2: A password-based key derivation function that uses a salt value and multiple iterations of a hash function to generate a derived key.&lt;/li&gt;
&lt;li&gt;Bcrypt: A popular password hashing algorithm that uses a combination of algorithms, including Blowfish and SHA-256.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;bcrypt&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;

&lt;span class="c1"&gt;# Generate a hash for the password "hello"
&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hashpw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gensalt&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Check if the provided password matches the stored hash
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stored_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provided_password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkpw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;provided_password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;stored_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter your password: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;check_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Password is correct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using these algorithms, you can significantly increase the time and resources required to crack hashed passwords, making it much harder for attackers to compromise your system. Bcrypt, for example, allows you to configure the cost factor, which determines how many rounds of hashing are performed. The higher the cost factor, the more computationally expensive the hashing process becomes. One hash can take hundreds of milliseconds to compute, making it much harder for attackers to crack passwords using brute-force attacks.&lt;/p&gt;

&lt;p&gt;This is the industry standard for storing passwords securely. By using a combination of salting, hashing, and expensive algorithms, you can create a robust password storage system that protects your users' sensitive information from unauthorized access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enhancing Password Security with Peppers
&lt;/h2&gt;

&lt;p&gt;Now that you've learned about salting, hashing, and expensive algorithms, you might be wondering if there are additional ways to enhance password security. Well, if you're a small startup or a personal user, the techniques we've discussed so far might be sufficient. But if you're a billion-dollar company or a government agency, you might want to consider upping your game.&lt;/p&gt;

&lt;p&gt;Let's say you're a company storing credentials to some VIP accounts - one of them is using the password "password123". If an attacker gains access to your database and wants specifically to target this VIP account, they can use a brute-force attack to crack the password, even with the expensive algorithms. It might take some time, but it's still possible.&lt;/p&gt;

&lt;p&gt;The reason this is possible is because all the information needed to validate the password is stored in the database. So what we do is add an additional variable which is not stored in the database, but is used in the hashing process. This is called a pepper.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are Peppers?
&lt;/h3&gt;

&lt;p&gt;Think of peppers as similar to salts, but with a twist. While salts are unique per user, peppers are shared across all users. This means that the pepper value is constant and not stored in the database. Instead, it's kept in a secure location, such as a configuration file or a Hardware Security Module (HSM) (more on that later).&lt;/p&gt;

&lt;p&gt;For example, let's say you have a password "MyP@ssw0rd" with a salt value of "SALT123". If you add a pepper value of "PEPPER456", your hashed password would look something like this: &lt;code&gt;hash(MyP@ssw0rd + SALT123 + PEPPER456)&lt;/code&gt;. This makes it virtually impossible for attackers to crack the password, even if they have access to the database. Without the pepper value, the hashed password is meaningless and cannot be used to validate the original password.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are Hardware Security Modules (HSMs)?
&lt;/h3&gt;

&lt;p&gt;HSMs in simple terms are specialized hardware devices that are designed to securely store sensitive information, such as encryption keys, certificates, and passwords. They provide a secure environment for cryptographic operations and can be used to protect your password hashing process from unauthorized access.&lt;/p&gt;

&lt;p&gt;In the context of password storage, you can use an HSM to securely store your pepper value, making it virtually impossible for attackers to access or tamper with it. By using an HSM, you can ensure that your pepper value remains secure and protected from unauthorized access.&lt;/p&gt;

&lt;h2&gt;
  
  
  And therefore we conclude...
&lt;/h2&gt;

&lt;p&gt;Storing passwords in plain text is amazing. I mean, who doesn't love making it easy for hackers to get their hands on sensitive info? But seriously, using expensive hashing algorithms which internally combine salting is the way to go. And if you're a big shot, you might want to consider adding a pepper to the mix and storing it in an HSM. This way, you can sleep soundly knowing that your users' passwords are safe and secure.&lt;/p&gt;

&lt;p&gt;Thanks for reading! May your passwords always remain secure... until the AI uprising, of course :D&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally posted on: &lt;a href="https://www.shivi.io/blog/password-storage" rel="noopener noreferrer"&gt;www.shivi.io/blog/password-storage&lt;/a&gt;&lt;/em&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%2Fmsrs3javkitftfzvrhx2.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%2Fmsrs3javkitftfzvrhx2.png" alt="Meme" width="500" height="651"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>webdev</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
