Skip to content

Security

Client Security

For security reasons, this article does not describe CC attacks for which Turms does not provide a special defense mechanism.

Client blacklist mechanism

The server's handling of banned clients

When turms-gateway detects that a new IP or user ID is blocked, it will first send a shutdown notification of the Turms business layer to the established and blocked session. The notification has the USER_IS_BLOCKED status code, telling the client that it is Banned. After the data is flushed, the Turms server automatically disconnects the underlying TCP connection.

When turms-gateway checks that the peer IP of the newly established TCP connection has been banned, or detects that the user ID sending the login request has been banned, by default, turms-gateway will directly close the TCP connection with it, and will not A notification of the reason for connection closure will be sent, such as "Your IP/User ID has been blocked for XX time".

There are two points to note:

  • turms-gateway itself cannot refuse to connect with the banned IP before the TCP connection is established. If you want the server to refuse to connect to the banned IP before the TCP handshake, you can use the callback plug-in provided after Turms to notify the cloud service security system to ban the IP, so as to completely realize the IP ban .

    In addition, the reason why we do not call the system service to completely block the IP is because: when the server is forcibly shut down, the blocked IP will not be automatically removed; modifying the underlying network configuration by ourselves may interfere with the cloud service's own network The management service conflicts, causing the server to be abnormal.

  • When the client connects or logs in, turms-gateway will actively disconnect the connection with the banned IP or user, but it will not send a notification of the reason for the connection closure. The advantages of doing this are: 1. The bandwidth of the cloud service is charged according to the outbound bandwidth, and the inbound bandwidth is not charged, so turms-gateway does not send a response on the business layer, which can slow down the bandwidth cost incurred when being attacked by DDoS; 2. Reduce information exposure and try not to provide effective information to hackers

Automatic ban mechanism

The timings that currently support automatic detection and banning of clients are:

  • When the user sends requests frequently and reaches a certain number of times

  • When the WebSocket frame sent by the user does not conform to the specification or is too large, and reaches a certain number of times. The size of the request is based on the Payload Length value in the WebSocket Frame Header

  • When the Turms client request sent by the user cannot be parsed or is too large, and reaches a certain number of times. The size of the request is based on the Payload Length value of the client request Header in the TCP byte stream

    Replenish:

    • When the server detects that the data frame or client request is "too large", it will not continue to parse the subsequent Payload part. If the Payload Length of the client does not match the actual Payload length, it will be judged as an illegal request
    • The specific request size limit can be configured through turms.gateway.client-api.max-request-size-bytes

In other words, after the TCP connection is established, any behavior of the user may trigger a ban.

The automatic ban mechanism of Turms adopts a grading system, and provides 3 levels by default. The ban durations of these 3 levels are: 1 minute, 30 minutes, and 60 minutes. Under the default configuration, when the client triggers 5 illegal behaviors, the server will block the IP and user ID of the client with the configuration of level 1. If a certain number of illegal behaviors are triggered within the blocking time, it will enter the next block grade, and so on.

If you want to modify the default configuration, you can pass turms.security.blocklist.ip.auto-block and turms.security.blocklist.user-id.auto-block prefix, and cooperate with IDEA's smart prompt Modify the default configuration. Its specific configuration items are declared in the im.turms.server.common.infra.property.env.common.security.AutoBlockItemProperties class.

Administrators can use the API: /blocked-clients/ips and /blocked-clients/users to add, delete, modify and query blocked IPs and blocked user IDs respectively. The specific operations follow Turms HTTP interface design general rules, so I won’t go into details.

Implementation principle of ban (expand knowledge)

The principle of synchronizing banned client data is similar to that of common distributed Replicated Map implementations. That is, each server holds a weakly consistent copy of the Map, and one or more Redis servers store a reference copy, and also records the logs of each blocking and unblocking behavior for each server Do incremental sync. When a new server goes online or a server's local logs data lags behind by 100,000 records, these servers will request full synchronization from Redis, otherwise the server only needs to request incremental logs from Redis at the default interval of 10 seconds to synchronize the local copy .

In addition, the causal consistency implementation currently adopted by Turms is: the order of blocking and unblocking actions is based on the insertion order of the blocked logs queue in Redis, and each server performs causal synchronization based on the order of logs in the queue to ensure that the client is blocked The eventual consistency of the data.

Why not use Bloom Filter

