- Introduction
- Update the
admin
user password - Disable the auto-creation of the admin user
- Disable the root role
- Use HTTPS
- Secure connection to MongoDB
- Make sure password are stored in an encrypted form
- Enforce strong passwords
- bruteForceAttackGuard
- originVetoer
- Define and test the ACL
- Use only aggregations and forbid the
filter
query parameter - Blacklist the
$where
MongoDB operator - Define role-specific GraphQL applications
Security Hardening
Introduction
This section describes the security hardening features available with RESTHeart and some best practices to protect against common attacks.
Important
|
No system can guarantee 100% security. Security must be achieved through a set of security hardening measures implemented on the whole system stack and enforced by strong and efficient security policies. |
Checklist
Best practice |
Priority |
Impact |
Update the |
Mandatory |
Action required |
Disable the root role |
Suggested |
Configuration required |
Disable the auto-creation of the |
Suggested |
Configuration required |
Use HTTPS |
Mandatory |
Action required |
Secure connection to MongoDB |
Mandatory |
Action required |
Make sure password are stored in an encrypted form |
Mandatory |
No action required if the default authenticator is used |
Enforce strong passwords |
Mandatory |
Configuration required |
Enable bruteForceAttackGuard |
Suggested |
Configuration required |
Enable originVetoer |
Suggested |
Configuration required |
Define and test the ACL |
Mandatory |
Action required |
Use only aggregations and forbid the filter query parameter |
Suggested |
Action required |
Blacklist the $where MongoDB operator |
Mandatory |
No action required from 6.3.0, configuration required otherwise |
Define role-specific GraphQL applications |
Mandatory |
Action required |
Update the admin
user password
At first startup, RESTHeart initializes the user admin
, with the default password secret
. This user can execute any request.
Warning
|
YOU MUST UPDATE THE DEFAULT PASSWORD! The role admin can execute any request as it is set as the root role in the mongoAclAuthorizer configuration.
|
To update it, run the following command:
$ curl -u admin:secret -X PATCH localhost:8080/users/admin -H "Content-Type: application/json" -d '{ "password": "my-strong-password" }'
Refer to User Management for more information on how to create new users, roles and permissions.
Note
|
mongoAclAuthorizer is the default ACL authorizer from RESTHeart starting v6.2. For previous releases, the fileAclAuthorizer was used. In this case the user password must be updated in the file etc/users.yml .
|
Disable the auto-creation of the admin user
At startup time, the mongoRealmAuthenticator
checks if the user admin
exists. If it does not exist, it automatically creates it. This means that whenever the user admin
is deleted, it will be eventually recreated with the default password secret
.
To avoid this dangerous behavior, you should disable the auto-creation of the admin
user:
authenticators:
mongoRealmAuthenticator:
# other options omitted
# clients with root-role can execute any request
create-user: false # <---- disable auto-creation of the admin user
create-user-document: '{"_id": "admin", "password": "secret", "roles": ["admin"]}'
Disable the root role
The mongoAclAuthorizer
by default defines the root role.
authorizers:
mongoAclAuthorizer:
# other options omitted
# clients with root-role can execute any request
root-role: admin
Warning
|
this role is granted all permission, including reading and deleting any MongoDb resource. |
When you have setup your ACL, the root
role can be disabled as follow:
authorizers:
mongoAclAuthorizer:
# other options omitted
# root role disabled!
root-role: null
Use HTTPS
Warning
|
IT IS PARAMOUNT TO SECURE RESTHEART WITH TLS. |
This can be achieved either by a reverse proxy (such as Nginx, AWS API gateway, etc) or by configuring RESTHeart to only use the https-listener.
To configure RESTHeart to use TLS, follow the instructions at Configure TLS.
Secure connection to MongoDB
To configure RESTHeart to connect to MongoDB over TLS, follow the instructions at Secure connection to MongoDB.
It is also very important to restrict the access to the MongoDB database to only the resources that are required by RESTHeart; for this refer to Restrict permissions of MongoDb User.
Make sure password are stored in an encrypted form
Passwords must be stored in an encrypted form.
The default mongoRealmAuthenticator
is recommended for production use and it does store the password in an encrypted form with the default configuration.
mongoRealmAuthenticator:
# omitting other options
bcrypt-hashed-password: true
bcrypt-complexity: 12
The fileRealmAuthenticator
is for testing and development purposes only and not suggested for production use, since it does not support password hashing.
Important
|
If you use a custom Authenticator you must make sure that the passwords are stored in an encrypted form. |
Enforce strong passwords
If users can update their password, it is important enforcing that user-defined passwords are strong enough and avoid a user to chose a weak password like 123456
.
The default mongoRealmAuthenticator
is recommended for production use and it allows to refuse to update user documents with weak passwords.
mongoRealmAuthenticator:
# omitting other options
enforce-minimum-password-strenght: false
# Integer from 0 to 4
# 0 Weak (guesses < 3^10)
# 1 Fair (guesses < 6^10)
# 2 Good (guesses < 8^10)
# 3 Strong (guesses < 10^10)
# 4 Very strong (guesses >= 10^10)
minimum-password-strength: 3
Note
|
enforce-minimum-password-strenght is available from RESTHeart v6.3.0.
|
bruteForceAttackGuard
bruteForceAttackGuard
defends from brute force password cracking attacks
by returning 429 Too Many Requests
when more than max-failed-attempts
wrong requests are received in last 10 seconds from the same ip.
Note
|
bruteForceAttackGuard is available from RESTHeart v6.3.0.
|
Important
|
if RESTHeart is behind a revers proxy, this must set the header X-Forwarded-For with the client IP. In this case set the option trust-x-forwarded-for: true
|
plugins-args:
# defends from brute force password cracking attacks
# by returning `429 Too Many Requests` when more than
# `max-failed-attempts` wrong requests
# are received in last 10 seconds from the same ip
bruteForceAttackGuard:
enabled: false
# if true, the source ip is obtained from X-Forwarded-For header
# this requires that header beeing set by the proxy, dangerous otherwise
trust-x-forwarded-for: false
# max number of failed attempts in 10 seconds sliding window
# before returning 429 Too Many Requests
max-failed-attempts: 5
originVetoer
originVetoer
protects from CSRF attacks by forbidding requests whose Origin header is not whitelisted
Note
|
this is disable by default and musts be activated by adding the following configuration with the correct whitelist to your restheart.yml file:
|
authorizers:
# originVetoer protects from CSRF attacks by forbidding requests whose Origin header is not whitelisted
originVetoer:
enabled: true
whitelist:
- https://restheart.org
- https://restheart.com
Define and test the ACL
The mongoAclAuthorizer
allows to define a very fine grained, role based ACL.
The permissions set must allow to execute just the required requests, blacklisting unused query parameters, projecting the response to hide sensitive data, merging the request body with sensitive properties at the server-side, filtering writes and reads.
The following permission document is an example of a very fine grained ACL:
{
"_id": "userCanCreateDocumentsInOwnCollection",
"description": [
"**** DESCRIPTION PROPERTY IS NOT REQUIRED, HERE ONLY FOR DOCUMENTATION PURPOSES",
"allow role 'user' to create documents under /{userid}",
"the request content must contain 'title' and 'content' <- bson-request-contains(title, content)",
"the request content cannot contain any property other than 'title' and 'content' <- bson-request-whitelist(title, content)",
"no qparams can be specified <- qparams-whitelist()",
"the property 'author' and 'status' are added to the request at server-side <- mergeRequest",
"the property 'log' with some request values is added to the request at server-side <- mergeRequest"
],
"roles": ["user"],
"priority": 100,
"predicate": "method(POST) and path-template('/{userid}') and equals(@user._id, ${userid}) and bson-request-whitelist(title, content) and bson-request-contains(title, content) and qparams-whitelist()",
"mongo": {
"mergeRequest": {
"author": "@user._id",
"status": "draft",
"log": "@request"
}
}
}
Refer to Format of permission for more information.
Note
|
When the permission language cannot be used and you need more control, you can define a custom Vetoer or an Request Interceptor that can enforce additional checking logic.
|
Use only aggregations and forbid the filter
query parameter
The filter
query parameter for the Mongo REST API allows clients to execute any MongoDB query.
This is very convenient at development time, however when you are ready to deploy your application, you should blacklist the filter
query parameter in your ACL and rely on Aggregations to expose, well defined and secured queries.
Blacklist the $where
MongoDB operator
If you cannot disable the filter
query parameter, you can blacklist unused operators, using the filterOperatorsBlacklist
plugin.
The $where
MongoDB query operator is dangerous and should not be used in any case.
Note
|
filterOperatorsBlacklist is enabled by default and blacklists $where only starting from RESTHeart v6.3.0. For previous versions, it should be enabled by adding the following configuration to your restheart.yml file:
|
plugins-args:
# a global blacklist for mongodb operators in filter query parameter
filterOperatorsBlacklist:
blacklist: [ "$where" ]
enabled: true
Define role-specific GraphQL applications
Note
|
The GraphQL API is read-only, so you should only pay attention to avoid exposing sensitive information to users. This very important due to the nature of GraphQL that allows the client to request data in any format allowed by the GraphQL schema. |
In order secure the GraphQL API, several GraphQL applications should be defined with different read logic and bound to different URIs. In this way, different roles can be granted access to different subsets of the GraphQL apps thus protecting the information.
Warning
|
Protecting the GraphQL API requires the application definitions to be defined with the correct filtering options. Always test your APIs! |