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

Client-Initiated Renegotiation DoS Vulnerability #486

Closed
wants to merge 3 commits into from
Closed

Client-Initiated Renegotiation DoS Vulnerability #486

wants to merge 3 commits into from

Conversation

rdlowrey
Copy link
Contributor

@rdlowrey rdlowrey commented Oct 9, 2013

Client-Initiated Renegotiation DoS Vulnerability

The idea of using SSL/TLS renegotiation as a DoS attack vector was first widely publicized in 2011 with the release of the TLC-SSL-DOS tool. The attack vector is plausible because establishing SSL connections requires more processing power for servers than what is required for clients (Bernat). This gap in resource consumption creates an easy target for nefarious clients looking to exhaust server resources through DoS attacks in which the TLS handshake is repeatedly renegotiated. There is generally no compelling reason to allow client-initiated renegotiation of the TLS handshake:

There are some cases in which renegotiation needs to be initiated by the server, but there is no known need for clients to do so.

-- SSL/TLS Deployment Best Practices

Encrypted PHP servers initialized via stream_socket_server() currently offer no mechanism to disable client-initiated TLS renegotiation and as a result afford no protection against the renegotiation DoS attack vector.

Proposed Solution
  • Add a new "max_handshake_rate" context option limiting the number of client-initiated renegotiation attempts allowed per second.
  • Clients exceeding the allowed rate are immediately shutdown (and have their stream's EOF flag set).
  • Rate-limiting is not applied until after the initial handshake is negotiated.
  • Servers wishing to differentiate between client sockets closed normally and those shutdown due to a renegotiation policy violation may check the stream's meta data after the fact:
$wrapperMeta = stream_get_meta_data($clientSocket)['wrapper_data'];
if (!empty($wrapperMeta['handshake_limit_exceeded'])) {
    echo "Client closed due to renegotiation policy violation!\n";
}
Suggested Usage

Renegotiation rate-limiting is not enabled by default. Unless servers have a good reason for allowing client-initiated renegotiation they should disable this functionality as demonstrated in the example server script below:

<?php
$bindTo = 'tls://127.0.0.1:12345';
$flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
$ctx = stream_context_create(['ssl' => [
    'local_cert' => '/path/to/cert.pem',
    'max_handshake_rate' => 0,
    'disable_compression' => TRUE
]]);
$server = stream_socket_server($bindTo, $errNo, $errStr, $flags, $ctx);
$clients = [];

while (1) {
    $r = array_merge([$server], $clients);
    $w = $e = [];
    stream_select($r, $w, $e, $timeout=1);

    foreach ($r as $sock) {
        if ($sock === $server
            && ($client = @stream_socket_accept($server, $timeout = 1))
        ) {
            $clientId = (int) $client;
            $clients[$clientId] = $client;
        } else {
            $clientId = (int) $client;
            $buffer = @fread($sock, 1024);

            if (strlen($buffer)) {
                echo "Client data received: ", $buffer, "\n";
            } elseif (feof($sock)) {
                $wrapperMeta = stream_get_meta_data($sock)['wrapper_data'];
                if (!empty($wrapperMeta['handshake_limit_exceeded'])) {
                    echo "Client closed due to renegotiation policy violation!\n";
                }
                fclose($sock);
                unset($clients[$clientId]);
                break 2; // end the demo script
            }
        }
    }
}

NOTE: This patch has no BC implications and should be safe to merge with 5.4.x and 5.5.x branches

DaveRandom and others added 2 commits October 8, 2013 22:47
- Removed potential segfault on rate limit increase post stream creation
- Stream meta data updated when client closed for reneg policy violation
- Added test
@datibbaw
Copy link
Contributor

👍


stream = php_openssl_get_stream_from_ssl_handle(ssl);
sslsock = (php_openssl_netstream_data_t*)stream->abstract;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both stream and sslock, never ever could be NULL?

@rdlowrey
Copy link
Contributor Author

Closing this ... I have a much better implementation coming soon.

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.

4 participants