Don't allow response headers to contain control characters

- For the purposes of this commit, control characters are everything < 0x20.
- Immediately throw an InvalidOperationException when the header is added to
  the IHttpResponseFeature.Headers dictionary.
This commit is contained in:
Stephen Halter 2016-04-21 14:17:38 -07:00
parent 296ca0f948
commit c1e5640a65
3 changed files with 38 additions and 11 deletions

View File

@ -2038,6 +2038,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
}
protected override void SetValueFast(string key, StringValues value)
{
switch (key.Length)
{
case 13:
@ -2424,10 +2425,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
}
break;
}
Unknown[key] = value;
}
protected override void AddValueFast(string key, StringValues value)
{
switch (key.Length)
{
case 13:
@ -2990,6 +2993,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
}
break;
}
Unknown.Add(key, value);
}
protected override bool RemoveFast(string key)
@ -7181,6 +7185,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
}
protected override void SetValueFast(string key, StringValues value)
{
ValidateHeaderCharacters(value);
switch (key.Length)
{
case 13:
@ -7512,10 +7517,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
}
break;
}
ValidateHeaderCharacters(key);
Unknown[key] = value;
}
protected override void AddValueFast(string key, StringValues value)
{
ValidateHeaderCharacters(value);
switch (key.Length)
{
case 13:
@ -7991,6 +7998,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
}
break;
}
ValidateHeaderCharacters(key);
Unknown.Add(key, value);
}
protected override bool RemoveFast(string key)

View File

@ -39,21 +39,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{
get
{
// Unlike the IHeaderDictionary version, this getter will throw a KeyNotFoundException.
return GetValueFast(key);
}
set
{
if (_isReadOnly)
{
ThrowReadOnlyException();
}
SetValueFast(key, value);
((IHeaderDictionary)this)[key] = value;
}
}
protected void ThrowReadOnlyException()
{
throw new InvalidOperationException("Headers are readonly, reponse has already started.");
throw new InvalidOperationException("Headers are read-only, response has already started.");
}
protected void ThrowArgumentException()
@ -140,11 +137,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
void ICollection<KeyValuePair<string, StringValues>>.Add(KeyValuePair<string, StringValues> item)
{
if (_isReadOnly)
{
ThrowReadOnlyException();
}
AddValueFast(item.Key, item.Value);
((IDictionary<string, StringValues>)this).Add(item.Key, item.Value);
}
void IDictionary<string, StringValues>.Add(string key, StringValues value)
@ -216,5 +209,27 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{
return TryGetValueFast(key, out value);
}
public static void ValidateHeaderCharacters(StringValues headerValues)
{
foreach (var value in headerValues)
{
ValidateHeaderCharacters(value);
}
}
public static void ValidateHeaderCharacters(string headerCharacters)
{
if (headerCharacters != null)
{
foreach (var ch in headerCharacters)
{
if (ch < 0x20)
{
throw new InvalidOperationException(string.Format("Invalid control character in header: 0x{0:X2}", (byte)ch));
}
}
}
}
}
}

View File

@ -299,6 +299,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
}}
protected override void SetValueFast(string key, StringValues value)
{{
{(loop.ClassName == "FrameResponseHeaders" ? "ValidateHeaderCharacters(value);" : "")}
switch (key.Length)
{{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}:
@ -313,10 +314,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
")}}}
break;
")}}}
{(loop.ClassName == "FrameResponseHeaders" ? "ValidateHeaderCharacters(key);" : "")}
Unknown[key] = value;
}}
protected override void AddValueFast(string key, StringValues value)
{{
{(loop.ClassName == "FrameResponseHeaders" ? "ValidateHeaderCharacters(value);" : "")}
switch (key.Length)
{{{Each(loop.HeadersByLength, byLength => $@"
case {byLength.Key}:
@ -335,6 +338,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
")}}}
break;
")}}}
{(loop.ClassName == "FrameResponseHeaders" ? "ValidateHeaderCharacters(key);" : "")}
Unknown.Add(key, value);
}}
protected override bool RemoveFast(string key)