Skip to content

C#: Relax condition for authorize attributes on cs/web/missing-function-level-access-control. #19302

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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
Expand Up @@ -81,7 +81,7 @@ predicate hasAuthViaXml(ActionMethod m) {

/** Holds if the given action has an attribute that indications authorization. */
predicate hasAuthViaAttribute(ActionMethod m) {
exists(Attribute attr | attr.getType().getName().toLowerCase().matches("%auth%") |
exists(Attribute attr | attr.getType().getABaseType*().getName().toLowerCase().matches("%auth%") |
attr = m.getOverridee*().getAnAttribute() or
attr = getAnUnboundBaseType*(m.getDeclaringType()).getAnAttribute()
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Improved detection of authorization checks in the `cs/web/missing-function-level-access-control` query. The query now recognizes authorization attributes inherited from base classes and interfaces.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
| ProfileController.cs:9:25:9:31 | Delete1 | This action is missing an authorization check. |
| ProfileController.cs:12:25:12:31 | Delete1 | This action is missing an authorization check. |
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
Security Features/CWE-285/MissingAccessControl.ql
query: Security Features/CWE-285/MissingAccessControl.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;

public class ProfileController : Controller {
public class RequirePermissionAttribute : AuthorizeAttribute { }

public class ProfileController : Controller
{
private void doThings() { }
private bool isAuthorized() { return false; }

// BAD: This is a Delete method, but no auth is specified.
public ActionResult Delete1(int id) {
public ActionResult Delete1(int id) // $ Alert
{
doThings();
return View();
}

// GOOD: isAuthorized is checked.
public ActionResult Delete2(int id) {
if (!isAuthorized()) {
public ActionResult Delete2(int id)
{
if (!isAuthorized())
{
return null;
}
doThings();
Expand All @@ -22,35 +28,49 @@ public ActionResult Delete2(int id) {

// GOOD: The Authorize attribute is used.
[Authorize]
public ActionResult Delete3(int id) {
public ActionResult Delete3(int id)
{
doThings();
return View();
}

// GOOD: The RequirePermission attribute is used (which extends AuthorizeAttribute).
[RequirePermission]
public ActionResult Delete4(int id)
{
doThings();
return View();
}
}

[Authorize]
public class AuthBaseController : Controller {
public class AuthBaseController : Controller
{
protected void doThings() { }
}

public class SubController : AuthBaseController {
public class SubController : AuthBaseController
{
// GOOD: The Authorize attribute is used on the base class.
public ActionResult Delete4(int id) {
public ActionResult Delete4(int id)
{
doThings();
return View();
}
}

[Authorize]
public class AuthBaseGenericController<T> : Controller {
public class AuthBaseGenericController<T> : Controller
{
protected void doThings() { }
}

public class SubGenericController : AuthBaseGenericController<string> {
public class SubGenericController : AuthBaseGenericController<string>
{
// GOOD: The Authorize attribute is used on the base class.
public ActionResult Delete5(int id) {
public ActionResult Delete5(int id)
{
doThings();
return View();
}
}
}