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

[🐸 Frogbot] Update version of google.golang.org/grpc to 1.58.3 #2287

Merged

Conversation

github-actions[bot]
Copy link
Contributor

📦 Vulnerable Dependencies

✍️ Summary

SEVERITY DIRECT DEPENDENCIES IMPACTED DEPENDENCY FIXED VERSIONS CVES

High
github.com/jfrog/jfrog-cli-core/v2:v2.45.4
github.com/spf13/viper:v1.17.0
google.golang.org/grpc:v1.58.2
google.golang.org/grpc v1.58.2 [1.56.3]
[1.57.1]
[1.58.3]
CVE-2023-44487

🔬 Research Details

Description:
The HTTP (Hypertext Transfer Protocol) is a fundamental protocol of the World Wide Web, enabling the exchange of data between a client (typically a web browser) and a server. It defines the rules for requesting and transmitting web pages and other resources over the internet. Request and response messages are exchanged as a stream of ASCII characters, sent over a reliable transport layer like TCP.

HTTP/2 is a modern network protocol designed to improve the performance and efficiency of web communication. It replaces the older HTTP/1.1 protocol and introduces features like header compression and enhanced request cancellation mechanisms, which collectively enhance the speed and responsiveness of websites.

This request cancellation mechanism allows clients to terminate unnecessary or redundant requests without waiting for a server's response, reducing network congestion and further improving the overall responsiveness of web applications.

HTTP/2 resolves numerous concerns found in HTTP/1.1 by organizing each HTTP message into a series of HTTP/2 frames. These frames include type, length, flags, stream identifier (ID), and payload. The stream ID is essential in clearly associating specific bytes on the network with their corresponding messages, facilitating secure multiplexing and concurrent processing. These streams are bidirectional, enabling clients to transmit frames, and servers to respond with frames using the same ID.

As detailed in this technical analysis, there's a vulnerability in the way request cancellation is implemented. The flaw lies in the process of sending an excessive number of requests (specifically, HEADERS frames), each immediately followed by a request cancellation frame utilizing the RST_STREAM frame. This sequence rapidly leads to a substantial consumption of server-side resources. Consequently, this vulnerability amplifies the risk of Distributed Denial of Service (DDoS) attacks, making it easier to overwhelm and exhaust the server's available resources.

A lot of server applications are vulnerable to the Http/2 Rapid Reset attack.
However, note that HTTP/2 must be enabled, which is not the default configuration on most applications (excluding nghttp2 for example).
A non-exhaustive list of these vulnerable web applications:

- Tomcat
- Jetty
- NGINX on certain conditions
- nghttp2
- Netty

Remediation:

Development mitigations

For netty:

import io.netty.handler.codec.http2.Http2FrameListener;
import io.netty.handler.codec.http2.Http2FrameStream;
import io.netty.handler.codec.http2.Http2ResetFrame;
import io.netty.handler.codec.http2.Http2HeadersFrame;

public class CustomHttp2FrameListener implements Http2FrameListener {
    private int rstFrameCount = 0;
    private int maxRstFrameCount = 10; // Adjust this to your desired limit
    private long resetTimeMillis = System.currentTimeMillis();
    private long resetTimeIntervalMillis = 60000; // 60 seconds

    @Override
    public int onDataRead(Http2FrameStream stream, byte[] data, int padding, boolean endOfStream) {
        // Handle data frames if needed
        return 0;
    }

    @Override
    public void onHeadersRead(Http2FrameStream stream, Http2HeadersFrame headersFrame) {
        // Handle headers frames if needed
    }

    @Override
    public void onHeadersRead(Http2FrameStream stream, Http2HeadersFrame headersFrame, boolean endOfStream) {
        // Handle headers frames if needed
    }

    @Override
    public void onRstStreamRead(Http2FrameStream stream, Http2ResetFrame resetFrame) {
        long currentTimeMillis = System.currentTimeMillis();
        
        // Check if the reset time interval has passed, and reset the count if needed
        if (currentTimeMillis - resetTimeMillis >= resetTimeIntervalMillis) {
            rstFrameCount = 0;
            resetTimeMillis = currentTimeMillis;
        }
        
        rstFrameCount++;
        
        // Check if the count exceeds the limit
        if (rstFrameCount > maxRstFrameCount) {
            // Take action, e.g., close the connection, log, or drop frames
            // You can use stream or resetFrame to get more context if needed.
            // To close the connection, you can use stream.connection().close();
        }
    }
}
Development mitigations

For Golang:

The default stream concurrency limit in golang is 250 streams (requests) per HTTP/2 connection. This value may be adjusted in the golang.org/x/net/http2 package using the Server.MaxConcurrentStreams setting and the ConfigureServer function which are available in golang.org/x/net/http2.

import (
	"fmt"
	"golang.org/x/net/http2"
	"net/http"
)

func main() {
	// Create an HTTP/2 server instance
	http2Server := &http2.Server{}

	// Set the desired stream concurrency limit
	maxConcurrentStreams := 500 // Change this to your desired limit
	http2Server.MaxConcurrentStreams = uint32(maxConcurrentStreams)

	// Configure an HTTP server to use HTTP/2 with the adjusted settings
	server := &http.Server{
		Addr:    ":8080",
		Handler: http.HandlerFunc(handleRequest),
	}
	http2.ConfigureServer(server, http2Server)

	// Start the HTTP server
	err := server.ListenAndServeTLS("cert.pem", "key.pem")
	if err != nil {
		fmt.Println("Error:", err)
	}
}
Development mitigations

For Nghttp2:
Implement nghttp2_on_frame_recv_callback callback function, and check and count RST_STREAM frames. If an excessive number of RST_STREAM frames are received, then take action, such as dropping the connection silently, or calling nghttp2_submit_goaway and gracefully terminate the connection.

#include <nghttp2/nghttp2.h>

// Callback function for handling frame reception
int on_frame_recv_callback(nghttp2_session* session,
                           const nghttp2_frame* frame, void* user_data) {
    // Check if the received frame is an RST_STREAM frame
    if (frame->hd.type == NGHTTP2_RST_STREAM) {
        // Increment a counter for RST_STREAM frames
        int* rst_stream_counter = (int*)user_data;
        (*rst_stream_counter)++;
        
        // Define a threshold for excessive RST_STREAM frames
        int rst_stream_threshold = 10;  // Adjust this value as needed
        
        // If the threshold is exceeded, take action (e.g., close the connection)
        if (*rst_stream_counter > rst_stream_threshold) {
            // Here, you can choose to close the connection gracefully or drop it
            // For demonstration purposes, we'll just print a message
            printf("Excessive RST_STREAM frames received. Closing the connection.\n");
            // You can call nghttp2_submit_goaway() to send a GOAWAY frame if needed.
            // nghttp2_submit_goaway(session, NGHTTP2_FLAG_NONE, error_code, opaque_data);
            // Then, close the connection.
        }
    }
    
    // Continue processing other frames if needed
    return 0;
}

int main() {
    // Initialize nghttp2_session and set up the on_frame_recv_callback
    nghttp2_session* session;
    int rst_stream_counter = 0;
    
    // Initialize nghttp2_session, set up callbacks, etc.
    // ...

    // Set the user data to be passed to the callback
    nghttp2_session_user_data(session, &rst_stream_counter);
    
    // Register the on_frame_recv_callback
    nghttp2_session_callbacks* callbacks;
    nghttp2_session_callbacks_new(&callbacks);
    nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, on_frame_recv_callback);
    // Other callback registrations here...
    
    // Attach the callbacks to the session
    nghttp2_session_server_new(&session, callbacks, &rst_stream_counter);
    
    // Start processing HTTP/2 frames
    // ...

    // Cleanup and finish the program
    // ...

    return 0;
}
Deployment mitigations

For NGINX:

Disabling HTTP/2 in NGINX is not necessary. Simply ensure you have configured:

  • keepalive_requests should be kept at the default setting of 1000 requests
  • http2_max_concurrent_streams should be kept at the default setting of 128 streams
  • limit_conn and limit_req should be set "with a reasonable setting balancing application performance and security"
Deployment mitigations

A possible mitigation is to limit the maximum number of requests that can be made over a single keep-alive connection.


@eyalbe4 eyalbe4 added the safe to test Approve running integration tests on a pull request label Oct 28, 2023
@github-actions github-actions bot removed the safe to test Approve running integration tests on a pull request label Oct 28, 2023
@eyalbe4 eyalbe4 added the safe to test Approve running integration tests on a pull request label Oct 31, 2023
@github-actions github-actions bot removed the safe to test Approve running integration tests on a pull request label Oct 31, 2023
@eyalbe4 eyalbe4 merged commit d047c66 into dev Nov 1, 2023
66 of 74 checks passed
@sverdlov93 sverdlov93 deleted the frogbot-google.golang.org/grpc-afb32ee903dad0d2cda59b19af8917c8 branch January 7, 2024 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants