Skip to content
代码片段 群组 项目
提交 108c2218 编辑于 作者: Will Godbe's avatar Will Godbe
浏览文件

Merged PR 21240: [6.0] MSRC 70023 - ASP.Net FormFeature.cs - DenialOfService

# ASP.Net FormFeature.cs - DenialOfService

When parsing multi-part form data with FormFeature.cs, we do not honor ValueCountLimit when the content disposition is of an unknown type. Therefore an attacker could send multi-part form data where very part has invalid content disposition, and make us read indefinitely.

## Description

When parsing multi-part form data with FormFeature.cs, we do not honor ValueCountLimit when the content disposition is of an unknown type. Therefore an attacker could send multi-part form data where very part has invalid content disposition, and make us read indefinitely.

## Customer Impact

Prevents a potential Denial-of-service attack.

## Regression?

- [ ] Yes
- [x] No

## Risk

- [ ] High
- [x] Medium
- [ ] Low

We could have missed another potential version of this vulnerability

## Verification

- [x] Manual (required)
- [x] Automated

Added a test, plus confirmed with a local repro that the pre-existing slowdown goes away after the change.

## Packaging changes reviewed?

- [ ] Yes
- [ ] No
- [x] N/A

----

## When servicing release/2.1

- [ ] Make necessary changes in eng/PatchConfig.props
上级 1e1c8913
No related branches found
No related tags found
无相关合并请求
...@@ -184,6 +184,7 @@ namespace Microsoft.AspNetCore.Http.Features ...@@ -184,6 +184,7 @@ namespace Microsoft.AspNetCore.Http.Features
else if (HasMultipartFormContentType(contentType)) else if (HasMultipartFormContentType(contentType))
{ {
var formAccumulator = new KeyValueAccumulator(); var formAccumulator = new KeyValueAccumulator();
var nonFormOrFileContentDispositionCount = 0;
var boundary = GetBoundary(contentType, _options.MultipartBoundaryLengthLimit); var boundary = GetBoundary(contentType, _options.MultipartBoundaryLengthLimit);
var multipartReader = new MultipartReader(boundary, _request.Body) var multipartReader = new MultipartReader(boundary, _request.Body)
...@@ -259,7 +260,11 @@ namespace Microsoft.AspNetCore.Http.Features ...@@ -259,7 +260,11 @@ namespace Microsoft.AspNetCore.Http.Features
} }
else else
{ {
System.Diagnostics.Debug.Assert(false, "Unrecognized content-disposition for this section: " + section.ContentDisposition); if (nonFormOrFileContentDispositionCount++ >= _options.ValueCountLimit)
{
throw new InvalidDataException($"Unrecognized Content-Disposition. Form value count limit {_options.ValueCountLimit} exceeded.");
}
} }
section = await multipartReader.ReadNextSectionAsync(cancellationToken); section = await multipartReader.ReadNextSectionAsync(cancellationToken);
......
...@@ -165,6 +165,12 @@ namespace Microsoft.AspNetCore.Http.Features ...@@ -165,6 +165,12 @@ namespace Microsoft.AspNetCore.Http.Features
InvalidContentDispositionValue + InvalidContentDispositionValue +
"\r\n" + "\r\n" +
"\r\n" + "\r\n" +
"Foo\r\n";
private const string MultipartFormFileNonFormOrFileContentDispositionValue = "--WebKitFormBoundary5pDRpGheQXaM8k3T\r\n" +
"Content-Disposition:x" +
"\r\n" +
"\r\n" +
"Foo\r\n"; "Foo\r\n";
private const string MultipartFormWithField = private const string MultipartFormWithField =
...@@ -468,6 +474,30 @@ InvalidContentDispositionValue + ...@@ -468,6 +474,30 @@ InvalidContentDispositionValue +
Assert.Equal("Form value count limit 2 exceeded.", exception.Message); Assert.Equal("Form value count limit 2 exceeded.", exception.Message);
} }
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task ReadFormAsync_NonFormOrFieldContentDisposition_ValueCountLimitExceeded_Throw(bool bufferRequest)
{
var formContent = new List<byte>();
formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormFileNonFormOrFileContentDispositionValue));
formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormFileNonFormOrFileContentDispositionValue));
formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormFileNonFormOrFileContentDispositionValue));
formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormEnd));
var context = new DefaultHttpContext();
var responseFeature = new FakeResponseFeature();
context.Features.Set<IHttpResponseFeature>(responseFeature);
context.Request.ContentType = MultipartContentType;
context.Request.Body = new NonSeekableReadStream(formContent.ToArray());
IFormFeature formFeature = new FormFeature(context.Request, new FormOptions() { BufferBody = bufferRequest, ValueCountLimit = 2 });
context.Features.Set<IFormFeature>(formFeature);
var exception = await Assert.ThrowsAsync<InvalidDataException>(() => context.Request.ReadFormAsync());
Assert.Equal("Unrecognized Content-Disposition. Form value count limit 2 exceeded.", exception.Message);
}
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [InlineData(false)]
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册