How Handle Htpasswd in NGINX

Maciej
4 min readFeb 10, 2021

By default nginx server does not come with htpasswd, but we can generate a password file with an external tool :)

Type of cryptography in htpasswd

htpasswd has multiple password protection methods as shown in the table below, except for bcrypt and SHA512 base, rest it is insecure.

Bcrypt is up to 72 characters, nginx basic authentication depends on system crypt.3 and it depends on the system whether it supports bcrypt.

There is also a patch that supports bcrypt by nginx alone regardless of the OS implementation but is unverified. Some Linux doesn’t support bcrypt, so if you want to use nginx basic authentication on your system, just use SHA512 based hashes.

SHA512 is also supported by the new version even in the Apache version of htpasswd, but if it is not supported, it can be generated with the openssl command as shown below, or it can be generated with crypt.3.

Examples:

  • For OpenSSL
  • For Python

Few words about bcrypt

A prefix that looks like this $2y$12$dNshows us the versions of bcrypt. Subsequent versions bcrypt are due to PHP and OpenBSD implementation bugs, and there is no difference in safety or performance and It can be used as htpasswd.

More information about where 2x prefix are used in BCrypt we can find in link below:

It we think about bcrypt cost, in our case prefix is $2y$12$. This $12$ is called the cost of bcrypt, or rounds, and it affects the strength of bcrypt. If we raise the value of this cost then we have:

  • Increased strength makes it more resistant to offline attacks when htpasswd data is stolen
  • On the other hand, the risk of DoS attacks increases because the consumption of computational resources increases.

Reference about bcrypt cost

Tools

This is few tools which we can use

Apache — htpasswd

htpasswd command that comes with Apache server. Apache has a default cost of 5, which is too low, so use -C to specify it explicitly as an option.

root@vagrant:/home/vagrant# htpasswd -nbB -C 12 example 'P@ssw0rd_123'
example:$2y$12$Y7A5LKaEB2uqhQuyDD.2tu0E1mSEUNF3VvoLs4YIc57IdpVaUqcCq
root@vagrant:/home/vagrant#

htpasswd in docker

Apache version of htpasswd is not distributed independently, so if you use it with nginx, it is awkward to handle, so you can also use Docker.

htpasswd in nodejs

Installation and use case:

root@vagrant:/home/vagrant# npm install -g htpasswd
/usr/local/bin/htpasswd -> /usr/local/lib/node_modules/htpasswd/bin/htpasswd
/usr/local/lib
└─┬ htpasswd@2.4.4
├─┬ apache-crypt@1.2.4
│ └── unix-crypt-td-js@1.1.4
├── apache-md5@1.1.5
├── bcryptjs@2.4.3
├── commander@2.20.3
└─┬ prompt@1.1.0
├── colors@1.4.0
├─┬ read@1.0.7
│ └── mute-stream@0.0.8
├── revalidator@0.1.8
├─┬ utile@0.3.0
│ ├── async@0.9.2
│ ├── deep-equal@0.2.2
│ ├── i@0.3.6
│ ├─┬ mkdirp@0.5.5
│ │ └── minimist@1.2.5
│ ├── ncp@1.0.1
│ └─┬ rimraf@2.7.1
│ └─┬ glob@7.1.6
│ ├── fs.realpath@1.0.0
│ ├─┬ inflight@1.0.6
│ │ └── wrappy@1.0.2
│ ├── inherits@2.0.4
│ ├─┬ minimatch@3.0.4
│ │ └─┬ brace-expansion@1.1.11
│ │ ├── balanced-match@1.0.0
│ │ └── concat-map@0.0.1
│ ├── once@1.4.0
│ └── path-is-absolute@1.0.1
└─┬ winston@2.4.5
├── async@1.0.0
├── colors@1.0.3
├── cycle@1.0.3
├── eyes@0.1.8
├── isstream@0.1.2
└── stack-trace@0.0.10
root@vagrant:/home/vagrant# htpasswd -nbBC 12 example 'P@ssw0rd_123'
example:$2a$12$ejx3AV8e38XDA6qjNe2iOO8zcKF66R8lPMu7B8Giu4NTomprpeYWy

htpasswd in PHP

To do this we will use password_hash(). More info about this function we can find in link below:

Example:

root@vagrant:/home/vagrant# wget https://gist.githubusercontent.com/spy86/cee57edd7095377775e2fa0f7581f9ce/raw/fa8f2ebcd4b3f15f44248adf029909161d4ee995/htpasswd.php
--2021-02-09 17:18:21-- https://gist.githubusercontent.com/spy86/cee57edd7095377775e2fa0f7581f9ce/raw/fa8f2ebcd4b3f15f44248adf029909161d4ee995/htpasswd.php
Resolving gist.githubusercontent.com (gist.githubusercontent.com)... 151.101.112.133
Connecting to gist.githubusercontent.com (gist.githubusercontent.com)|151.101.112.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 170 [text/plain]
Saving to: ‘htpasswd.php’
htpasswd.php 100%[===============================================================================>] 170 --.-KB/s in 0s2021-02-09 17:18:22 (7.27 MB/s) - ‘htpasswd.php’ saved [170/170]root@vagrant:/home/vagrant# php htpasswd.php
example:$2y$12$tVfoAkKgeiOuQ/hqS7ruW.kB693A59bnto9/Ty.3B6bOb9DShipU2

htpasswd in Python

To do this we will use python bcrypt module.

Example:

root@vagrant:/home/vagrant# wgethttps://gist.githubusercontent.com/spy86/f6facd1a1f95d45cf6b892d9fe99b53d/raw/5b262479d9fd552df9ce4fce240ed997798f0331/htpasswd.py^C
root@vagrant:/home/vagrant# wget https://gist.githubusercontent.com/spy86/f6facd1a1f95d45cf6b892d9fe99b53d/raw/5b262479d9fd552df9ce4fce240ed997798f0331/htpasswd.py
--2021-02-09 17:30:08-- https://gist.githubusercontent.com/spy86/f6facd1a1f95d45cf6b892d9fe99b53d/raw/5b262479d9fd552df9ce4fce240ed997798f0331/htpasswd.py
Resolving gist.githubusercontent.com (gist.githubusercontent.com)... 151.101.112.133
Connecting to gist.githubusercontent.com (gist.githubusercontent.com)|151.101.112.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 375 [text/plain]
Saving to: ‘htpasswd.py’
htpasswd.py 100%[===============================================================================>] 375 --.-KB/s in 0s2021-02-09 17:30:09 (11.8 MB/s) - ‘htpasswd.py’ saved [375/375]root@vagrant:/home/vagrant# chmod +x htpasswd.py
root@vagrant:/home/vagrant# ./htpasswd.py -C 12 example P@ssw0rd_123
example:$2b$12$zfkL1GKlWYP9lykN6cj/geUlw.SCc45CNwpi.39SWwCfHYbJ3OsTu

--

--

Maciej

DevOps Consultant. I’m strongly focused on automation, security, and reliability.