Add support for auth via xml using the physical path

This commit is contained in:
Joe Farebrother
2023-05-16 16:52:58 +01:00
parent e93f3186fe
commit 29b5f14283

View File

@@ -3,23 +3,40 @@
import csharp
import semmle.code.csharp.frameworks.microsoft.AspNetCore
import semmle.code.csharp.frameworks.system.web.UI
import semmle.code.asp.WebConfig
/** Holds if `m` is a method representing an action whose name indicates that it should have some authorization/authentication check. */
predicate needsAuth(Method m) {
(
m = any(MicrosoftAspNetCoreMvcController c).getAnActionMethod()
or
m.getDeclaringType().getBaseClass*() instanceof SystemWebUIPageClass and
m.getAParameter().getType().getName().matches("%EventArgs")
) and
exists(string name |
name =
abstract class ActionMethod extends Method {
string getADescription() {
result =
[
m.getName(), m.getDeclaringType().getBaseClass*().getName(),
m.getDeclaringType().getFile().getRelativePath()
] and
name.toLowerCase().regexpMatch(".*(edit|delete|modify|admin|superuser).*")
)
this.getName(), this.getDeclaringType().getBaseClass*().getName(),
this.getDeclaringType().getFile().getRelativePath()
]
}
predicate needsAuth() {
this.getADescription().toLowerCase().regexpMatch(".*(edit|delete|modify|admin|superuser).*")
}
Callable getAnAuthorizingCallable() { result = this }
}
private class MvcActionMethod extends ActionMethod {
MvcActionMethod() { this = any(MicrosoftAspNetCoreMvcController c).getAnActionMethod() }
}
private class WebFormActionMethod extends ActionMethod {
WebFormActionMethod() {
this.getDeclaringType().getBaseClass*() instanceof SystemWebUIPageClass and
this.getAParameter().getType().getName().matches("%EventArgs")
}
override Callable getAnAuthorizingCallable() {
result = this
or
result.getDeclaringType() = this.getDeclaringType() and
result.getName() = "Page_Load"
}
}
/** An expression that indicates that some authorization/authentication check is being performed. */
@@ -40,21 +57,52 @@ class AuthExpr extends Expr {
}
/** Holds if `m` is a method that should have an auth check, and does indeed have one. */
predicate hasAuth(Method m) {
needsAuth(m) and
exists(Method om, Callable caller, AuthExpr auth |
om = m
or
om.getDeclaringType() = m.getDeclaringType() and
om.getName() = "Page_Load"
|
om.calls*(caller) and
predicate hasAuthViaCode(ActionMethod m) {
m.needsAuth() and
exists(Callable caller, AuthExpr auth |
m.getAnAuthorizingCallable().calls*(caller) and
auth.getEnclosingCallable() = caller
)
}
/** Holds if `m` is a method that should have an auth check, but is missing it. */
predicate missingAuth(Method m) {
needsAuth(m) and
not hasAuth(m)
class AuthorizationXmlElement extends XmlElement {
AuthorizationXmlElement() {
this.getParent() instanceof SystemWebXmlElement and
this.getName().toLowerCase() = "authorization"
}
predicate hasDenyElement() { this.getAChild().getName().toLowerCase() = "deny" }
string getPhysicalPath() { result = this.getFile().getParentContainer().getRelativePath() }
string getLocationTagPath() {
exists(LocationXmlElement loc, XmlAttribute path |
loc = this.getParent().(SystemWebXmlElement).getParent() and
path = loc.getAnAttribute() and
path.getName().toLowerCase() = "path" and
result = path.getValue()
)
}
}
/**
* Holds if the given action has an xml `authorization` tag that refers to it.
* TODO: Currently only supports physical paths, however virtual paths defined by `AddRoute` can also be used.
*/
predicate hasAuthViaXml(ActionMethod m) {
exists(AuthorizationXmlElement el, string path, string rest |
path = (el.getPhysicalPath() + "/" + el.getLocationTagPath())
or
not exists(el.getLocationTagPath()) and
path = el.getPhysicalPath()
|
el.hasDenyElement() and
m.getDeclaringType().getFile().getRelativePath() = path + rest
)
}
/** Holds if `m` is a method that should have an auth check, but is missing it. */
predicate missingAuth(ActionMethod m) {
m.needsAuth() and
not hasAuthViaCode(m)
}