This commit is contained in:
parent
ef99d81d68
commit
1bff37bec1
|
|
@ -139,6 +139,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
|||
BadHttpRequestException ex;
|
||||
switch (reason)
|
||||
{
|
||||
case RequestRejectionReason.TlsOverHttpError:
|
||||
ex = new BadHttpRequestException(CoreStrings.HttpParserTlsOverHttpError, StatusCodes.Status400BadRequest, reason);
|
||||
break;
|
||||
case RequestRejectionReason.InvalidRequestLine:
|
||||
ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidRequestLine_Detail(detail), StatusCodes.Status400BadRequest, reason);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
|
|
@ -26,36 +26,36 @@
|
|||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
|
|
@ -614,4 +614,7 @@ For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?l
|
|||
<data name="Http2StreamResetByApplication" xml:space="preserve">
|
||||
<value>The HTTP/2 stream was reset by the application with error code {errorCode}.</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="HttpParserTlsOverHttpError" xml:space="preserve">
|
||||
<value>Detected a TLS handshake to an endpoint that does not have TLS enabled.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -31,6 +31,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
private const byte ByteTab = (byte)'\t';
|
||||
private const byte ByteQuestionMark = (byte)'?';
|
||||
private const byte BytePercentage = (byte)'%';
|
||||
private const int MinTlsRequestSize = 1; // We need at least 1 byte to check for a proper TLS request line
|
||||
|
||||
public unsafe bool ParseRequestLine(TRequestHandler handler, in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||
{
|
||||
|
|
@ -415,9 +416,29 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
|||
return new Span<byte>(data, methodLength);
|
||||
}
|
||||
|
||||
private unsafe bool IsTlsHandshake(byte* data, int length)
|
||||
{
|
||||
const byte SslRecordTypeHandshake = (byte)0x16;
|
||||
|
||||
// Make sure we can check at least for the existence of a TLS handshake - we check the first byte
|
||||
// See https://serializethoughts.com/2014/07/27/dissecting-tls-client-hello-message/
|
||||
|
||||
return (length >= MinTlsRequestSize && data[0] == SslRecordTypeHandshake);
|
||||
}
|
||||
|
||||
[StackTraceHidden]
|
||||
private unsafe void RejectRequestLine(byte* requestLine, int length)
|
||||
=> throw GetInvalidRequestException(RequestRejectionReason.InvalidRequestLine, requestLine, length);
|
||||
{
|
||||
// Check for incoming TLS handshake over HTTP
|
||||
if (IsTlsHandshake(requestLine, length))
|
||||
{
|
||||
throw GetInvalidRequestException(RequestRejectionReason.TlsOverHttpError, requestLine, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw GetInvalidRequestException(RequestRejectionReason.InvalidRequestLine, requestLine, length);
|
||||
}
|
||||
}
|
||||
|
||||
[StackTraceHidden]
|
||||
private unsafe void RejectRequestHeader(byte* headerLine, int length)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||
{
|
||||
internal enum RequestRejectionReason
|
||||
{
|
||||
TlsOverHttpError,
|
||||
UnrecognizedHTTPVersion,
|
||||
InvalidRequestLine,
|
||||
InvalidRequestHeader,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
|
@ -394,6 +394,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
|||
Assert.Equal(buffer.End, examined);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseRequestLineTlsOverHttp()
|
||||
{
|
||||
var parser = CreateParser(_nullTrace);
|
||||
var buffer = ReadOnlySequenceFactory.CreateSegments(new byte[] { 0x16, 0x03, 0x01, 0x02, 0x00, 0x01, 0x00, 0xfc, 0x03, 0x03, 0x03, 0xca, 0xe0, 0xfd, 0x0a });
|
||||
|
||||
var requestHandler = new RequestHandler();
|
||||
|
||||
var badHttpRequestException = Assert.Throws<BadHttpRequestException>(() =>
|
||||
{
|
||||
parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined);
|
||||
});
|
||||
|
||||
Assert.Equal(badHttpRequestException.StatusCode, StatusCodes.Status400BadRequest);
|
||||
Assert.Equal(RequestRejectionReason.TlsOverHttpError, badHttpRequestException.Reason);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseHeadersWithGratuitouslySplitBuffers()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue