194 lines
No EOL
13 KiB
XML
Executable file
194 lines
No EOL
13 KiB
XML
Executable file
<!--
|
|
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
|
|
~ and other contributors as indicated by the @author tags.
|
|
~
|
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
~ you may not use this file except in compliance with the License.
|
|
~ You may obtain a copy of the License at
|
|
~
|
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
~
|
|
~ Unless required by applicable law or agreed to in writing, software
|
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
~ See the License for the specific language governing permissions and
|
|
~ limitations under the License.
|
|
-->
|
|
|
|
<chapter id="security_vulnerabilities">
|
|
<title>Security Vulnerabilities</title>
|
|
<para>
|
|
This chapter discusses possible security vulnerabilities Keycloak could have, how Keycloak mitigates those
|
|
vulnerabilities, and what steps you need to do to configure Keycloak to mitigate some vulnerabilities. A good list
|
|
of potential vulnerabilities and what security implementations should do to mitigate them can be found in the
|
|
<ulink url="http://tools.ietf.org/html/rfc6819">OAuth 2.0 Threat Model</ulink> document put out by the IETF. Many of those vulnerabilities are discussed here.
|
|
</para>
|
|
<section>
|
|
<title>SSL/HTTPS Requirement</title>
|
|
<para>
|
|
If you do not use SSL/HTTPS for all communication between the Keycloak auth server and the clients it secures
|
|
you will be very vulnerable to man in the middle attacks. OAuth 2.0/OpenID Connect uses access tokens for
|
|
security. Without SSL/HTTPS, attackers can sniff your network and obtain an access token. Once they have an
|
|
access token they can do any operation that the token has been given permission for.
|
|
</para>
|
|
<para>
|
|
Keycloak has <link linkend="ssl_modes">three modes for SSL/HTTPS</link>. SSL can be hard to set up, so out of the box, Keycloak allows
|
|
non-HTTPS communication over private IP addresses like localhost, 192.168.x.x, and other private IP addresses.
|
|
In production, you should make sure SSL is enabled and required across the board.
|
|
</para>
|
|
<para>
|
|
On the adapter/client side, Keycloak allows you to turn off the SSL trust manager. The trust manager ensures
|
|
identity the client is talking to. It checks the DNS domain name against the server's certificate. In production
|
|
you should make sure that each of your client adapters is configured to use a truststore. Otherwise you are vulnerable
|
|
to DNS man in the middle attacks.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>CSRF Attacks</title>
|
|
<para>
|
|
Cross-site request forgery (CSRF) is a web-based attack whereby HTTP
|
|
requests are transmitted from a user that the web site trusts or has
|
|
authenticated (e.g., via HTTP redirects or HTML forms). Any site that uses
|
|
cookie based authentication is vulnerable for these types of attacks. These attacks are mitigated
|
|
by matching a state cookie against a posted form or query parameter.
|
|
</para>
|
|
<para>
|
|
OAuth 2.0 login specification requires that a state cookie be used and matched against a transmitted state
|
|
parameter. Keycloak fully implements this part of the specification so all logins are protected.
|
|
</para>
|
|
<para>
|
|
The Keycloak adminstration console is a pure Javascript/HTML5 application that makes REST calls to the
|
|
backend Keycloak admin API. These calls all require bearer token authentication and are made via Javascript
|
|
Ajax calls. CSRF does not apply here. The admin REST API can also be configured to validate CORS origins
|
|
as well.
|
|
</para>
|
|
<para>
|
|
The only part of Keycloak that really falls into CSRF is the user account management pages. To mitigate this
|
|
Keycloak sets a state cookie and also embeds the value of this state cookie within hidden form fields or
|
|
query parameters in action links. This query or form parameter is checked against the state cookie to verify
|
|
that the call was made by the user.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Clickjacking</title>
|
|
<para>
|
|
With clickjacking, a malicious site loads the target site in a
|
|
transparent iFrame overlaid on top of a set of dummy
|
|
buttons that are carefully constructed to be placed directly under
|
|
important buttons on the target site. When a user clicks a visible
|
|
button, they are actually clicking a button (such as an "Authorize"
|
|
button) on the hidden page. An attacker can steal a user's authentication credentials and
|
|
access their resources.
|
|
</para>
|
|
<para>
|
|
By default, every response by Keycloak sets some specific browser headers that can prevent this from happening
|
|
specifically <ulink url="http://tools.ietf.org/html/rfc7034">X-FRAME_OPTIONS</ulink> and <ulink url="http://www.w3.org/TR/CSP/">Content-Security-Policy</ulink>. You
|
|
should take a look at both of these headers. In the admin console you can specify the values these headers will
|
|
have. By default, Keycloak only sets up a same-origin policy for iframes.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Compromised Access Codes</title>
|
|
<para>
|
|
It would be very hard for an attacker to compromise Keycloak access codes. Keycloak generates a cryptographically
|
|
strong random value for its access codes so it would be very hard to guess an access token.
|
|
An access code can only be turned into an access token once so it can't be replayed. In the admin console
|
|
you can specify how long an access token is valid for. This value should be really short. Like a seconds.
|
|
Just long enough for the client to make the request to turn the code into an token.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Compromised access and refresh tokens</title>
|
|
<para>
|
|
There's a few things you can do to mitigate access tokens and refresh tokens from being stolen.
|
|
Most importantly is to enforce SSL/HTTPS communication between Keycloak and its clients and applications.
|
|
Short lifespans (minutes) for access tokens allows Keycloak to check the validity of a refresh token. Making
|
|
sure refresh tokens always stay private to the client and are never transmitted ever is very important as well.
|
|
</para>
|
|
<para>
|
|
If an access token or refresh token is compromised, the first thing you should do is go to the admin console
|
|
and push a not-before revocation policy to all applications. This will enforce that any tokens issued
|
|
prior to that date are now invalid. You can also disable specific applications, clients, and users if you
|
|
feel that any one of those entities is completely compromised.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Open redirectors</title>
|
|
<para>
|
|
An attacker could use the end-user authorization endpoint and the
|
|
redirect URI parameter to abuse the authorization server as an open
|
|
redirector. An open redirector is an endpoint using a parameter to
|
|
automatically redirect a user agent to the location specified by the
|
|
parameter value without any validation. An attacker could utilize a user's trust in an authorization
|
|
server to launch a phishing attack.
|
|
</para>
|
|
<para>
|
|
Keycloak requires that all registered applications and clients register at least one redirection uri pattern.
|
|
Any time a client asks Keycloak to perform a redirect (on login or logout for example), Keycloak will
|
|
check the redirect uri vs. the list of valid registered uri patterns. It is important that clients and
|
|
applications register as specific a URI pattern as possible to mitigate open redirector attacks.
|
|
</para>
|
|
</section>
|
|
<section id="brute-force-attacks">
|
|
<title>Password guess: brute force attacks</title>
|
|
<para>
|
|
A brute force attack happens when an attacker is trying to guess a user's password. Keycloak has some
|
|
limited brute force detection capabilities. If turned on, a user account will be temporarily disabled
|
|
if a threshold of login failures is reached. The downside of this is that this makes Keycloak vulnerable
|
|
to denial of service attacks. Eventually we will expand this functionality to take client IP address into
|
|
account when deciding whether to block a user.
|
|
</para>
|
|
<para>
|
|
Another thing you can do to prevent password guessing is to point a tool like <ulink url="http://fail2ban.org">Fail2Ban</ulink> to the Keycloak
|
|
server's log file. Keycloak logs every login failure and client IP address that had the failure.
|
|
</para>
|
|
<para>
|
|
In the admin console, per realm, you can set up a password policy to enforce that users pick hard to guess passwords.
|
|
A password has to match all policies. The password policies that can be configured are hash iterations, length, digits,
|
|
lowercase, uppercase, special characters, not username, regex patterns, password history and force expired password update.
|
|
Force expired password update policy forces or requires password updates after specified span of time. Password history policy
|
|
restricts a user from resetting his password to N old expired passwords. Multiple regex patterns can be specified.
|
|
If there's more than one regex added, password has to match all fully.
|
|
Increasing number of Hash Iterations (n) does not worsen anything (and certainly not the cipher) and it greatly increases the
|
|
resistance to dictionary attacks. However the drawback to increasing n is that it has some cost (CPU usage, energy, delay) for
|
|
the legitimate parties. Increasing n also slightly increases the odds that a random password gives the same result as the right
|
|
password due to hash collisions, and is thus a false but accepted password; however that remains very unlikely, in the order of
|
|
n*[1/(2^256)] for practical values of n, and can be entirely ignored in practice. Keycloak also uses PBKDF2 internally to
|
|
cryptographically derive passwords to refine and improve the ratio of cost between attacker and legitimate parties.
|
|
Good practice is to pay attention to the time complexity of hash_password and hash; then increase n as much as tolerable in
|
|
the situation(s) at hand and and revise parameters such as n every few years to account for time complexity trade off.
|
|
</para>
|
|
<para>
|
|
Finally, the best way to mitigate against brute force attacks is to require user to set up a one-time-password (OTP).
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Password database compromised</title>
|
|
<para>
|
|
Keycloak does not store passwords in raw text. It stores a hash of them. Because of performance reasons,
|
|
Keycloak only hashes passwords once. While a human could probably never crack a hashed password, it is very
|
|
possible that a computer could. The security community suggests around 20,000 (yes thousand!) hashing iterations
|
|
to be done to each password. This number grows every year due to increasing computing power (It was 1000 12 years ago).
|
|
The problem with this is that password hashing is a huge performance hit as each login would require the entered
|
|
password to be hashed that many times and compared to the stored hash. So, its up to the admin to configure the
|
|
password hash iterations. This can be done in the admin console password policy configuration. Again, the default
|
|
value is 1 as we thought it might be more important for Keycloak to scale out of the box. There's a lot of
|
|
other measures admins can do to protect their password databases.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>SQL Injection attacks</title>
|
|
<para>
|
|
At this point in time, there is no knowledge of any SQL injection vulnerabilities in Keycloak
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Limiting Scope</title>
|
|
<para>
|
|
Using the <literal>Scope</literal> menu in the admin console for clients, you can control
|
|
exactly which role mappings will be included within the token sent back to the client application. This
|
|
allows you to limit the scope of permissions given to the client which is great if the client isn't
|
|
very trusted and is known to not being very careful with its tokens.
|
|
</para>
|
|
</section>
|
|
</chapter> |