Python: Modernise flask library

This commit is contained in:
Rasmus Wriedt Larsen 2019-10-16 13:11:58 +02:00
Родитель edfcf39137
Коммит a9d43a2c49
5 изменённых файлов: 25 добавлений и 30 удалений

Просмотреть файл

@ -17,7 +17,7 @@ import semmle.python.web.flask.General
from CallNode call, Object isTrue
where
call = theFlaskClass().declaredAttribute("run").(FunctionObject).getACall() and
call = theFlaskClass().declaredAttribute("run").(FunctionValue).getACall() and
call.getArgByName("debug").refersTo(isTrue) and
isTrue.booleanValue() = true
select call, "A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger."

Просмотреть файл

@ -1,23 +1,18 @@
import python
import semmle.python.web.Http
/** The flask module */
ModuleObject theFlaskModule() {
result = ModuleObject::named("flask")
}
/** The flask app class */
ClassObject theFlaskClass() {
result = theFlaskModule().attr("Flask")
ClassValue theFlaskClass() {
result = Value::named("flask.Flask")
}
/** The flask MethodView class */
ClassObject theFlaskMethodViewClass() {
result = ModuleObject::named("flask.views").attr("MethodView")
ClassValue theFlaskMethodViewClass() {
result = Value::named("flask.views.MethodView")
}
ClassObject theFlaskReponseClass() {
result = theFlaskModule().attr("Response")
ClassValue theFlaskReponseClass() {
result = Value::named("flask.Response")
}
/** Holds if `route` is routed to `func`
@ -25,7 +20,7 @@ ClassObject theFlaskReponseClass() {
*/
predicate app_route(ControlFlowNode route, Function func) {
exists(CallNode route_call, CallNode decorator_call |
route_call.getFunction().(AttrNode).getObject("route").refersTo(_, theFlaskClass(), _) and
route_call.getFunction().(AttrNode).getObject("route").pointsTo().getClass() = theFlaskClass() and
decorator_call.getFunction() = route_call and
route_call.getArg(0) = route and
decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func
@ -35,7 +30,7 @@ predicate app_route(ControlFlowNode route, Function func) {
/* Helper for add_url_rule */
private predicate add_url_rule_call(ControlFlowNode regex, ControlFlowNode callable) {
exists(CallNode call |
call.getFunction().(AttrNode).getObject("add_url_rule").refersTo(_, theFlaskClass(), _) and
call.getFunction().(AttrNode).getObject("add_url_rule").pointsTo().getClass() = theFlaskClass() and
regex = call.getArg(0) |
callable = call.getArg(2) or
callable = call.getArgByName("view_func")
@ -47,14 +42,14 @@ predicate add_url_rule(ControlFlowNode regex, Function func) {
exists(ControlFlowNode callable |
add_url_rule_call(regex, callable)
|
exists(PyFunctionObject f | f.getFunction() = func and callable.refersTo(f))
exists(PythonFunctionValue f | f.getScope() = func and callable.pointsTo(f))
or
/* MethodView.as_view() */
exists(MethodViewClass view_cls |
view_cls.asTaint().taints(callable) |
func = view_cls.lookupAttribute(httpVerbLower()).(FunctionObject).getFunction()
func = view_cls.lookup(httpVerbLower()).(FunctionValue).getScope()
)
/* TO DO -- Handle Views that aren't MethodViews */
/* TODO: -- Handle Views that aren't MethodViews */
)
}
@ -68,10 +63,10 @@ predicate flask_routing(ControlFlowNode regex, Function func) {
}
/** A class that extends flask.views.MethodView */
private class MethodViewClass extends ClassObject {
private class MethodViewClass extends ClassValue {
MethodViewClass() {
this.getAnImproperSuperType() = theFlaskMethodViewClass()
this.getASuperType() = theFlaskMethodViewClass()
}
/* As we are restricted to strings for taint kinds, we need to map these classes to strings. */
@ -96,9 +91,9 @@ private class MethodViewTaint extends TaintKind {
private class AsView extends TaintSource {
AsView() {
exists(ClassObject view_class |
view_class.getAnImproperSuperType() = theFlaskMethodViewClass() and
this.(CallNode).getFunction().(AttrNode).getObject("as_view").refersTo(view_class)
exists(ClassValue view_class |
view_class.getASuperType() = theFlaskMethodViewClass() and
this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class)
)
}
@ -109,7 +104,7 @@ private class AsView extends TaintSource {
override predicate isSourceOf(TaintKind kind) {
exists(MethodViewClass view_class |
kind = view_class.asTaint() and
this.(CallNode).getFunction().(AttrNode).getObject("as_view").refersTo(view_class)
this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class)
)
}
@ -119,7 +114,7 @@ private class AsView extends TaintSource {
class FlaskCookieSet extends CookieSet, CallNode {
FlaskCookieSet() {
this.getFunction().(AttrNode).getObject("set_cookie").refersTo(_, theFlaskReponseClass(), _)
this.getFunction().(AttrNode).getObject("set_cookie").pointsTo().getClass() = theFlaskReponseClass()
}
override string toString() { result = CallNode.super.toString() }

Просмотреть файл

@ -8,8 +8,8 @@ import semmle.python.security.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.flask.General
FunctionObject flask_redirect() {
result = theFlaskModule().attr("redirect")
FunctionValue flask_redirect() {
result = Value::named("flask.redirect")
}
/**

Просмотреть файл

@ -4,15 +4,15 @@ import semmle.python.security.TaintTracking
import semmle.python.web.Http
import semmle.python.web.flask.General
private Object theFlaskRequestObject() {
result = theFlaskModule().attr("request")
private Value theFlaskRequestObject() {
result = Value::named("flask.request")
}
/** Holds if `attr` is an access of attribute `name` of the flask request object */
private predicate flask_request_attr(AttrNode attr, string name) {
attr.isLoad() and
attr.getObject(name).refersTo(theFlaskRequestObject())
attr.getObject(name).pointsTo(theFlaskRequestObject())
}
/** Source of external data from a flask request */

Просмотреть файл

@ -32,7 +32,7 @@ class FlaskResponseArgument extends HttpResponseTaintSink {
FlaskResponseArgument() {
exists(CallNode call |
call.getFunction().refersTo(theFlaskReponseClass()) and
call.getFunction().pointsTo(theFlaskReponseClass()) and
call.getArg(0) = this
)
}