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:
parent
296ca0f948
commit
c1e5640a65
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue