Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/** Provides classes for working with `Microsoft.AspNetCore.Components` */

import csharp
import semmle.code.csharp.frameworks.Microsoft

Check warning

Code scanning / CodeQL

Redundant import Warning

Redundant import, the module is already imported inside
semmle.code.csharp.frameworks.microsoft.AspNetCore
.
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.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.
*
* 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() {
exists(string s |
s = this.getRouteAttributeUrl().splitAt("{").regexpCapture("\\*?([^:?}]+)[:?}](.*)", 1) and
result = s.toLowerCase()
)
}

/** Gets a property attributed with `[Parameter]` attribute. */
pragma[nomagic]
private Property getAParameterProperty(string name) {
result = this.getAProperty() and
result.getAnAttribute() instanceof MicrosoftAspNetCoreComponentsParameterAttribute and
name = result.getName().toLowerCase()
}

/** Gets a property whose value is populated from route parameters. */
Property getARouteParameterProperty() {
exists(string name | name = this.getARouteParameter() |
result = this.getAParameterProperty(name)
)
}
}

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" }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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). */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// <auto-generated/>
#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<string?> ValueChanged { get; set; }

[Parameter]
public EventCallback<string?> 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// <auto-generated/>
#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
Loading