Skip to content

Commit ceea1fc

Browse files
committed
Merged PR 50419: Harden cookie parsing
Harden cookie parsing
1 parent 616c551 commit ceea1fc

File tree

2 files changed

+40
-7
lines changed

2 files changed

+40
-7
lines changed

src/Microsoft.Owin/Infrastructure/OwinHelpers.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ internal static partial class OwinHelpers
515515
}
516516
};
517517

518-
private static readonly char[] SemicolonAndComma = new[] { ';', ',' };
518+
private static readonly char[] Semicolon = new[] { ';' };
519519

520520
internal static IDictionary<string, string> GetCookies(IOwinRequest request)
521521
{
@@ -530,7 +530,7 @@ internal static IDictionary<string, string> GetCookies(IOwinRequest request)
530530
if (request.Get<string>("Microsoft.Owin.Cookies#text") != text)
531531
{
532532
cookies.Clear();
533-
ParseDelimited(text, SemicolonAndComma, AddCookieCallback, decodePlus: false, decodeKey: false, state: cookies);
533+
ParseDelimited(text, Semicolon, AddCookieCallback, decodePlus: false, decodeKey: false, state: cookies);
534534
request.Set("Microsoft.Owin.Cookies#text", text);
535535
}
536536
return cookies;
@@ -587,7 +587,9 @@ internal static partial class OwinHelpers
587587
public static string GetHeader(IDictionary<string, string[]> headers, string key)
588588
{
589589
string[] values = GetHeaderUnmodified(headers, key);
590-
return values == null ? null : string.Join(",", values);
590+
return values == null ? null
591+
: string.Equals("cookie", key, StringComparison.OrdinalIgnoreCase)
592+
? string.Join(";", values) : string.Join(",", values);
591593
}
592594

593595
public static IEnumerable<string> GetHeaderSplit(IDictionary<string, string[]> headers, string key)
Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4-
using System;
4+
using System.Linq;
55
using Xunit;
66

77
namespace Microsoft.Owin.Tests
@@ -11,8 +11,8 @@ public class RequestCookieTests
1111
[Theory]
1212
[InlineData("key=value", "key", "value")]
1313
[InlineData("__secure-key=value", "__secure-key", "value")]
14-
[InlineData("key%2C=%21value", "key,", "!value")]
15-
[InlineData("ke%23y%2C=val%5Eue", "ke#y,", "val^ue")]
14+
[InlineData("key%2C=%21value", "key%2C", "!value")]
15+
[InlineData("ke%23y%2C=val%5Eue", "ke%23y%2C", "val^ue")]
1616
[InlineData("base64=QUI%2BREU%2FRw%3D%3D", "base64", "QUI+REU/Rw==")]
1717
[InlineData("base64=QUI+REU/Rw==", "base64", "QUI+REU/Rw==")]
1818
public void UnEscapesValues(string input, string expectedKey, string expectedValue)
@@ -22,8 +22,39 @@ public void UnEscapesValues(string input, string expectedKey, string expectedVal
2222
var cookies = context.Cookies;
2323

2424
var cookie = Assert.Single(cookies);
25-
Assert.Equal(Uri.EscapeDataString(expectedKey), cookie.Key);
25+
Assert.Equal(expectedKey, cookie.Key);
2626
Assert.Equal(expectedValue, cookies[expectedKey]);
2727
}
28+
29+
[Theory]
30+
[InlineData("key", null, null)]
31+
[InlineData("=,key=value", new[] { "" }, new[] { ",key=value" })]
32+
[InlineData(",key=value", new[] { ",key" }, new[] { "value" })]
33+
[InlineData(",key=value; key=value2", new[] { ",key", "key" }, new[] { "value", "value2" })]
34+
[InlineData("key=value; ,key2=value2", new[] { "key", ",key2" }, new[] { "value", "value2" })]
35+
[InlineData("%6bey=value; key=value2", new[] { "%6bey", "key" }, new[] { "value", "value2" })]
36+
[InlineData("key=value; key2=value2", new[] { "key", "key2" }, new[] { "value", "value2" })]
37+
[InlineData("key=value; key=value2", new[] { "key" }, new[] { "value" })]
38+
public void ParseCookies(string input, string[] expectedKeys, string[] expectedValues)
39+
{
40+
var context = new OwinRequest();
41+
context.Headers["Cookie"] = input;
42+
var cookies = context.Cookies.ToArray();
43+
44+
if (expectedKeys == null)
45+
{
46+
Assert.Empty(cookies);
47+
}
48+
else
49+
{
50+
Assert.Equal(expectedKeys.Length, cookies.Length);
51+
52+
for (var i = 0; i < expectedKeys.Length; i++)
53+
{
54+
Assert.Equal(expectedKeys[i], cookies[i].Key);
55+
Assert.Equal(expectedValues[i], cookies[i].Value);
56+
}
57+
}
58+
}
2859
}
2960
}

0 commit comments

Comments
 (0)