Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache user details for basic authentication #5006

Open
2 tasks done
LukeLambert opened this issue Feb 28, 2023 · 3 comments
Open
2 tasks done

Cache user details for basic authentication #5006

LukeLambert opened this issue Feb 28, 2023 · 3 comments
Labels
area/security Security related issues priority/4/normal Normal priority items status/needs-design Requires thoughtful design type/feature Request for adding a new feature

Comments

@LukeLambert
Copy link

Description

For the /api/verify?auth=basic endpoint, caching user details would considerably increase the performance of the endpoint, as Authelia would not have to fetch details from an LDAP server or calculate expensive password hashes for every request.

The key could be derived from the user credentials. e.g. hmac_sha256(username + password, secret_key)

There are a couple security tradeoffs:

  • The password hashing algorithm is downgraded. However, this hash would only live in memory.
  • Brute force attacks are faster when the credentials are cached in memory. However, regulation policies could help protect against that.

The caching feature could be opt-in behind a setting. My one-factor apps use only long, randomly-generated passwords, so I'm comfortable with the tradeoffs.

Use Case

Services like WebDAV still rely on basic auth, but the current implementation can make resource usage and request latencies impractically high.

Details

No response

Documentation

There is a similar proposal for Traefik.

Pre-Submission Checklist

  • I agree to follow the Code of Conduct
  • I have checked for related issues and checked the documentation
@LukeLambert LukeLambert added priority/4/normal Normal priority items status/needs-design Requires thoughtful design type/feature Request for adding a new feature labels Feb 28, 2023
@james-d-elliott
Copy link
Member

james-d-elliott commented Feb 28, 2023

considerably increase the performance

Could you please provide performance and resource statistics that show this.

Services like WebDAV still rely on basic auth, but the current implementation can make resource usage and request latencies impractically high.

Likewise please show empirical evidence that this is the case, and where the latency actually is.

  • Brute force attacks are faster when the credentials are cached in memory. However, regulation policies could help protect against that.

We are unlikely to accept any feature that allows this, regardless of opt-in or opt-out nature. All authentication attempts should take the same time.

@LukeLambert
Copy link
Author

The added latency is simply a feature of strong password hashing algorithms. The docs state that you should aim for 500 milliseconds of compute for each password verification. When you protect an API with basic auth, that's 500 ms of added latency for each API request. It absolutely hammers the CPU and, for some algorithms, eats tons of memory.

Below is an example demonstrating how slow the basic auth endpoint is. slowuser is using argon2id. fastuser is using pbkdf2 with sha256 and 100,000 iterations, which is the closest I could get (computationally) to my proposal using the built-in password hashers. However, since the hashed credentials would only be stored temporarily in memory, I would propose using something much, much faster for the cache key, like one iteration of sha256 or sha512. Response times would likely be single digit milliseconds.

docker-compose.yml

version: "3.8"
services:
  authelia:
    image: "authelia/authelia"
    ports:
      - "9091:9091"
    volumes:
      - "./config:/config"
    healthcheck:
      disable: true

config/configuration.yml

jwt_secret: "abcdefghijklmnopqrstuvwxyz0123456789"

authentication_backend:
  file:
    path: "/config/users_database.yml"

access_control:
  default_policy: "deny"
  rules:
    - domain: "example.com"
      policy: "one_factor"

session:
  domain: "example.com"
  secret: "abcdefghijklmnopqrstuvwxyz0123456789"

storage:
  encryption_key: "abcdefghijklmnopqrstuvwxyz0123456789"
  local:
    path: "/config/db.sqlite3"

notifier:
  filesystem:
    filename: "/config/notification.txt"

config/users_database.yml

users:
  slowuser:
    displayname: "Slow User"
    # docker run --rm authelia/authelia authelia crypto hash generate argon2 --password "password"
    password: "$argon2id$v=19$m=65536,t=3,p=4$p05U+GcQ6HSevteJ0QsqBQ$NvmN1HU5YHbFIPzrYfkoQn13d7byNlxJ1T0aO6lIiG8"
    email: "[email protected]"
    groups: [ ]
  fastuser:
    displayname: "Fast User"
    # docker run --rm authelia/authelia authelia crypto hash generate pbkdf2 --variant sha256 --iterations 100000 --password "password"
    password: "$pbkdf2-sha256$100000$VVnvAgVikboxgwzkJV.smQ$zhILFiAulTCLOGZwjGCk9fcP79fAaMM1uflGsaQSBuQ"
    email: "[email protected]"
    groups: [ ]

Slow user: argon2id

# Username: slowuser
# Password: password
hey -n 100 -c 1 \
  -H "X-Original-URL: https://example.com/" \
  -H "X-Forwarded-Method: GET" \
  -H "Authorization: Basic c2xvd3VzZXI6cGFzc3dvcmQ=" \
  "http://localhost:9091/api/verify?auth=basic"

Summary:
  Total:	12.7527 secs
  Slowest:	0.1415 secs
  Fastest:	0.1226 secs
  Average:	0.1275 secs
  Requests/sec:	7.8415
  

Response time histogram:
  0.123 [1]	|■
  0.124 [8]	|■■■■■■■■■
  0.126 [29]	|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.128 [35]	|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.130 [17]	|■■■■■■■■■■■■■■■■■■■
  0.132 [6]	|■■■■■■■
  0.134 [1]	|■
  0.136 [0]	|
  0.138 [1]	|■
  0.140 [1]	|■
  0.141 [1]	|■


Latency distribution:
  10% in 0.1246 secs
  25% in 0.1259 secs
  50% in 0.1273 secs
  75% in 0.1283 secs
  90% in 0.1303 secs
  95% in 0.1320 secs
  99% in 0.1415 secs

Details (average, fastest, slowest):
  DNS+dialup:	0.0000 secs, 0.1226 secs, 0.1415 secs
  DNS-lookup:	0.0000 secs, 0.0000 secs, 0.0003 secs
  req write:	0.0000 secs, 0.0000 secs, 0.0001 secs
  resp wait:	0.1274 secs, 0.1225 secs, 0.1407 secs
  resp read:	0.0001 secs, 0.0000 secs, 0.0001 secs

Status code distribution:
  [200]	100 responses

Faster user: pbkdf2, sha256, 100000 iterations

# Username: fastuser
# Password: password
hey -n 100 -c 1 \
  -H "X-Original-URL: https://example.com/" \
  -H "X-Forwarded-Method: GET" \
  -H "Authorization: Basic ZmFzdHVzZXI6cGFzc3dvcmQ=" \
  "http://localhost:9091/api/verify?auth=basic"

Summary:
  Total:	5.4633 secs
  Slowest:	0.0593 secs
  Fastest:	0.0540 secs
  Average:	0.0546 secs
  Requests/sec:	18.3041
  

Response time histogram:
  0.054 [1]	|■
  0.055 [59]	|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.055 [30]	|■■■■■■■■■■■■■■■■■■■■
  0.056 [3]	|■■
  0.056 [3]	|■■
  0.057 [0]	|
  0.057 [0]	|
  0.058 [1]	|■
  0.058 [2]	|■
  0.059 [0]	|
  0.059 [1]	|■


Latency distribution:
  10% in 0.0541 secs
  25% in 0.0542 secs
  50% in 0.0544 secs
  75% in 0.0547 secs
  90% in 0.0551 secs
  95% in 0.0558 secs
  99% in 0.0593 secs

Details (average, fastest, slowest):
  DNS+dialup:	0.0000 secs, 0.0540 secs, 0.0593 secs
  DNS-lookup:	0.0000 secs, 0.0000 secs, 0.0002 secs
  req write:	0.0000 secs, 0.0000 secs, 0.0001 secs
  resp wait:	0.0546 secs, 0.0540 secs, 0.0592 secs
  resp read:	0.0000 secs, 0.0000 secs, 0.0001 secs

Status code distribution:
  [200]	100 responses

Testing done on a single-CPU compute-optimized VM from Vultr.

@LukeLambert
Copy link
Author

LukeLambert commented Mar 1, 2023

For my use case (a WebDAV server), the latency and resource usage were too high. I wrote a proxy that sits in front of Authelia, queries the /api/verify?auth=basic endpoint using the website root (https://example.com/) and provided credentials, and caches the result.

The cache key is hmac_sha256(site_root + credentials, secret_key). 401 responses are cached for 60 seconds and 200 responses are cached for 300 seconds.

The proxy is very fast, but it doesn't allow for the granular access control policies that Authelia would if caching were a built-in feature.

@james-d-elliott james-d-elliott added the area/security Security related issues label Mar 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/security Security related issues priority/4/normal Normal priority items status/needs-design Requires thoughtful design type/feature Request for adding a new feature
Projects
None yet
Development

No branches or pull requests

2 participants