The theoretical solution to realize the blacklist function based on Bloom Filter is widely known, but in fact, Bloom Filter has many pitfalls in this scenario, specifically:

  • The features and engineering practices supported by Bloom Filter are limited. such as:

    • In a distributed environment, how to judge the order of "ban operation" and "unblock operation", and how to ensure the final consistency
    • How to set different ban durations for different banned users (such as five minutes/half an hour)
    • How to add additional information to additional banned users, such as the reason for being blocked
    • How to synchronize the blacklist list between nodes, how to do incremental synchronization
    • How to implement "unblocking operation" and what is the cost

    To sum up, even the most basic functions of the blacklist system cannot be realized by Bloom Filter in a distributed environment. Even if Bloom Filter is barely realized in conjunction with other engineering practices, then the advantages of Bloom Filter itself will not exist.

  • The amount of blocked user data itself is very small, and Bloom Filter cannot give full play to its advantages. And if it is just to judge whether the user has been blocked, according to the 1 million banned user IDs, a total of 12MiB or 61.4MiB of memory is needed (additional supplement: this example also confirms that we are in About the Valhalla project Mentioned in the article: Java's waste of memory makes people feel a little "self-defeating"). Because thread-safe collections are usually used in actual programming, and most thread-safe Sets are generally implemented based on Map, so the thread-safe Map is uniformly used below:

    java
    public static void main(String[] args) {
        int number = 1_000_000;
        var map1 = ConcurrentHashMap.newKeySet((int)(number / 0.75F + 1.0F));
        var map2 = new NonBlockingHashMapLong<>(number);
        for (long i = 0; i < number; i++) {
            map1.add(i);
            map2.put(i, Boolean.TRUE);
        }
        System.out.println(GraphLayout.parseInstance(map1).toFootprint());
        System.out.println(GraphLayout.parseInstance(map2).toFootprint());
    }

    The output of its memory usage is as follows (calculated based on org.openjdk.jol.jol-core library):

    text
    java.util.concurrent.ConcurrentHashMap$KeySetView@593634add footprint:
         COUNT       AVG       SUM   DESCRIPTION
             1   8388624   8388624   [Ljava.util.concurrent.ConcurrentHashMap$Node;
             1        16        16   java.lang.Boolean
       1000000        24  24000000   java.lang.Long
             1        64        64   java.util.concurrent.ConcurrentHashMap
             1        24        24   java.util.concurrent.ConcurrentHashMap$KeySetView
       1000000        32  32000000   java.util.concurrent.ConcurrentHashMap$Node
       2000004            64388728   (total)
    
    org.jctools.maps.NonBlockingHashMapLong@51ca57d6d footprint:
         COUNT       AVG       SUM   DESCRIPTION
             3   2796304   8388912   [J
             1   4194320   4194320   [Ljava.lang.Object;
             1        16        16   java.lang.Boolean
             2        16        32   org.jctools.maps.ConcurrentAutoTable
             2        40        80   org.jctools.maps.ConcurrentAutoTable$CAT
             1        40        40   org.jctools.maps.NonBlockingHashMapLong
             1        64        64   org.jctools.maps.NonBlockingHashMapLong$CHM
            11            12583464   (total)
  • There is an error

Client interface anti-brush current limit

The current limiting implementation of turms-gateway adopts the mainstream algorithm "token bucket algorithm" (for example, the API Gateway of AWS provides traffic integer implementation using the token bucket algorithm).

Basics

No matter what the algorithm is, it needs to calculate the "allowed number of requests". The following is a unified description, and the word "token" is used to refer to the "allowed number of requests". In addition, the following table is the general implementation of this type of algorithm, and its variants will not affect the essence of the algorithm, so it will not be discussed.

Fixed time window algorithmSliding time window algorithmToken bucket algorithmLeaky bucket algorithm
Token CapFixed or Dynamic Token Cap (usually Fixed Cap)Fixed or Dynamic Token Cap (usually Fixed Cap)Fixed or Dynamic Token Cap (usually Fixed Cap)Fixed or Dynamic Token Cap (usually Fixed upper limit)
Current number of available tokensCalculated by a single time intervalCalculated by multiple time intervalsCalculated by the current number of tokens in stockCalculated by the current number of tokens in stock
Token issuance intervalEmphasize coarse-grained interval issuance (such as interval 1 minute)Emphasize fine-grained interval issuance (such as interval 15 seconds)Emphasize fine-grained interval issuance (such as interval 1 second)Emphasize fine-grained interval Release (such as interval 1 second)
Clear count on token issueYesYes. But generally only the earliest few windows are clearedNoNo
Resource overheadNo timer required, minimal overheadNo timer required, minimal overheadNo timer required, minimal overheadEach session needs to maintain an MPSC synchronization queue, and a timer to time the Poll queue, with very high overhead big
Difficulty of implementationVery simpleVery simpleVery simpleRelatively troublesome
General CommentDue to the need to clear the count and the granularity is too large, the client can burst a large number of requests before each token issuance, causing the problem of "double burst traffic"avoiding the problem of "double burst traffic" , but because of the "clear count" operation, its control precision is not as good as the token bucket algorithm and the leaky bucket algorithmIt can not only handle burst requests through stock tokens, but also through fine-grained interval commands Cards are issued to smoothly throttle requests.
In fact, the CPU credit mechanism of cloud services is similar to this
The length is slightly longer, see below

Both the leaky bucket algorithm and the token bucket algorithm have the ability to handle burst requests and smoothly limit the flow of requests. But a special function of the leaky bucket algorithm is that it can limit the flow of downstream services (the most important one is the database). However, there is also a price for downstream flow limiting. It requires the operation and maintenance personnel to accurately estimate the downstream service throughput, otherwise it may cause the downstream service to be idle while the upstream service is limiting the flow.

In addition, the use of MPSC queues to cache requests not only reduces throughput, but also increases memory overhead and GC times, resulting in poor user experience and exacerbating the effect of DDoS attacks. (Supplement: By reading the source code of the Turms server, you will find that in the process of processing client requests in Turms, the code is as "light" as possible, so using the MPSC queue for each user session is considered a heavy operation)

In summary, the Turms server finally uses the token bucket algorithm.

In particular, compared to the traditional HTTP server, the CPU and memory system resources required to receive and process a regular HTTP request and response may be hundreds of times the system resources required for the interaction between the Turms server and its client (for example: except The network layer protocol header, the average size of a request from the Turms client is about 32B). Therefore, there is no need to take the sudden Turms client requests of a small number of users too seriously. The system resources used to process hundreds of Turms client requests may be similar to processing one HTTP request (of course, there are other forms of CC attacks that will cause a lot of resource consumption).

other:

  • turms-gateway does not support and currently does not plan to support the implementation of global current limiting. The reason is: global current limiting is usually over-designed. Global current limiting is to alleviate DDoS attacks at all times, increase Redis failure points, and reduce the request processing of the entire system Throughput, many times you lose sight of the other, the gain outweighs the gain
  • Turms does not currently support assigning different weights to different types of requests. For example, a login request requires 3 tokens, and a message request requires 1 token
  • turms-gateway supports the configuration of the runtime zero-downtime update token bucket algorithm

User Information Security

For most domestic groups with a little Internet age, unless they have a strong sense of security, their plaintext passwords are very likely to have been leaked (the specific content can be found out through social engineering database). Combined with the fact that the passwords used by most users are relatively fixed, so no matter how encrypted the server is, the security of the "password" is still relatively low.

TODO

Admin Security

Administrator authentication and authorization

Authentication

Authentication: The server is implemented based on the common HTTP Basic authentication to confirm which administrator is the sender of the HTTP request.

Configuration item: turms.security.password.admin-password-encoding-algorithm, its optional values are: bcrypt (default), salted_sha256 and noop.

Supported key encryption algorithms

*BCrypt. Its cost is a hard-coded 10 (2^10 rounds), which is used to prevent hackers from easily deciphering the plaintext password through the rainbow table when it is removed from the database.

For the specific algorithm implementation, please refer to the source code implementation of Bouncy Castle of Fork under the turms-server-common subproject: org.bouncycastle.crypto.generators.BCrypt#generate

  • Salted SHA-256

  • NOOP (plaintext storage)

Special mention: The password field in the admin collection is not stored in string (such as the common Base64 encoded string), but the original byte[] byte data.

Authorization

Authorization: The server confirms what authority the sender of the HTTP request has to do

Because Turms's own permission management requirements are very simple, its design and implementation are also relatively simple. For example, there are no concepts such as user groups, group roles, and role inheritance, and there is no many-to-many relationship between users and roles. Specifically, Turms uses RBAC (Role-Based Access Control) design scheme.

Turms' RBAC Model

Turms' RBAC model consists of three subjects: Admin, Role and Permission. A user can have only one role, and a role can have multiple permissions. in:

  • Each role also has a field rank, only relatively high-rank administrators can add, delete and modify relatively low-rank administrator account information, such as passwords.
  • Permissions are used to describe what operations a role can perform on what resources, such as adding, deleting, modifying and querying user resources
Special Character - Root

Root is a built-in administrator role in Turms, which has all administrator privileges and cannot be modified or deleted.

Special root account - turms

The root account turms user has the Root root role authority, and its account name does not support modification (but can be changed by modifying the hard-coded im.turms.server.common.domain.admin.constant.AdminConst#ROOT_ADMIN_ACCOUNT value) Modify the root account name), its initial password is turms by default, but users can use the configuration item turms.security.password.initial-root-password when the admin collection has not been created and the turms-service is started Defined initial password.

Log desensitization

TODO