C#: ASP.NET Core like members are tainted#9393
Conversation
878529e to
afb8d97
Compare
|
DCA run looks fine. |
tamasvajk
left a comment
There was a problem hiding this comment.
I think we should add a change note. It has an impact on a wide audience.
Makes sense. I will add a change note. |
| public class ViewModel | ||
| { | ||
| public string RequestId { get; set; } | ||
|
|
||
| public object Query; | ||
| } | ||
|
|
||
| public class TestController : Controller | ||
| { | ||
| public object MyAction(ViewModel viewModel) | ||
| { | ||
| throw null; | ||
| } | ||
| } |
There was a problem hiding this comment.
Just to be sure, could you add a class without any reference to it?
public class UnusedViewModel
{
public string RequestId { get; set; }
public object Query;
}
My expectation would be that its properties don't show up in remoteFlowSourceMembers.
There was a problem hiding this comment.
Yes, that is correct. In Remote.qll RemoteFlowSource are only extended on types used as parameter types on methods in Controller like classes.
| public class ViewModel | ||
| { | ||
| public string RequestId { get; set; } | ||
|
|
||
| public object Query; | ||
| } |
There was a problem hiding this comment.
Nit picking, but what happens with get-only properties and private or static members?
There was a problem hiding this comment.
Hmm, they are also included. There is no further restrictions on the Assignable members. Let's change this such that it is only public and non static assignable members.
Good catch!
There was a problem hiding this comment.
Also - this is not nit picking! Really good that you ask these questions!
There was a problem hiding this comment.
We can also fine-grain it even more. Do you have any special opinion on, which members we should included/exclude?
There was a problem hiding this comment.
I'm not an expert on this. A quick google search revealed that (of course) this can be customized in asp.net. But in any case, I think if we mimic what the DefaultModelBinder does, we probably handle 95% of the cases correctly. I couldn't find an explicit list of the requirements on members, but it looks like only public non-static properties are handled. Also, properties with private setters are excluded as per dotnet/aspnetcore#38243. Also, maybe the class/record needs to have a default constructor. But I think we should dig a bit more deeply into the documentation.
There was a problem hiding this comment.
@tamasvajk : Thank you!
Ah yes, I think you are right. I read some of this (I know it is old): https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/february/asp-net-mvc-the-features-and-foibles-of-asp-net-mvc-model-binding
It doesn't explicitly state that properties should be get/set, but it seems like it is implicitly assumed and this could serve is a conservative extension of the existing logic (cover more with lower risk of false positives).
My suggestion would be that we take all public properties with public getters and setters and all public non-readonly fields. No statics allowed of course. Then we should be on the safe side and also cover most cases!
There was a problem hiding this comment.
I think we can ignore fields altogether. There are some commonly used attributes to specify from where data should be bound. For example if data is taken from the request body, then FromBody is used: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.frombodyattribute?view=aspnetcore-6.0. These attributes have no Field target, so I think we can safely ignore fields.
There was a problem hiding this comment.
Alright! ASP.NET is complicated :-) It looks like the canonical examples all uses public (non static) auto implemented properties with public getters and setters. Maybe that is sufficiently conservative as a starting point.
…ources of tainted data.
b512a19 to
0fa7ddf
Compare
0fa7ddf to
f7f83a0
Compare
…blic getters and setters as being tainted.
f7f83a0 to
9211d75
Compare
|
Confirmed - Fixed in 2.10.0 CLI bundle and 0.2.0 codeql/csharp-queries (changelog) Forcing Action to 2.10.0 lights up a bunch of alerts that were missing for me ( new alerts on complex types) |
| abstract class AspNetCoreRemoteFlowSource extends RemoteFlowSource { } | ||
|
|
||
| /** | ||
| * Data flow for AST.NET Core. |
| private class AspNetCoreRemoteFlowSourceMember extends TaintTracking::TaintedMember { | ||
| AspNetCoreRemoteFlowSourceMember() { | ||
| this.getDeclaringType() = any(AspNetCoreRemoteFlowSource source).getType() and | ||
| this.isPublic() and | ||
| not this.isStatic() and | ||
| exists(Property p | p = this | | ||
| p.isAutoImplemented() and p.getGetter().isPublic() and p.getSetter().isPublic() | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
Can be simplified a bit:
private class AspNetCoreRemoteFlowSourceMember extends TaintTracking::TaintedMember, Property {
AspNetCoreRemoteFlowSourceMember() {
this.getDeclaringType() = any(AspNetCoreRemoteFlowSource source).getType() and
this.isPublic() and
not this.isStatic() and
this.isAutoImplemented() and
this.getGetter().isPublic() and
this.getSetter().isPublic()
}
}
Consider all properties of ASP.NET Core like objects to also be sources of tainted data.
I have taken the liberty to collapse a couple of remote flow source types into one type (everything related to ASP.Net Core) and then only perceive members of these to be tainted as well instead of doing it generally for all remote flow sources.