Accessing Content Security Policy violation reports posted to ASP.Net
up vote
1
down vote
favorite
For example if you have a CSP like
default-src 'self'; report-uri /CspViolationReport
and if /CspViolationReport
is handled by ASP.Net, how do you access the CSP violation report that is posted?
We expect to find some JSON posted, e.g. http://www.w3.org/TR/CSP11/#example-violation-report
When you inspect Request.Form
, there are no keys, and there is no evidence of it in Request.ServerVariables["ALL_RAW"]
, but Request.ServerVariables["HTTP_METHOD"]
is "POST".
Intercepting the POST with Fiddler, you can see that the JSON is certainly being posted, but .Net doesn't seem to let you see it.
asp.net content-security-policy
add a comment |
up vote
1
down vote
favorite
For example if you have a CSP like
default-src 'self'; report-uri /CspViolationReport
and if /CspViolationReport
is handled by ASP.Net, how do you access the CSP violation report that is posted?
We expect to find some JSON posted, e.g. http://www.w3.org/TR/CSP11/#example-violation-report
When you inspect Request.Form
, there are no keys, and there is no evidence of it in Request.ServerVariables["ALL_RAW"]
, but Request.ServerVariables["HTTP_METHOD"]
is "POST".
Intercepting the POST with Fiddler, you can see that the JSON is certainly being posted, but .Net doesn't seem to let you see it.
asp.net content-security-policy
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
For example if you have a CSP like
default-src 'self'; report-uri /CspViolationReport
and if /CspViolationReport
is handled by ASP.Net, how do you access the CSP violation report that is posted?
We expect to find some JSON posted, e.g. http://www.w3.org/TR/CSP11/#example-violation-report
When you inspect Request.Form
, there are no keys, and there is no evidence of it in Request.ServerVariables["ALL_RAW"]
, but Request.ServerVariables["HTTP_METHOD"]
is "POST".
Intercepting the POST with Fiddler, you can see that the JSON is certainly being posted, but .Net doesn't seem to let you see it.
asp.net content-security-policy
For example if you have a CSP like
default-src 'self'; report-uri /CspViolationReport
and if /CspViolationReport
is handled by ASP.Net, how do you access the CSP violation report that is posted?
We expect to find some JSON posted, e.g. http://www.w3.org/TR/CSP11/#example-violation-report
When you inspect Request.Form
, there are no keys, and there is no evidence of it in Request.ServerVariables["ALL_RAW"]
, but Request.ServerVariables["HTTP_METHOD"]
is "POST".
Intercepting the POST with Fiddler, you can see that the JSON is certainly being posted, but .Net doesn't seem to let you see it.
asp.net content-security-policy
asp.net content-security-policy
edited Jan 9 '15 at 2:10
asked Jan 8 '15 at 21:56
franzo
796724
796724
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
up vote
2
down vote
accepted
Here's a way, inspired by http://muaz-khan.blogspot.co.nz/2012/06/exploring-csp-content-security-policy.html, thanks!
void ProcessCspValidationReport() {
Request.InputStream.Position = 0;
using (StreamReader inputStream = new StreamReader(Request.InputStream))
{
string s = inputStream.ReadToEnd();
if (!string.IsNullOrWhiteSpace(s))
{
CspPost cspPost = JsonConvert.DeserializeObject<CspPost>(s);
//now you can access properties of cspPost.CspReport
}
}
}
class CspPost
{
[JsonProperty("csp-report")]
public CspReport CspReport { get; set; }
}
class CspReport
{
[JsonProperty("document-uri")]
public string DocumentUri { get; set; }
[JsonProperty("referrer")]
public string Referrer { get; set; }
[JsonProperty("effective-directive")]
public string EffectiveDirective { get; set; }
[JsonProperty("violated-directive")]
public string ViolatedDirective { get; set; }
[JsonProperty("original-policy")]
public string OriginalPolicy { get; set; }
[JsonProperty("blocked-uri")]
public string BlockedUri { get; set; }
[JsonProperty("source-file")]
public string SourceFile { get; set; }
[JsonProperty("line-number")]
public int LineNumber { get; set; }
[JsonProperty("column-number")]
public int ColumnNumber { get; set; }
[JsonProperty("status-code")]
public string StatusCode { get; set; }
}
add a comment |
up vote
0
down vote
Or you might just try CspBuilder.info :)
add a comment |
up vote
0
down vote
Here's one using DataContractJsonSerializer
which is in namespaces System.Runtime.Serialization
and System.Runtime.Serialization.Json
no other libraries required, it's all in the .NET Framework.
Controller:
public class ReportingController : Controller
{
[HttpPost]
public void CspReport()
{
var context = System.Web.HttpContext.Current;
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = Encoding.UTF8;
using (IO.Stream body = context.Request.InputStream) {
var ser = new DataContractJsonSerializer(typeof(CspReportContainer));
var report = (CspReportContainer)ser.ReadObject(body);
ReportingControllerHelper.LogCspReport(report.Report);
}
}
}
Model:
[DataContract()]
public class CspReportContainer
{
[DataMember(Name = "csp-report")]
public CspReport Report { get; set; }
}
[DataContract()]
public class CspReport
{
[DataMember(Name = "blocked-uri")]
public string BlockedUri { get; set; }
[DataMember(Name = "column-number")]
public int? ColumnNumber { get; set; }
[DataMember(Name = "document-uri")]
public string DocumentUri { get; set; }
[DataMember(Name = "effective-directive")]
public string EffectiveDirective { get; set; }
[DataMember(Name = "line-number")]
public int? LineNumber { get; set; }
[DataMember(Name = "original-policy")]
public string OriginalPolicy { get; set; }
[DataMember(Name = "referrer")]
public string Referrer { get; set; }
[DataMember(Name = "source-file")]
public string SourceFile { get; set; }
[DataMember(Name = "status-code")]
public int? StatusCode { get; set; }
[DataMember(Name = "violated-directive")]
public string ViolatedDirective { get; set; }
}
add a comment |
up vote
0
down vote
The problem might be with content-type of request: application/csp-report. I just added to WebApiConfig:
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(
new System.Net.Http.Headers.MediaTypeHeaderValue("application/csp-report"));
Of course you also need clases form other answers: CspReportContainer, CspReport
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f27850216%2faccessing-content-security-policy-violation-reports-posted-to-asp-net%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
Here's a way, inspired by http://muaz-khan.blogspot.co.nz/2012/06/exploring-csp-content-security-policy.html, thanks!
void ProcessCspValidationReport() {
Request.InputStream.Position = 0;
using (StreamReader inputStream = new StreamReader(Request.InputStream))
{
string s = inputStream.ReadToEnd();
if (!string.IsNullOrWhiteSpace(s))
{
CspPost cspPost = JsonConvert.DeserializeObject<CspPost>(s);
//now you can access properties of cspPost.CspReport
}
}
}
class CspPost
{
[JsonProperty("csp-report")]
public CspReport CspReport { get; set; }
}
class CspReport
{
[JsonProperty("document-uri")]
public string DocumentUri { get; set; }
[JsonProperty("referrer")]
public string Referrer { get; set; }
[JsonProperty("effective-directive")]
public string EffectiveDirective { get; set; }
[JsonProperty("violated-directive")]
public string ViolatedDirective { get; set; }
[JsonProperty("original-policy")]
public string OriginalPolicy { get; set; }
[JsonProperty("blocked-uri")]
public string BlockedUri { get; set; }
[JsonProperty("source-file")]
public string SourceFile { get; set; }
[JsonProperty("line-number")]
public int LineNumber { get; set; }
[JsonProperty("column-number")]
public int ColumnNumber { get; set; }
[JsonProperty("status-code")]
public string StatusCode { get; set; }
}
add a comment |
up vote
2
down vote
accepted
Here's a way, inspired by http://muaz-khan.blogspot.co.nz/2012/06/exploring-csp-content-security-policy.html, thanks!
void ProcessCspValidationReport() {
Request.InputStream.Position = 0;
using (StreamReader inputStream = new StreamReader(Request.InputStream))
{
string s = inputStream.ReadToEnd();
if (!string.IsNullOrWhiteSpace(s))
{
CspPost cspPost = JsonConvert.DeserializeObject<CspPost>(s);
//now you can access properties of cspPost.CspReport
}
}
}
class CspPost
{
[JsonProperty("csp-report")]
public CspReport CspReport { get; set; }
}
class CspReport
{
[JsonProperty("document-uri")]
public string DocumentUri { get; set; }
[JsonProperty("referrer")]
public string Referrer { get; set; }
[JsonProperty("effective-directive")]
public string EffectiveDirective { get; set; }
[JsonProperty("violated-directive")]
public string ViolatedDirective { get; set; }
[JsonProperty("original-policy")]
public string OriginalPolicy { get; set; }
[JsonProperty("blocked-uri")]
public string BlockedUri { get; set; }
[JsonProperty("source-file")]
public string SourceFile { get; set; }
[JsonProperty("line-number")]
public int LineNumber { get; set; }
[JsonProperty("column-number")]
public int ColumnNumber { get; set; }
[JsonProperty("status-code")]
public string StatusCode { get; set; }
}
add a comment |
up vote
2
down vote
accepted
up vote
2
down vote
accepted
Here's a way, inspired by http://muaz-khan.blogspot.co.nz/2012/06/exploring-csp-content-security-policy.html, thanks!
void ProcessCspValidationReport() {
Request.InputStream.Position = 0;
using (StreamReader inputStream = new StreamReader(Request.InputStream))
{
string s = inputStream.ReadToEnd();
if (!string.IsNullOrWhiteSpace(s))
{
CspPost cspPost = JsonConvert.DeserializeObject<CspPost>(s);
//now you can access properties of cspPost.CspReport
}
}
}
class CspPost
{
[JsonProperty("csp-report")]
public CspReport CspReport { get; set; }
}
class CspReport
{
[JsonProperty("document-uri")]
public string DocumentUri { get; set; }
[JsonProperty("referrer")]
public string Referrer { get; set; }
[JsonProperty("effective-directive")]
public string EffectiveDirective { get; set; }
[JsonProperty("violated-directive")]
public string ViolatedDirective { get; set; }
[JsonProperty("original-policy")]
public string OriginalPolicy { get; set; }
[JsonProperty("blocked-uri")]
public string BlockedUri { get; set; }
[JsonProperty("source-file")]
public string SourceFile { get; set; }
[JsonProperty("line-number")]
public int LineNumber { get; set; }
[JsonProperty("column-number")]
public int ColumnNumber { get; set; }
[JsonProperty("status-code")]
public string StatusCode { get; set; }
}
Here's a way, inspired by http://muaz-khan.blogspot.co.nz/2012/06/exploring-csp-content-security-policy.html, thanks!
void ProcessCspValidationReport() {
Request.InputStream.Position = 0;
using (StreamReader inputStream = new StreamReader(Request.InputStream))
{
string s = inputStream.ReadToEnd();
if (!string.IsNullOrWhiteSpace(s))
{
CspPost cspPost = JsonConvert.DeserializeObject<CspPost>(s);
//now you can access properties of cspPost.CspReport
}
}
}
class CspPost
{
[JsonProperty("csp-report")]
public CspReport CspReport { get; set; }
}
class CspReport
{
[JsonProperty("document-uri")]
public string DocumentUri { get; set; }
[JsonProperty("referrer")]
public string Referrer { get; set; }
[JsonProperty("effective-directive")]
public string EffectiveDirective { get; set; }
[JsonProperty("violated-directive")]
public string ViolatedDirective { get; set; }
[JsonProperty("original-policy")]
public string OriginalPolicy { get; set; }
[JsonProperty("blocked-uri")]
public string BlockedUri { get; set; }
[JsonProperty("source-file")]
public string SourceFile { get; set; }
[JsonProperty("line-number")]
public int LineNumber { get; set; }
[JsonProperty("column-number")]
public int ColumnNumber { get; set; }
[JsonProperty("status-code")]
public string StatusCode { get; set; }
}
answered Jan 9 '15 at 0:13
franzo
796724
796724
add a comment |
add a comment |
up vote
0
down vote
Or you might just try CspBuilder.info :)
add a comment |
up vote
0
down vote
Or you might just try CspBuilder.info :)
add a comment |
up vote
0
down vote
up vote
0
down vote
Or you might just try CspBuilder.info :)
Or you might just try CspBuilder.info :)
answered Jan 9 '15 at 22:12
kravietz
5,43311918
5,43311918
add a comment |
add a comment |
up vote
0
down vote
Here's one using DataContractJsonSerializer
which is in namespaces System.Runtime.Serialization
and System.Runtime.Serialization.Json
no other libraries required, it's all in the .NET Framework.
Controller:
public class ReportingController : Controller
{
[HttpPost]
public void CspReport()
{
var context = System.Web.HttpContext.Current;
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = Encoding.UTF8;
using (IO.Stream body = context.Request.InputStream) {
var ser = new DataContractJsonSerializer(typeof(CspReportContainer));
var report = (CspReportContainer)ser.ReadObject(body);
ReportingControllerHelper.LogCspReport(report.Report);
}
}
}
Model:
[DataContract()]
public class CspReportContainer
{
[DataMember(Name = "csp-report")]
public CspReport Report { get; set; }
}
[DataContract()]
public class CspReport
{
[DataMember(Name = "blocked-uri")]
public string BlockedUri { get; set; }
[DataMember(Name = "column-number")]
public int? ColumnNumber { get; set; }
[DataMember(Name = "document-uri")]
public string DocumentUri { get; set; }
[DataMember(Name = "effective-directive")]
public string EffectiveDirective { get; set; }
[DataMember(Name = "line-number")]
public int? LineNumber { get; set; }
[DataMember(Name = "original-policy")]
public string OriginalPolicy { get; set; }
[DataMember(Name = "referrer")]
public string Referrer { get; set; }
[DataMember(Name = "source-file")]
public string SourceFile { get; set; }
[DataMember(Name = "status-code")]
public int? StatusCode { get; set; }
[DataMember(Name = "violated-directive")]
public string ViolatedDirective { get; set; }
}
add a comment |
up vote
0
down vote
Here's one using DataContractJsonSerializer
which is in namespaces System.Runtime.Serialization
and System.Runtime.Serialization.Json
no other libraries required, it's all in the .NET Framework.
Controller:
public class ReportingController : Controller
{
[HttpPost]
public void CspReport()
{
var context = System.Web.HttpContext.Current;
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = Encoding.UTF8;
using (IO.Stream body = context.Request.InputStream) {
var ser = new DataContractJsonSerializer(typeof(CspReportContainer));
var report = (CspReportContainer)ser.ReadObject(body);
ReportingControllerHelper.LogCspReport(report.Report);
}
}
}
Model:
[DataContract()]
public class CspReportContainer
{
[DataMember(Name = "csp-report")]
public CspReport Report { get; set; }
}
[DataContract()]
public class CspReport
{
[DataMember(Name = "blocked-uri")]
public string BlockedUri { get; set; }
[DataMember(Name = "column-number")]
public int? ColumnNumber { get; set; }
[DataMember(Name = "document-uri")]
public string DocumentUri { get; set; }
[DataMember(Name = "effective-directive")]
public string EffectiveDirective { get; set; }
[DataMember(Name = "line-number")]
public int? LineNumber { get; set; }
[DataMember(Name = "original-policy")]
public string OriginalPolicy { get; set; }
[DataMember(Name = "referrer")]
public string Referrer { get; set; }
[DataMember(Name = "source-file")]
public string SourceFile { get; set; }
[DataMember(Name = "status-code")]
public int? StatusCode { get; set; }
[DataMember(Name = "violated-directive")]
public string ViolatedDirective { get; set; }
}
add a comment |
up vote
0
down vote
up vote
0
down vote
Here's one using DataContractJsonSerializer
which is in namespaces System.Runtime.Serialization
and System.Runtime.Serialization.Json
no other libraries required, it's all in the .NET Framework.
Controller:
public class ReportingController : Controller
{
[HttpPost]
public void CspReport()
{
var context = System.Web.HttpContext.Current;
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = Encoding.UTF8;
using (IO.Stream body = context.Request.InputStream) {
var ser = new DataContractJsonSerializer(typeof(CspReportContainer));
var report = (CspReportContainer)ser.ReadObject(body);
ReportingControllerHelper.LogCspReport(report.Report);
}
}
}
Model:
[DataContract()]
public class CspReportContainer
{
[DataMember(Name = "csp-report")]
public CspReport Report { get; set; }
}
[DataContract()]
public class CspReport
{
[DataMember(Name = "blocked-uri")]
public string BlockedUri { get; set; }
[DataMember(Name = "column-number")]
public int? ColumnNumber { get; set; }
[DataMember(Name = "document-uri")]
public string DocumentUri { get; set; }
[DataMember(Name = "effective-directive")]
public string EffectiveDirective { get; set; }
[DataMember(Name = "line-number")]
public int? LineNumber { get; set; }
[DataMember(Name = "original-policy")]
public string OriginalPolicy { get; set; }
[DataMember(Name = "referrer")]
public string Referrer { get; set; }
[DataMember(Name = "source-file")]
public string SourceFile { get; set; }
[DataMember(Name = "status-code")]
public int? StatusCode { get; set; }
[DataMember(Name = "violated-directive")]
public string ViolatedDirective { get; set; }
}
Here's one using DataContractJsonSerializer
which is in namespaces System.Runtime.Serialization
and System.Runtime.Serialization.Json
no other libraries required, it's all in the .NET Framework.
Controller:
public class ReportingController : Controller
{
[HttpPost]
public void CspReport()
{
var context = System.Web.HttpContext.Current;
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = Encoding.UTF8;
using (IO.Stream body = context.Request.InputStream) {
var ser = new DataContractJsonSerializer(typeof(CspReportContainer));
var report = (CspReportContainer)ser.ReadObject(body);
ReportingControllerHelper.LogCspReport(report.Report);
}
}
}
Model:
[DataContract()]
public class CspReportContainer
{
[DataMember(Name = "csp-report")]
public CspReport Report { get; set; }
}
[DataContract()]
public class CspReport
{
[DataMember(Name = "blocked-uri")]
public string BlockedUri { get; set; }
[DataMember(Name = "column-number")]
public int? ColumnNumber { get; set; }
[DataMember(Name = "document-uri")]
public string DocumentUri { get; set; }
[DataMember(Name = "effective-directive")]
public string EffectiveDirective { get; set; }
[DataMember(Name = "line-number")]
public int? LineNumber { get; set; }
[DataMember(Name = "original-policy")]
public string OriginalPolicy { get; set; }
[DataMember(Name = "referrer")]
public string Referrer { get; set; }
[DataMember(Name = "source-file")]
public string SourceFile { get; set; }
[DataMember(Name = "status-code")]
public int? StatusCode { get; set; }
[DataMember(Name = "violated-directive")]
public string ViolatedDirective { get; set; }
}
edited Aug 3 '17 at 14:15
answered Nov 4 '16 at 18:56
Robin French
475416
475416
add a comment |
add a comment |
up vote
0
down vote
The problem might be with content-type of request: application/csp-report. I just added to WebApiConfig:
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(
new System.Net.Http.Headers.MediaTypeHeaderValue("application/csp-report"));
Of course you also need clases form other answers: CspReportContainer, CspReport
add a comment |
up vote
0
down vote
The problem might be with content-type of request: application/csp-report. I just added to WebApiConfig:
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(
new System.Net.Http.Headers.MediaTypeHeaderValue("application/csp-report"));
Of course you also need clases form other answers: CspReportContainer, CspReport
add a comment |
up vote
0
down vote
up vote
0
down vote
The problem might be with content-type of request: application/csp-report. I just added to WebApiConfig:
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(
new System.Net.Http.Headers.MediaTypeHeaderValue("application/csp-report"));
Of course you also need clases form other answers: CspReportContainer, CspReport
The problem might be with content-type of request: application/csp-report. I just added to WebApiConfig:
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(
new System.Net.Http.Headers.MediaTypeHeaderValue("application/csp-report"));
Of course you also need clases form other answers: CspReportContainer, CspReport
edited Nov 15 at 16:32
answered Nov 15 at 16:12
Tomasz Rzepecki
113
113
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f27850216%2faccessing-content-security-policy-violation-reports-posted-to-asp-net%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown