From 8bae79d9ceb1410f10c779f37ab2f3f29fd83313 Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Wed, 15 Jan 2025 13:26:00 -0500 Subject: [PATCH 01/12] Components file --- .../microsoft/aspnetcore/Components.qll | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll new file mode 100644 index 000000000000..0ea7f936b2e5 --- /dev/null +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll @@ -0,0 +1,136 @@ +/** Provides classes for working with `Microsoft.AspNetCore.Components` */ + +import csharp +import semmle.code.csharp.frameworks.Microsoft +import semmle.code.csharp.frameworks.microsoft.AspNetCore + +/** The `Microsoft.AspNetCore.Components` namespace */ +class MicrosoftAspNetCoreComponentsNamespace extends Namespace { + MicrosoftAspNetCoreComponentsNamespace() { + this.getParentNamespace() instanceof MicrosoftAspNetCoreNamespace and + this.hasName("Components") + } +} + +/** + * A class in the `Microsoft.AspNetCore.Components` namespace. + */ +private class MicrosoftAspNetCoreComponentsClass extends Class { + MicrosoftAspNetCoreComponentsClass() { + this.getNamespace() instanceof MicrosoftAspNetCoreComponentsNamespace + } +} + +/** The `Microsoft.AspNetCore.Components.ParameterAttribute` class. */ +class MicrosoftAspNetCoreComponentsParamaterAttributeClass extends MicrosoftAspNetCoreComponentsClass +{ + MicrosoftAspNetCoreComponentsParamaterAttributeClass() { this.hasName("ParameterAttribute") } +} + +/** The `Microsoft.AspNetCore.Components.CascadingParameterAttributeBase` class. */ +class MicrosoftAspNetCoreComponentsCascadingParameterAttributeBaseClass extends MicrosoftAspNetCoreComponentsClass +{ + MicrosoftAspNetCoreComponentsCascadingParameterAttributeBaseClass() { + this.hasName("CascadingParameterAttributeBase") + } +} + +/** The `Microsoft.AspNetCore.Components.ComponentBase` class. */ +class MicrosoftAspNetCoreComponentsComponentBaseClass extends MicrosoftAspNetCoreComponentsClass { + MicrosoftAspNetCoreComponentsComponentBaseClass() { this.hasName("ComponentBase") } +} + +/** The `Microsoft.AspNetCore.Components.IComponent` interface. */ +class MicrosoftAspNetCoreComponentsIComponentInterface extends Interface { + MicrosoftAspNetCoreComponentsIComponentInterface() { + this.getNamespace() instanceof MicrosoftAspNetCoreComponentsNamespace and + this.hasName("IComponent") + } +} + +/** The `Microsoft.AspNetCore.Components.RouteAttribute` attribute. */ +private class MicrosoftAspNetCoreComponentsRouteAttribute extends Attribute { + MicrosoftAspNetCoreComponentsRouteAttribute() { + this.getType().getNamespace() instanceof MicrosoftAspNetCoreComponentsNamespace and + this.getType().hasName("RouteAttribute") + } +} + +/** The `Microsoft.AspNetCore.Components.ParameterAttribute` attribute. */ +private class MicrosoftAspNetCoreComponentsParameterAttribute extends Attribute { + MicrosoftAspNetCoreComponentsParameterAttribute() { + this.getType().getNamespace() instanceof MicrosoftAspNetCoreComponentsNamespace and + this.getType().hasName("ParameterAttribute") + } +} + +/** An ASP.NET Core (Blazor) component. */ +class MicrosoftAspNetCoreComponentsComponent extends Class { + MicrosoftAspNetCoreComponentsComponent() { + this.getABaseType+() instanceof MicrosoftAspNetCoreComponentsComponentBaseClass or + this.getABaseType+() instanceof MicrosoftAspNetCoreComponentsIComponentInterface + } + + /** Gets a property whose value cascades down the component hierarchy. */ + Property getACascadingParameterProperty() { + result = this.getAProperty() and + result.getAnAttribute().getType().getBaseClass() instanceof + MicrosoftAspNetCoreComponentsCascadingParameterAttributeBaseClass + } + + /** Gets the url for the route from the `Microsoft.AspNetCore.Components.RouteAttribute` of the component. */ + private string getRouteAttributeUrl() { + exists(MicrosoftAspNetCoreComponentsRouteAttribute a | a = this.getAnAttribute() | + result = a.getArgument(0).getValue() + ) + } + + /** + * Gets a route parameter from the `Microsoft.AspNetCore.Components.RouteAttribute` of the component. + * + * A route parameter is defined in the URL by wrapping its name in a pair of { braces } when adding a component's @page declaration. + * There are various extensions that can be added next to the parameter name, such as `:int` or `?` to make the parameter optional. + * Optionally, the parameter name can start with a `*` to make it a catch-all parameter. + * + * And example of a route parameter is `@page "/counter/{id:int}/{other?}/{*rest}"`, from this we're getting the `id`, `other` and `rest` parameters. + */ + private string getARouteParameter() { + result = this.getRouteAttributeUrl().splitAt("{").regexpCapture("\\*?([^:?}]+)[:?}](.*)", 1) + } + + /** Gets a property attributed with `[Parameter]` attribute. */ + Property getAParameterProperty() { + result = this.getAProperty() and + result.getAnAttribute() instanceof MicrosoftAspNetCoreComponentsParameterAttribute + } + + /** Gets a property whose value is populated from route parameters. */ + Property getARouteParameterProperty() { + result = this.getAParameterProperty() and + exists(string urlParamName | urlParamName = this.getARouteParameter() | + result.getName().toLowerCase() = urlParamName.toLowerCase() + ) + } +} + +private module Sources { + private import semmle.code.csharp.security.dataflow.flowsources.Remote + + /** + * A property with a `[Parameter]` attribute in an ASP.NET Core component which + * is populated from a route parameter. + */ + private class AspNetCoreComponentRouteParameterFlowSource extends AspNetRemoteFlowSource, + DataFlow::ExprNode + { + AspNetCoreComponentRouteParameterFlowSource() { + exists(MicrosoftAspNetCoreComponentsComponent c, Property p | + p = c.getARouteParameterProperty() + | + this.asExpr() = p.getGetter().getACall() + ) + } + + override string getSourceType() { result = "ASP.NET Core component route parameter" } + } +} From 6ae7edeae0216ef43a2caf53cd36f766a4e95a57 Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Wed, 15 Jan 2025 13:27:21 -0500 Subject: [PATCH 02/12] Add Blazor components file to Remote sources module --- .../code/csharp/security/dataflow/flowsources/Remote.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll index dc2fb36c47ae..2906fde4e1de 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsources/Remote.qll @@ -26,7 +26,8 @@ abstract class RemoteFlowSource extends SourceNode { * A module for importing frameworks that defines remote flow sources. */ private module RemoteFlowSources { - private import semmle.code.csharp.frameworks.ServiceStack + private import semmle.code.csharp.frameworks.ServiceStack as ServiceStack + private import semmle.code.csharp.frameworks.microsoft.aspnetcore.Components as Blazor } /** A data flow source of remote user input (ASP.NET). */ From aaefa0f82a0b4356090deac40882360e651fa957 Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Fri, 31 Jan 2025 11:32:13 -0500 Subject: [PATCH 03/12] Add remote flow source test --- .../all-platforms/blazor/remoteFlowSource.expected | 6 ++++++ .../all-platforms/blazor/remoteFlowSource.ql | 7 +++++++ .../blazor_build_mode_none/remoteFlowSource.expected | 6 ++++++ .../blazor_build_mode_none/remoteFlowSource.ql | 7 +++++++ .../all-platforms/blazor_net_8/remoteFlowSource.expected | 6 ++++++ .../all-platforms/blazor_net_8/remoteFlowSource.ql | 7 +++++++ 6 files changed, 39 insertions(+) create mode 100644 csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected create mode 100644 csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.ql create mode 100644 csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected create mode 100644 csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.ql create mode 100644 csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected create mode 100644 csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.ql diff --git a/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected b/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected new file mode 100644 index 000000000000..9a54413c075d --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected @@ -0,0 +1,6 @@ +| BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | +| BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | +| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | ASP.NET Core component query string | +| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | ASP.NET Core component query string | +| BlazorTest/Components/Pages/TestPage.razor:27:29:27:39 | access to property InputValue1 | ASP.NET Core `InputBase<>.Value`-bound property read | +| BlazorTest/Components/Pages/TestPage.razor:80:29:80:39 | access to property InputValue6 | ASP.NET Core `InputBase<>.Value`-bound property read | diff --git a/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.ql b/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.ql new file mode 100644 index 000000000000..d79af0412286 --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.ql @@ -0,0 +1,7 @@ +import semmle.code.csharp.security.dataflow.flowsources.Remote + +from RemoteFlowSource source, File f +where + source.getLocation().getFile() = f and + (f.fromSource() or f.getExtension() = "razor") +select source, source.getSourceType() diff --git a/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected b/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected new file mode 100644 index 000000000000..9a54413c075d --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected @@ -0,0 +1,6 @@ +| BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | +| BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | +| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | ASP.NET Core component query string | +| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | ASP.NET Core component query string | +| BlazorTest/Components/Pages/TestPage.razor:27:29:27:39 | access to property InputValue1 | ASP.NET Core `InputBase<>.Value`-bound property read | +| BlazorTest/Components/Pages/TestPage.razor:80:29:80:39 | access to property InputValue6 | ASP.NET Core `InputBase<>.Value`-bound property read | diff --git a/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.ql b/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.ql new file mode 100644 index 000000000000..d79af0412286 --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.ql @@ -0,0 +1,7 @@ +import semmle.code.csharp.security.dataflow.flowsources.Remote + +from RemoteFlowSource source, File f +where + source.getLocation().getFile() = f and + (f.fromSource() or f.getExtension() = "razor") +select source, source.getSourceType() diff --git a/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected b/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected new file mode 100644 index 000000000000..9a54413c075d --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected @@ -0,0 +1,6 @@ +| BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | +| BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | +| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | ASP.NET Core component query string | +| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | ASP.NET Core component query string | +| BlazorTest/Components/Pages/TestPage.razor:27:29:27:39 | access to property InputValue1 | ASP.NET Core `InputBase<>.Value`-bound property read | +| BlazorTest/Components/Pages/TestPage.razor:80:29:80:39 | access to property InputValue6 | ASP.NET Core `InputBase<>.Value`-bound property read | diff --git a/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.ql b/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.ql new file mode 100644 index 000000000000..d79af0412286 --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.ql @@ -0,0 +1,7 @@ +import semmle.code.csharp.security.dataflow.flowsources.Remote + +from RemoteFlowSource source, File f +where + source.getLocation().getFile() = f and + (f.fromSource() or f.getExtension() = "razor") +select source, source.getSourceType() From 414c0a646a2ae121f58c97e749833ae529dccb0c Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Fri, 31 Jan 2025 12:52:48 -0500 Subject: [PATCH 04/12] Fix test results --- .../all-platforms/blazor/remoteFlowSource.expected | 6 ++---- .../blazor_build_mode_none/remoteFlowSource.expected | 6 ++---- .../all-platforms/blazor_net_8/remoteFlowSource.expected | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected b/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected index 9a54413c075d..b698ca4daf3f 100644 --- a/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected +++ b/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected @@ -1,6 +1,4 @@ | BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | | BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | ASP.NET Core component query string | -| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | ASP.NET Core component query string | -| BlazorTest/Components/Pages/TestPage.razor:27:29:27:39 | access to property InputValue1 | ASP.NET Core `InputBase<>.Value`-bound property read | -| BlazorTest/Components/Pages/TestPage.razor:80:29:80:39 | access to property InputValue6 | ASP.NET Core `InputBase<>.Value`-bound property read | +| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | external | +| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | external | diff --git a/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected b/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected index 9a54413c075d..b698ca4daf3f 100644 --- a/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected +++ b/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected @@ -1,6 +1,4 @@ | BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | | BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | ASP.NET Core component query string | -| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | ASP.NET Core component query string | -| BlazorTest/Components/Pages/TestPage.razor:27:29:27:39 | access to property InputValue1 | ASP.NET Core `InputBase<>.Value`-bound property read | -| BlazorTest/Components/Pages/TestPage.razor:80:29:80:39 | access to property InputValue6 | ASP.NET Core `InputBase<>.Value`-bound property read | +| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | external | +| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | external | diff --git a/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected b/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected index 9a54413c075d..b698ca4daf3f 100644 --- a/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected +++ b/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected @@ -1,6 +1,4 @@ | BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | | BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | ASP.NET Core component query string | -| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | ASP.NET Core component query string | -| BlazorTest/Components/Pages/TestPage.razor:27:29:27:39 | access to property InputValue1 | ASP.NET Core `InputBase<>.Value`-bound property read | -| BlazorTest/Components/Pages/TestPage.razor:80:29:80:39 | access to property InputValue6 | ASP.NET Core `InputBase<>.Value`-bound property read | +| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | external | +| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | external | From 5236a40d0a495e1d0416630395257b1b90b91a7f Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Mon, 3 Feb 2025 22:34:08 -0500 Subject: [PATCH 05/12] Remove unnecessary class --- .../csharp/frameworks/microsoft/aspnetcore/Components.qll | 6 ------ 1 file changed, 6 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll index 0ea7f936b2e5..b8564904c3ab 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll @@ -21,12 +21,6 @@ private class MicrosoftAspNetCoreComponentsClass extends Class { } } -/** The `Microsoft.AspNetCore.Components.ParameterAttribute` class. */ -class MicrosoftAspNetCoreComponentsParamaterAttributeClass extends MicrosoftAspNetCoreComponentsClass -{ - MicrosoftAspNetCoreComponentsParamaterAttributeClass() { this.hasName("ParameterAttribute") } -} - /** The `Microsoft.AspNetCore.Components.CascadingParameterAttributeBase` class. */ class MicrosoftAspNetCoreComponentsCascadingParameterAttributeBaseClass extends MicrosoftAspNetCoreComponentsClass { From eb25c768bbf9cfbcb854f2460df5b25e8b81af98 Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Mon, 3 Feb 2025 22:35:57 -0500 Subject: [PATCH 06/12] Change note --- .../lib/change-notes/2025-02-03-blazor-routing-parameters.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2025-02-03-blazor-routing-parameters.md diff --git a/csharp/ql/lib/change-notes/2025-02-03-blazor-routing-parameters.md b/csharp/ql/lib/change-notes/2025-02-03-blazor-routing-parameters.md new file mode 100644 index 000000000000..00afc5867c62 --- /dev/null +++ b/csharp/ql/lib/change-notes/2025-02-03-blazor-routing-parameters.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Blazor `[Parameter]` fields bound to a variable from the route specified in the `@page` directive are now modeled as remote flow sources. From 07aad61c9ec961bc5a7f1ee46b2d6dfc77f01b1f Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Tue, 4 Feb 2025 21:45:34 -0500 Subject: [PATCH 07/12] Typo --- .../code/csharp/frameworks/microsoft/aspnetcore/Components.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll index b8564904c3ab..8cb252c1c46b 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll @@ -86,7 +86,7 @@ class MicrosoftAspNetCoreComponentsComponent extends Class { * There are various extensions that can be added next to the parameter name, such as `:int` or `?` to make the parameter optional. * Optionally, the parameter name can start with a `*` to make it a catch-all parameter. * - * And example of a route parameter is `@page "/counter/{id:int}/{other?}/{*rest}"`, from this we're getting the `id`, `other` and `rest` parameters. + * An example of a route parameter is `@page "/counter/{id:int}/{other?}/{*rest}"`, from this we're getting the `id`, `other` and `rest` parameters. */ private string getARouteParameter() { result = this.getRouteAttributeUrl().splitAt("{").regexpCapture("\\*?([^:?}]+)[:?}](.*)", 1) From 12ebfa65dcefe6b0a592de67dedf73a22a7fedf2 Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Tue, 4 Feb 2025 21:50:14 -0500 Subject: [PATCH 08/12] Change join order of Property/Name matching --- .../microsoft/aspnetcore/Components.qll | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll index 8cb252c1c46b..6e37fc0480fb 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/aspnetcore/Components.qll @@ -88,21 +88,26 @@ class MicrosoftAspNetCoreComponentsComponent extends Class { * * An example of a route parameter is `@page "/counter/{id:int}/{other?}/{*rest}"`, from this we're getting the `id`, `other` and `rest` parameters. */ + pragma[nomagic] private string getARouteParameter() { - result = this.getRouteAttributeUrl().splitAt("{").regexpCapture("\\*?([^:?}]+)[:?}](.*)", 1) + exists(string s | + s = this.getRouteAttributeUrl().splitAt("{").regexpCapture("\\*?([^:?}]+)[:?}](.*)", 1) and + result = s.toLowerCase() + ) } /** Gets a property attributed with `[Parameter]` attribute. */ - Property getAParameterProperty() { + pragma[nomagic] + private Property getAParameterProperty(string name) { result = this.getAProperty() and - result.getAnAttribute() instanceof MicrosoftAspNetCoreComponentsParameterAttribute + result.getAnAttribute() instanceof MicrosoftAspNetCoreComponentsParameterAttribute and + name = result.getName().toLowerCase() } /** Gets a property whose value is populated from route parameters. */ Property getARouteParameterProperty() { - result = this.getAParameterProperty() and - exists(string urlParamName | urlParamName = this.getARouteParameter() | - result.getName().toLowerCase() = urlParamName.toLowerCase() + exists(string name | name = this.getARouteParameter() | + result = this.getAParameterProperty(name) ) } } From a783ac1abf812eaedf77d50af8242f0c37a9cb26 Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Wed, 5 Feb 2025 11:22:23 -0500 Subject: [PATCH 09/12] Add QL tests for remoteFlowSource --- .../blazor/Components_MyInput_razor.g.cs | 124 ++++ .../blazor/Components_MyOutput_razor.g.cs | 115 ++++ .../Components_Pages_TestPage_razor.g.cs | 567 ++++++++++++++++++ .../microsoft/aspnetcore/blazor/options | 2 + .../blazor/remoteFlowSource.expected | 4 + .../aspnetcore/blazor/remoteFlowSource.ql | 7 + 6 files changed, 819 insertions(+) create mode 100644 csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_MyInput_razor.g.cs create mode 100644 csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_MyOutput_razor.g.cs create mode 100644 csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_Pages_TestPage_razor.g.cs create mode 100644 csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/options create mode 100644 csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.expected create mode 100644 csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.ql diff --git a/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_MyInput_razor.g.cs b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_MyInput_razor.g.cs new file mode 100644 index 000000000000..bdff55cfc1cc --- /dev/null +++ b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_MyInput_razor.g.cs @@ -0,0 +1,124 @@ +// +#pragma warning disable 1591 +namespace BlazorTest.Components +{ +#line default + using global::System; + using global::System.Collections.Generic; + using global::System.Linq; + using global::System.Threading.Tasks; + using global::Microsoft.AspNetCore.Components; +#nullable restore + using System.Net.Http + +#nullable disable + ; +#nullable restore + using System.Net.Http.Json + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Forms + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Routing + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Web + +#nullable disable + ; +#nullable restore + using static Microsoft.AspNetCore.Components.Web.RenderMode + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Web.Virtualization + +#nullable disable + ; +#nullable restore + using Microsoft.JSInterop + +#nullable disable + ; +#nullable restore + using BlazorTest + +#nullable disable + ; +#nullable restore + using BlazorTest.Components + +#line default +#line hidden +#nullable disable + ; + [global::BlazorTest.Components.MyInput.__PrivateComponentRenderModeAttribute] +#nullable restore + public partial class MyInput : global::Microsoft.AspNetCore.Components.ComponentBase +#nullable disable + { +#pragma warning disable 1998 + protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) + { + __builder.OpenElement(0, "input"); + __builder.AddAttribute(1, "value", global::Microsoft.AspNetCore.Components.BindConverter.FormatValue( +#nullable restore +Param1 + +#line default +#line hidden +#nullable disable + )); + __builder.AddAttribute(2, "onchange", global::Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredBindSetter(callback: __value => + { + Param1 = __value; return global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.InvokeAsynchronousDelegate(callback: +#nullable restore +Fire + +#line default +#line hidden +#nullable disable + ); + }, value: Param1), Param1)); + __builder.SetUpdatesAttributeName("value"); + __builder.CloseElement(); + } +#pragma warning restore 1998 +#nullable restore + + [Parameter] + public string? Param1 { get; set; } = ""; + + [Parameter] + public EventCallback ValueChanged { get; set; } + + [Parameter] + public EventCallback Param1Changed { get; set; } + + private void Fire() + { + ValueChanged.InvokeAsync(Param1); + Param1Changed.InvokeAsync(Param1); + } + +#line default +#line hidden +#nullable disable + + private sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + { + private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => InteractiveServer + ; + public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; + } + } +} +#pragma warning restore 1591 diff --git a/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_MyOutput_razor.g.cs b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_MyOutput_razor.g.cs new file mode 100644 index 000000000000..698aceba27cf --- /dev/null +++ b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_MyOutput_razor.g.cs @@ -0,0 +1,115 @@ +// +#pragma warning disable 1591 +namespace BlazorTest.Components +{ +#line default + using global::System; + using global::System.Collections.Generic; + using global::System.Linq; + using global::System.Threading.Tasks; + using global::Microsoft.AspNetCore.Components; +#nullable restore + using System.Net.Http + +#nullable disable + ; +#nullable restore + using System.Net.Http.Json + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Forms + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Routing + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Web + +#nullable disable + ; +#nullable restore + using static Microsoft.AspNetCore.Components.Web.RenderMode + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Web.Virtualization + +#nullable disable + ; +#nullable restore + using Microsoft.JSInterop + +#nullable disable + ; +#nullable restore + using BlazorTest + +#nullable disable + ; +#nullable restore + using BlazorTest.Components + +#line default +#line hidden +#nullable disable + ; + [global::BlazorTest.Components.MyOutput.__PrivateComponentRenderModeAttribute] +#nullable restore + public partial class MyOutput : global::Microsoft.AspNetCore.Components.ComponentBase +#nullable disable + { +#pragma warning disable 1998 + protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) + { + __builder.OpenElement(0, "div"); + __builder.OpenElement(1, "p"); + __builder.AddContent(2, "Value from InputText: "); + __builder.AddContent(3, +#nullable restore +Value + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.AddMarkupContent(4, "\n "); + __builder.OpenElement(5, "p"); + __builder.AddContent(6, "Raw value from InputText: "); + __builder.AddContent(7, +#nullable restore +new MarkupString(Value) + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.CloseElement(); + } +#pragma warning restore 1998 +#nullable restore + + [Parameter] + public string Value { get; set; } = ""; + +#line default +#line hidden +#nullable disable + + private sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + { + private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => InteractiveServer + ; + public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; + } + } +} +#pragma warning restore 1591 diff --git a/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_Pages_TestPage_razor.g.cs b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_Pages_TestPage_razor.g.cs new file mode 100644 index 000000000000..8732f8c7e4be --- /dev/null +++ b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/Components_Pages_TestPage_razor.g.cs @@ -0,0 +1,567 @@ +// +#pragma warning disable 1591 +namespace BlazorTest.Components.Pages +{ +#line default + using global::System; + using global::System.Collections.Generic; + using global::System.Linq; + using global::System.Threading.Tasks; + using global::Microsoft.AspNetCore.Components; +#nullable restore + using System.Net.Http + +#nullable disable + ; +#nullable restore + using System.Net.Http.Json + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Forms + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Routing + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Web + +#nullable disable + ; +#nullable restore + using static Microsoft.AspNetCore.Components.Web.RenderMode + +#nullable disable + ; +#nullable restore + using Microsoft.AspNetCore.Components.Web.Virtualization + +#nullable disable + ; +#nullable restore + using Microsoft.JSInterop + +#nullable disable + ; +#nullable restore + using BlazorTest + +#nullable disable + ; +#nullable restore + using BlazorTest.Components + +#line default +#line hidden +#nullable disable + ; + [global::Microsoft.AspNetCore.Components.RouteAttribute( + // language=Route,Component +#nullable restore +"/" + +#line default +#line hidden +#nullable disable + )] + [global::Microsoft.AspNetCore.Components.RouteAttribute( + // language=Route,Component +#nullable restore +"/test/{urlParam?}" + +#line default +#line hidden +#nullable disable + )] + [global::BlazorTest.Components.Pages.TestPage.__PrivateComponentRenderModeAttribute] +#nullable restore + public partial class TestPage : global::Microsoft.AspNetCore.Components.ComponentBase +#nullable disable + { +#pragma warning disable 1998 + protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder) + { + __builder.OpenComponent(0); + __builder.AddAttribute(1, "ChildContent", (global::Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => + { + __builder2.AddContent(2, "TestPage"); + } + )); + __builder.CloseComponent(); + __builder.AddMarkupContent(3, "\n\n"); + __builder.OpenElement(4, "div"); + __builder.AddMarkupContent(5, "

Route parameter

\n "); + __builder.OpenElement(6, "p"); + __builder.AddContent(7, "Go to: "); + __builder.OpenElement(8, "a"); + __builder.AddAttribute(9, "href", "/test/" + ( +#nullable restore +XssUrl + +#line default +#line hidden +#nullable disable + )); + __builder.AddContent(10, "/test/"); + __builder.AddContent(11, +#nullable restore +XssUrl + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.CloseElement(); + __builder.AddMarkupContent(12, "\n "); + __builder.OpenElement(13, "p"); + __builder.AddContent(14, "Parameter from URL: "); + __builder.AddContent(15, +#nullable restore +UrlParam + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.AddMarkupContent(16, "\n "); + __builder.OpenElement(17, "p"); + __builder.AddContent(18, "Raw parameter from URL: "); + __builder.AddContent(19, +#nullable restore +(MarkupString)UrlParam + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.CloseElement(); + __builder.AddMarkupContent(20, "\n\n
\n\n"); + __builder.OpenElement(21, "div"); + __builder.AddMarkupContent(22, "

Query parameter

\n "); + __builder.OpenElement(23, "p"); + __builder.AddContent(24, "Go to: "); + __builder.OpenElement(25, "a"); + __builder.AddAttribute(26, "href", "/test/?qs=" + ( +#nullable restore +XssUrl + +#line default +#line hidden +#nullable disable + )); + __builder.AddContent(27, "/test/?qs="); + __builder.AddContent(28, +#nullable restore +XssUrl + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.CloseElement(); + __builder.AddMarkupContent(29, "\n "); + __builder.OpenElement(30, "p"); + __builder.AddContent(31, "Parameter from query string: "); + __builder.AddContent(32, +#nullable restore +QueryParam + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.AddMarkupContent(33, "\n "); + __builder.OpenElement(34, "p"); + __builder.AddContent(35, "Raw parameter from query string: "); + __builder.AddContent(36, +#nullable restore +new MarkupString(QueryParam) + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.CloseElement(); + __builder.AddMarkupContent(37, "\n\n
\n\n"); + __builder.OpenElement(38, "div"); + __builder.AddMarkupContent(39, "

Bind InputText component

\n "); + __builder.OpenComponent(40); + __builder.AddComponentParameter(41, nameof(global::Microsoft.AspNetCore.Components.Forms.InputText. +#nullable restore +Value + +#line default +#line hidden +#nullable disable + ), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck( +#nullable restore +InputValue1 + +#line default +#line hidden +#nullable disable + )); + __builder.AddComponentParameter(42, nameof(global::Microsoft.AspNetCore.Components.Forms.InputText.ValueChanged), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck>(global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this, global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this, __value => InputValue1 = __value, InputValue1)))); + __builder.AddComponentParameter(43, nameof(global::Microsoft.AspNetCore.Components.Forms.InputText.ValueExpression), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck>>(() => InputValue1)); + __builder.CloseComponent(); + __builder.AddMarkupContent(44, "\n "); + __builder.OpenElement(45, "p"); + __builder.AddContent(46, "Value from InputText: "); + __builder.AddContent(47, +#nullable restore +InputValue1 + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.AddMarkupContent(48, "\n "); + __builder.OpenElement(49, "p"); + __builder.AddContent(50, "Raw value from InputText: "); + __builder.AddContent(51, +#nullable restore +new MarkupString(InputValue1) + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.CloseElement(); + __builder.AddMarkupContent(52, "\n\n
\n\n"); + __builder.OpenElement(53, "div"); + __builder.AddMarkupContent(54, "

Bind input element

\n "); + __builder.OpenElement(55, "input"); + __builder.AddAttribute(56, "value", global::Microsoft.AspNetCore.Components.BindConverter.FormatValue( +#nullable restore +InputValue2 + +#line default +#line hidden +#nullable disable + )); + __builder.AddAttribute(57, "onchange", global::Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => InputValue2 = __value, InputValue2)); + __builder.SetUpdatesAttributeName("value"); + __builder.CloseElement(); + __builder.AddMarkupContent(58, "\n "); + __builder.OpenElement(59, "p"); + __builder.AddContent(60, "Value from InputText: "); + __builder.AddContent(61, +#nullable restore +InputValue2 + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.AddMarkupContent(62, "\n "); + __builder.OpenElement(63, "p"); + __builder.AddContent(64, "Raw value from InputText: "); + __builder.AddContent(65, +#nullable restore +new MarkupString(InputValue2) + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.CloseElement(); + __builder.AddMarkupContent(66, "\n\n
\n\n"); + __builder.OpenElement(67, "div"); + __builder.AddMarkupContent(68, "

Bind through object property

\n "); + __builder.OpenElement(69, "input"); + __builder.AddAttribute(70, "value", global::Microsoft.AspNetCore.Components.BindConverter.FormatValue( +#nullable restore +Container1.Value + +#line default +#line hidden +#nullable disable + )); + __builder.AddAttribute(71, "onchange", global::Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => Container1.Value = __value, Container1.Value)); + __builder.SetUpdatesAttributeName("value"); + __builder.CloseElement(); + __builder.AddMarkupContent(72, "\n "); + __builder.OpenElement(73, "p"); + __builder.AddContent(74, "Value from InputText: "); + __builder.AddContent(75, +#nullable restore +Container1.Value + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.AddMarkupContent(76, "\n "); + __builder.OpenElement(77, "p"); + __builder.AddContent(78, "Raw value from InputText: "); + __builder.AddContent(79, +#nullable restore +new MarkupString(Container1.Value) + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.CloseElement(); + __builder.AddMarkupContent(80, "\n\n
\n\n"); + __builder.OpenElement(81, "div"); + __builder.AddMarkupContent(82, "

Input component with custom event

\n "); + __builder.OpenComponent(83); + __builder.AddComponentParameter(84, nameof(global::BlazorTest.Components.MyInput. +#nullable restore +Param1 + +#line default +#line hidden +#nullable disable + ), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck( +#nullable restore +InputValue3 + +#line default +#line hidden +#nullable disable + )); + __builder.AddComponentParameter(85, nameof(global::BlazorTest.Components.MyInput. +#nullable restore +ValueChanged + +#line default +#line hidden +#nullable disable + ), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck>(global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this, +#nullable restore +MyInputChanged + +#line default +#line hidden +#nullable disable + ))); + __builder.CloseComponent(); + __builder.AddMarkupContent(86, "\n "); + __builder.OpenElement(87, "p"); + __builder.AddContent(88, "Value from InputText: "); + __builder.AddContent(89, +#nullable restore +InputValue3 + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.AddMarkupContent(90, "\n "); + __builder.OpenElement(91, "p"); + __builder.AddContent(92, "Raw value from InputText: "); + __builder.AddContent(93, +#nullable restore +new MarkupString(InputValue3) + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.CloseElement(); + __builder.AddMarkupContent(94, "\n\n
\n\n"); + __builder.OpenElement(95, "div"); + __builder.AddMarkupContent(96, "

Input component with binding

\n "); + __builder.OpenComponent(97); + __builder.AddComponentParameter(98, nameof(global::BlazorTest.Components.MyInput. +#nullable restore +Param1 + +#line default +#line hidden +#nullable disable + ), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck( +#nullable restore +InputValue4 + +#line default +#line hidden +#nullable disable + )); + __builder.AddComponentParameter(99, nameof(global::BlazorTest.Components.MyInput.Param1Changed), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck>(global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this, global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this, __value => InputValue4 = __value, InputValue4)))); + __builder.CloseComponent(); + __builder.AddMarkupContent(100, "\n "); + __builder.OpenElement(101, "p"); + __builder.AddContent(102, "Value from InputText: "); + __builder.AddContent(103, +#nullable restore +InputValue4 + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.AddMarkupContent(104, "\n "); + __builder.OpenElement(105, "p"); + __builder.AddContent(106, "Raw value from InputText: "); + __builder.AddContent(107, +#nullable restore +new MarkupString(InputValue4) + +#line default +#line hidden +#nullable disable + ); + __builder.CloseElement(); + __builder.CloseElement(); + __builder.AddMarkupContent(108, "\n\n
\n\n"); + __builder.OpenElement(109, "div"); + __builder.AddMarkupContent(110, "

Input, Output components

\n "); + __builder.OpenComponent(111); + __builder.AddComponentParameter(112, nameof(global::BlazorTest.Components.MyInput. +#nullable restore +Param1 + +#line default +#line hidden +#nullable disable + ), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck( +#nullable restore +InputValue5 + +#line default +#line hidden +#nullable disable + )); + __builder.AddComponentParameter(113, nameof(global::BlazorTest.Components.MyInput.Param1Changed), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck>(global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this, global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this, __value => InputValue5 = __value, InputValue5)))); + __builder.CloseComponent(); + __builder.AddMarkupContent(114, "\n "); + __builder.OpenComponent(115); + __builder.AddComponentParameter(116, nameof(global::BlazorTest.Components.MyOutput. +#nullable restore +Value + +#line default +#line hidden +#nullable disable + ), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck( +#nullable restore +InputValue5 + +#line default +#line hidden +#nullable disable + )); + __builder.CloseComponent(); + __builder.CloseElement(); + __builder.AddMarkupContent(117, "\n\n
\n\n"); + __builder.OpenElement(118, "div"); + __builder.AddMarkupContent(119, "

Bind InputText, Output component

\n "); + __builder.OpenComponent(120); + __builder.AddComponentParameter(121, nameof(global::Microsoft.AspNetCore.Components.Forms.InputText. +#nullable restore +Value + +#line default +#line hidden +#nullable disable + ), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck( +#nullable restore +InputValue6 + +#line default +#line hidden +#nullable disable + )); + __builder.AddComponentParameter(122, nameof(global::Microsoft.AspNetCore.Components.Forms.InputText.ValueChanged), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck>(global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this, global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this, __value => InputValue6 = __value, InputValue6)))); + __builder.AddComponentParameter(123, nameof(global::Microsoft.AspNetCore.Components.Forms.InputText.ValueExpression), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck>>(() => InputValue6)); + __builder.CloseComponent(); + __builder.AddMarkupContent(124, "\n "); + __builder.OpenComponent(125); + __builder.AddComponentParameter(126, nameof(global::BlazorTest.Components.MyOutput. +#nullable restore +Value + +#line default +#line hidden +#nullable disable + ), global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck( +#nullable restore +InputValue6 + +#line default +#line hidden +#nullable disable + )); + __builder.CloseComponent(); + __builder.CloseElement(); + } +#pragma warning restore 1998 +#nullable restore + + + public class Container + { + public string? Value { get; set; } = ""; + } + + private const string XssUrl = "aaaa<%2Fb>"; + private const string XssUrl2 = "aaaa"; + + [Parameter] + public string UrlParam { get; set; } = ""; + + [SupplyParameterFromQuery(Name = "qs")] + public string QueryParam { get; set; } = ""; + + public string InputValue1 { get; set; } = ""; + public string InputValue2 { get; set; } = ""; + public string InputValue3 { get; set; } = ""; + public string InputValue4 { get; set; } = ""; + public string InputValue5 { get; set; } = ""; + public string InputValue6 { get; set; } = ""; + + public Container Container1 { get; set; } = new Container(); + + protected override void OnInitialized() + { + InputValue1 = XssUrl2; + InputValue2 = XssUrl2; + Container1.Value = XssUrl2; + InputValue3 = XssUrl2; + InputValue4 = XssUrl2; + InputValue5 = XssUrl2; + InputValue6 = XssUrl2; + + } + + private void MyInputChanged(string value) + { + InputValue3 = value; + } + +#line default +#line hidden +#nullable disable + + private sealed class __PrivateComponentRenderModeAttribute : global::Microsoft.AspNetCore.Components.RenderModeAttribute + { + private static global::Microsoft.AspNetCore.Components.IComponentRenderMode ModeImpl => InteractiveServer + ; + public override global::Microsoft.AspNetCore.Components.IComponentRenderMode Mode => ModeImpl; + } + } +} +#pragma warning restore 1591 diff --git a/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/options b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/options new file mode 100644 index 000000000000..d44a4aa5500b --- /dev/null +++ b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/options @@ -0,0 +1,2 @@ +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj +semmle-extractor-options: /nostdlib /noconfig \ No newline at end of file diff --git a/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.expected b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.expected new file mode 100644 index 000000000000..b698ca4daf3f --- /dev/null +++ b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.expected @@ -0,0 +1,4 @@ +| BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | +| BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | +| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | external | +| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | external | diff --git a/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.ql b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.ql new file mode 100644 index 000000000000..d79af0412286 --- /dev/null +++ b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.ql @@ -0,0 +1,7 @@ +import semmle.code.csharp.security.dataflow.flowsources.Remote + +from RemoteFlowSource source, File f +where + source.getLocation().getFile() = f and + (f.fromSource() or f.getExtension() = "razor") +select source, source.getSourceType() From 274a2d8dac7322fe299b2d897b942ac89feb13f3 Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Wed, 5 Feb 2025 11:24:29 -0500 Subject: [PATCH 10/12] Remove remoteFlowSource integration test --- .../all-platforms/blazor/remoteFlowSource.expected | 4 ---- .../all-platforms/blazor/remoteFlowSource.ql | 7 ------- .../blazor_build_mode_none/remoteFlowSource.expected | 4 ---- .../blazor_build_mode_none/remoteFlowSource.ql | 7 ------- .../all-platforms/blazor_net_8/remoteFlowSource.expected | 4 ---- .../all-platforms/blazor_net_8/remoteFlowSource.ql | 7 ------- 6 files changed, 33 deletions(-) delete mode 100644 csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected delete mode 100644 csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.ql delete mode 100644 csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected delete mode 100644 csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.ql delete mode 100644 csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected delete mode 100644 csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.ql diff --git a/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected b/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected deleted file mode 100644 index b698ca4daf3f..000000000000 --- a/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.expected +++ /dev/null @@ -1,4 +0,0 @@ -| BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | external | -| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | external | diff --git a/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.ql b/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.ql deleted file mode 100644 index d79af0412286..000000000000 --- a/csharp/ql/integration-tests/all-platforms/blazor/remoteFlowSource.ql +++ /dev/null @@ -1,7 +0,0 @@ -import semmle.code.csharp.security.dataflow.flowsources.Remote - -from RemoteFlowSource source, File f -where - source.getLocation().getFile() = f and - (f.fromSource() or f.getExtension() = "razor") -select source, source.getSourceType() diff --git a/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected b/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected deleted file mode 100644 index b698ca4daf3f..000000000000 --- a/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.expected +++ /dev/null @@ -1,4 +0,0 @@ -| BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | external | -| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | external | diff --git a/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.ql b/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.ql deleted file mode 100644 index d79af0412286..000000000000 --- a/csharp/ql/integration-tests/all-platforms/blazor_build_mode_none/remoteFlowSource.ql +++ /dev/null @@ -1,7 +0,0 @@ -import semmle.code.csharp.security.dataflow.flowsources.Remote - -from RemoteFlowSource source, File f -where - source.getLocation().getFile() = f and - (f.fromSource() or f.getExtension() = "razor") -select source, source.getSourceType() diff --git a/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected b/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected deleted file mode 100644 index b698ca4daf3f..000000000000 --- a/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.expected +++ /dev/null @@ -1,4 +0,0 @@ -| BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | external | -| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | external | diff --git a/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.ql b/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.ql deleted file mode 100644 index d79af0412286..000000000000 --- a/csharp/ql/integration-tests/all-platforms/blazor_net_8/remoteFlowSource.ql +++ /dev/null @@ -1,7 +0,0 @@ -import semmle.code.csharp.security.dataflow.flowsources.Remote - -from RemoteFlowSource source, File f -where - source.getLocation().getFile() = f and - (f.fromSource() or f.getExtension() = "razor") -select source, source.getSourceType() From 0a817eb1da939200cad083f280e6db0333e1ce5d Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Wed, 5 Feb 2025 11:25:51 -0500 Subject: [PATCH 11/12] Fix test expectations --- .../microsoft/aspnetcore/blazor/remoteFlowSource.expected | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.expected b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.expected index b698ca4daf3f..2c845e8e4001 100644 --- a/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.expected +++ b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.expected @@ -1,4 +1,4 @@ -| BlazorTest/Components/Pages/TestPage.razor:10:29:10:36 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:11:48:11:55 | access to property UrlParam | ASP.NET Core component route parameter | -| BlazorTest/Components/Pages/TestPage.razor:19:38:19:47 | access to property QueryParam | external | -| BlazorTest/Components/Pages/TestPage.razor:20:60:20:69 | access to property QueryParam | external | +| Components_Pages_TestPage_razor.g.cs:126:1:126:8 | access to property UrlParam | ASP.NET Core component route parameter | +| Components_Pages_TestPage_razor.g.cs:138:15:138:22 | access to property UrlParam | ASP.NET Core component route parameter | +| Components_Pages_TestPage_razor.g.cs:176:1:176:10 | access to property QueryParam | external | +| Components_Pages_TestPage_razor.g.cs:188:18:188:27 | access to property QueryParam | external | From 29d03db06bd5d4bf9c736b75b81bcb20e08cb0ba Mon Sep 17 00:00:00 2001 From: Ed Minnix Date: Thu, 6 Feb 2025 15:10:06 -0500 Subject: [PATCH 12/12] Remove unneeded disjunction --- .../frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.ql b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.ql index d79af0412286..afccffd11fec 100644 --- a/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.ql +++ b/csharp/ql/test/library-tests/frameworks/microsoft/aspnetcore/blazor/remoteFlowSource.ql @@ -3,5 +3,5 @@ import semmle.code.csharp.security.dataflow.flowsources.Remote from RemoteFlowSource source, File f where source.getLocation().getFile() = f and - (f.fromSource() or f.getExtension() = "razor") + f.fromSource() select source, source.getSourceType()