Summary
Today, the Security Plugin stores user authentication information (username/password for basic or access/refresh tokens for token, saml, oidc etc.) in the cookie that gets stored in the users browser. This cookie is encrypted with two-way encryption using a salt based on the xpack.security.encryptionKey in the kibana.yml.
This approach has a number of benefits (e.g. easy to scale) and drawbacks (e.g. we're hitting browser cookie size limit more and more). But more importantly, there are number of use cases we cannot really handle with the current approach, like #18162 or #53478.
This issue proposes using a more secure approach - maintaining server-side sessions in the Kibana backend. Instead of putting the encrypted authentication information in the cookie, the cookie would contain an encrypted session ID, which the server side would generate on first authentication, and store it alongside with all additional information in the Elasticsearch index. After session expiration (see below) or on explicit logout, it would be removed.
Where to store session information?
Since we started to discourage Kibana administrators from giving users access to .kibana index we can safely (to be assessed) use this index to store session information. Alternatively we can use a dedicated index similar to .security-tokens index used by Elasticsearch.
We'd likely want to store the session information in an encrypted form. Either leveraging xpack.security.encryptionKey for all sessions or separate unique keys for every session that'd be stored in the cookie, we'll need to find an acceptable security-performance trade-off. If we use single encryption key we may want to throw some AAD into the mix.
When to clean up session information?
We can implement a number of optimizations to not overburden Kibana server with the session management, for example when user explicitly logs out or Kibana decides to do that on its own we'd not only remove this specific session, but also all other sessions that have expired (based on xpack.security.session.idleTimeout and xpack.security.session.lifespan settings).
In addition to that we can leverage TaskManager to schedule a periodic 24h task to do the cleanup as well.
Also we may want to just mark sessions as deleted and physically delete them later for audit purposes.
What fields session information should include?
These are the first that come into my mind:
- Version (e.g. to properly handle migration scenarios)
- Creation/removal/last-access timestamps (e.g. for audit purposes)
- User and Elasticsearch realm names (e.g. to limit concurrent sessions)
- Provider type and name (for internal Kibana purposes)
- The flag that tells whether it's an intermediate (e.g. used during SAML handshake) or final session
- [Optional] URL that initiated log in (may go to the miscellaneous data field for the realms that actually use that data instead)
- Miscellaneous data field (e.g. username/password for
basic, access/refresh token pair for saml or certificate fingerprint for pki)
Concerns
There are a number of concerns regarding Server-Side session comparing to the current approach:
- Performance:
- Additional request to retrieve session information for every request that requires authentication
- Decryption of the session information in addition to cookie content decryption for every request that requires authentication
- Increase of
.kibana index size (only if we decide to use existing .kibana index)
- Security (only if we decide to use existing
.kibana index):
- Potential leakage of the sensitive information during
.kibana index backup
- Users with direct access to
.kibana index can drop user sessions (not swap or alter though)
- Complexity:
- We need to specifically handle the case when multiple requests try to initiate login at the same time (e.g. when
pki or kerberos is used we can receive multiple "login" requests at the same time and we'll only figure out that they belong to the same user only after we talk to Elasticsearch that would issue different access tokens for both requests)
- There is a chance we may need help from the Elasticsearch team (see previous point)
- Additional index to take care of (only if we decide to use separate index to store session information)
Original comment by @skearns64:
Today, the Security component of X-Pack for Kibana encodes both the username and the password in the cookie that gets stored in the users browser. This cookie is encrypted with two-way encryption using a salt based on the `shield.encryptionKey` in the kibana.yml.
This issue proposes using a more secure approach - maintaining server-side sessions in the Kibana backend. Instead of putting the encrypted username/password in the cookie, the cookie would contain an encrypted session ID, which the server side would generate on first authentication, and keep in memory, updating the expiration date with each valid request while the session was active. After session expiration, it would be removed.
I see two potential phases to this.
Phase 1 would be simply storing the session state in the Kibana server memory. The drawback to this approach is In scenarios where multiple Kibana instances are being load-balanced; the load balancer would have to ensure that the same users were always directed to the same Kibana instance (so their requests go to the Kibana server holding their session).
Phase 2 would be to store the session state in Elasticsearch, potentially in the .kibana index. I think doing this depends on LINK REDACTED , which would ensure that the .kibana index (or whatever index we choose to use here) was not accessible to end-users.
Summary
Today, the Security Plugin stores user authentication information (username/password for
basicor access/refresh tokens fortoken,saml,oidcetc.) in the cookie that gets stored in the users browser. This cookie is encrypted with two-way encryption using a salt based on thexpack.security.encryptionKeyin the kibana.yml.This approach has a number of benefits (e.g. easy to scale) and drawbacks (e.g. we're hitting browser cookie size limit more and more). But more importantly, there are number of use cases we cannot really handle with the current approach, like #18162 or #53478.
This issue proposes using a more secure approach - maintaining server-side sessions in the Kibana backend. Instead of putting the encrypted authentication information in the cookie, the cookie would contain an encrypted session ID, which the server side would generate on first authentication, and store it alongside with all additional information in the Elasticsearch index. After session expiration (see below) or on explicit logout, it would be removed.
Where to store session information?
Since we started to discourage Kibana administrators from giving users access to
.kibanaindex we can safely (to be assessed) use this index to store session information. Alternatively we can use a dedicated index similar to.security-tokensindex used by Elasticsearch.We'd likely want to store the session information in an encrypted form. Either leveraging
xpack.security.encryptionKeyfor all sessions or separate unique keys for every session that'd be stored in the cookie, we'll need to find an acceptable security-performance trade-off. If we use single encryption key we may want to throw some AAD into the mix.When to clean up session information?
We can implement a number of optimizations to not overburden Kibana server with the session management, for example when user explicitly logs out or Kibana decides to do that on its own we'd not only remove this specific session, but also all other sessions that have expired (based on
xpack.security.session.idleTimeoutandxpack.security.session.lifespansettings).In addition to that we can leverage
TaskManagerto schedule a periodic 24h task to do the cleanup as well.Also we may want to just mark sessions as deleted and physically delete them later for audit purposes.
What fields session information should include?
These are the first that come into my mind:
basic, access/refresh token pair forsamlor certificate fingerprint forpki)Concerns
There are a number of concerns regarding Server-Side session comparing to the current approach:
.kibanaindex size (only if we decide to use existing.kibanaindex).kibanaindex):.kibanaindex backup.kibanaindex can drop user sessions (not swap or alter though)pkiorkerberosis used we can receive multiple "login" requests at the same time and we'll only figure out that they belong to the same user only after we talk to Elasticsearch that would issue different access tokens for both requests)Original comment by @skearns64:
Today, the Security component of X-Pack for Kibana encodes both the username and the password in the cookie that gets stored in the users browser. This cookie is encrypted with two-way encryption using a salt based on the `shield.encryptionKey` in the kibana.yml.This issue proposes using a more secure approach - maintaining server-side sessions in the Kibana backend. Instead of putting the encrypted username/password in the cookie, the cookie would contain an encrypted session ID, which the server side would generate on first authentication, and keep in memory, updating the expiration date with each valid request while the session was active. After session expiration, it would be removed.
I see two potential phases to this.
Phase 1 would be simply storing the session state in the Kibana server memory. The drawback to this approach is In scenarios where multiple Kibana instances are being load-balanced; the load balancer would have to ensure that the same users were always directed to the same Kibana instance (so their requests go to the Kibana server holding their session).
Phase 2 would be to store the session state in Elasticsearch, potentially in the .kibana index. I think doing this depends on LINK REDACTED , which would ensure that the .kibana index (or whatever index we choose to use here) was not accessible to end-users.