Skip to content

Commit 0a3afc9

Browse files
authored
Clientruntime/sanitize request header (#28169)
* fix(ClientRuntime): sanitize request headers 1. add `HttpRequestSanitizer` to sanitize headers 2. update `HttpRequestMessageWrapper` to sanitive headers during headers copy 3. add test cases * prepare release notes of 2.3.24
1 parent 8724e58 commit 0a3afc9

File tree

5 files changed

+167
-3
lines changed

5 files changed

+167
-3
lines changed

sdk/mgmtcommon/ClientRuntime/ClientRuntime/HttpRequestMessageWrapper.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

4+
using Microsoft.Rest.Utilities;
45
using System;
56
using System.Collections.Generic;
67
using System.Net.Http;
@@ -26,6 +27,7 @@ public HttpRequestMessageWrapper(HttpRequestMessage httpRequest, string content)
2627

2728
this.CopyHeaders(httpRequest.Headers);
2829
this.CopyHeaders(httpRequest.GetContentHeaders());
30+
HttpRequestSanitizer.SanitizerHeaders(Headers);
2931

3032
this.Content = content;
3133
this.Method = httpRequest.Method;

sdk/mgmtcommon/ClientRuntime/ClientRuntime/Microsoft.Rest.ClientRuntime.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
<Description>Infrastructure for error handling, tracing, and HttpClient pipeline configuration. Required by client libraries generated using AutoRest.</Description>
44
<AssemblyName>Microsoft.Rest.ClientRuntime</AssemblyName>
55
<AssemblyTitle>Client Runtime Library for Microsoft AutoRest Generated Clients</AssemblyTitle>
6-
<Version>2.3.23</Version>
6+
<Version>2.3.24</Version>
77
<PackageId>Microsoft.Rest.ClientRuntime</PackageId>
88
<PackageTags>Microsoft AutoRest ClientRuntime $(NugetCommonTags) $(NugetCommonProfileTags)</PackageTags>
99
<PackageReleaseNotes>
1010
<![CDATA[
11-
Added support for specifying MaxRetries in RetryAfterDelegatingHandler.
11+
- Improving sanitization of exception messages. For details, see "CVE-2022-26907 - Security Update Guide - Microsoft - Azure SDK for .NET Information Disclosure Vulnerability": https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-26907
12+
- Optimize performance of parsing JSON content
1213
]]>
1314
</PackageReleaseNotes>
1415
</PropertyGroup>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
8+
namespace Microsoft.Rest.Utilities
9+
{
10+
/// <summary>
11+
/// Sanitizer used internall by <see cref="HttpRequestMessageWrapper"/>.
12+
/// </summary>
13+
internal class HttpRequestSanitizer
14+
{
15+
private readonly static string _redactedPlaceholder = "REDACTED";
16+
private readonly static HashSet<string> _allowedHeaders = new HashSet<string>(new string[]
17+
{
18+
"x-ms-request-id",
19+
"x-ms-client-request-id",
20+
"x-ms-return-client-request-id",
21+
"traceparent",
22+
"MS-CV",
23+
24+
"Accept",
25+
"Cache-Control",
26+
"Connection",
27+
"Content-Length",
28+
"Content-Type",
29+
"Date",
30+
"ETag",
31+
"Expires",
32+
"If-Match",
33+
"If-Modified-Since",
34+
"If-None-Match",
35+
"If-Unmodified-Since",
36+
"Last-Modified",
37+
"Pragma",
38+
"Request-Id",
39+
"Retry-After",
40+
"Server",
41+
"Transfer-Encoding",
42+
"User-Agent",
43+
"WWW-Authenticate" // OAuth Challenge header.
44+
}, StringComparer.OrdinalIgnoreCase);
45+
46+
/// <summary>
47+
/// Sanitize value of sensitive headers in the given <paramref name="headers"/>.
48+
/// </summary>
49+
/// <param name="headers">A collection of headers to sanitize.</param>
50+
public static void SanitizerHeaders(IDictionary<string, IEnumerable<string>> headers)
51+
{
52+
if (headers == null)
53+
{
54+
return;
55+
}
56+
57+
var namesOfHeaderToSanitize = headers.Keys.Except(_allowedHeaders, StringComparer.OrdinalIgnoreCase).ToList();
58+
59+
foreach (string name in namesOfHeaderToSanitize)
60+
{
61+
headers[name] = new string[] { _redactedPlaceholder };
62+
}
63+
}
64+
}
65+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.Rest.ClientRuntime.Tests
5+
{
6+
using System.Net;
7+
using System.Net.Http;
8+
using System.Collections.Generic;
9+
using Xunit;
10+
using System.Linq;
11+
12+
public class HttpRequestSanitizerTest
13+
{
14+
[Theory]
15+
[InlineData("authorization")]
16+
[InlineData("Authorization")]
17+
[InlineData("AUTHORIZATION")]
18+
public void SanitizeAuthorizationHeader(string headerName)
19+
{
20+
var request = CreateRequestWrapper(headerName, "test");
21+
22+
Assert.True(request.Headers.TryGetValue(HttpRequestHeader.Authorization.ToString(), out IEnumerable<string> sanitizedValues));
23+
Assert.Single(sanitizedValues);
24+
Assert.NotEqual("test", sanitizedValues.First());
25+
Assert.Equal("REDACTED", sanitizedValues.First());
26+
}
27+
28+
[Theory]
29+
[InlineData("custom")]
30+
[InlineData("foo")]
31+
[InlineData("x-ms-secret")]
32+
public void SanitizeCustomHeader(string headerName)
33+
{
34+
var request = CreateRequestWrapper(headerName, "test");
35+
36+
Assert.True(request.Headers.TryGetValue(headerName, out IEnumerable<string> sanitizedValues));
37+
Assert.Single(sanitizedValues);
38+
Assert.NotEqual("test", sanitizedValues.First());
39+
Assert.Equal("REDACTED", sanitizedValues.First());
40+
}
41+
42+
[Theory]
43+
[InlineData("Accept", "application/json")]
44+
[InlineData("User-Agent", "azure-sdk")]
45+
[InlineData("Pragma", "foo")]
46+
public void KeepAllowedHeaders(string headerName, string headerValue)
47+
{
48+
var request = CreateRequestWrapper(headerName, headerValue);
49+
50+
Assert.True(request.Headers.TryGetValue(headerName, out IEnumerable<string> sanitizedValues));
51+
Assert.Single(sanitizedValues);
52+
Assert.Equal(headerValue, sanitizedValues.First());
53+
}
54+
55+
[Theory]
56+
[InlineData("accept", "Accept", "application/json")]
57+
[InlineData("user-agent", "User-Agent", "azure-sdk")]
58+
[InlineData("pragma", "Pragma", "foo")]
59+
public void AllowedHeaderNamesAreCaseInsensitive(string headerName, string standardName, string headerValue)
60+
{
61+
var request = CreateRequestWrapper(headerName, headerValue);
62+
63+
Assert.True(request.Headers.TryGetValue(standardName, out IEnumerable<string> sanitizedValues));
64+
Assert.Single(sanitizedValues);
65+
Assert.Equal(headerValue, sanitizedValues.First());
66+
}
67+
68+
[Fact]
69+
public void OnlySanitizeNotAllowedHeader()
70+
{
71+
var request = CreateRequestWrapper("Authorization", "test");
72+
request.Headers.Add("Pragma", new string[] { "foo" });
73+
request.Headers.Add("User-Agent", new string[] { "azure-sdk" });
74+
75+
Assert.True(request.Headers.TryGetValue(HttpRequestHeader.Authorization.ToString(), out IEnumerable<string> sanitizedValues));
76+
Assert.Single(sanitizedValues);
77+
Assert.NotEqual("test", sanitizedValues.First());
78+
Assert.Equal("REDACTED", sanitizedValues.First());
79+
80+
Assert.True(request.Headers.TryGetValue("Pragma", out sanitizedValues));
81+
Assert.Single(sanitizedValues);
82+
Assert.Equal("foo", sanitizedValues.First());
83+
84+
Assert.True(request.Headers.TryGetValue("User-Agent", out sanitizedValues));
85+
Assert.Single(sanitizedValues);
86+
Assert.Equal("azure-sdk", sanitizedValues.First());
87+
}
88+
89+
private HttpRequestMessageWrapper CreateRequestWrapper(string headerName, string headerValue)
90+
{
91+
var request = new HttpRequestMessage();
92+
request.Headers.Add(headerName, headerValue);
93+
return new HttpRequestMessageWrapper(request, "");
94+
}
95+
}
96+
}

sdk/mgmtcommon/ClientRuntime/Tests/ClientRuntime.NetCore.Tests/ServiceClientTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ public void HeadersAndPayloadAreNotDisposed()
206206
GC.Collect();
207207
Assert.NotNull(ex.Request);
208208
Assert.NotNull(ex.Response);
209-
Assert.Equal("2013-11-01", ex.Request.Headers["x-ms-version"].First());
209+
Assert.Equal("REDACTED", ex.Request.Headers["x-ms-version"].First());
210210
Assert.Equal("Text", ex.Response.Content);
211211
}
212212
}

0 commit comments

Comments
 (0)