Python: Autoformat web.

This commit is contained in:
Taus Brock-Nannestad
2020-03-20 16:38:27 +01:00
parent 5b121b7723
commit f406a45ce0
8 changed files with 56 additions and 100 deletions

View File

@@ -4,15 +4,13 @@ import semmle.python.security.strings.External
import HttpConstants
/** Generic taint source from a http request */
abstract class HttpRequestTaintSource extends TaintSource {
abstract class HttpRequestTaintSource extends TaintSource { }
}
/** Taint kind representing the WSGI environment.
/**
* Taint kind representing the WSGI environment.
* As specified in PEP 3333. https://www.python.org/dev/peps/pep-3333/#environ-variables
*/
class WsgiEnvironment extends TaintKind {
WsgiEnvironment() { this = "wsgi.environment" }
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
@@ -26,10 +24,12 @@ class WsgiEnvironment extends TaintKind {
tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode and
tonode.(CallNode).getArg(0).pointsTo(key)
or
tonode.(SubscriptNode).getObject() = fromnode and tonode.isLoad() and
tonode.(SubscriptNode).getObject() = fromnode and
tonode.isLoad() and
tonode.(SubscriptNode).getIndex().pointsTo(key)
|
key = Value::forString(text) and result instanceof ExternalStringKind and
|
key = Value::forString(text) and
result instanceof ExternalStringKind and
(
text = "QUERY_STRING" or
text = "PATH_INFO" or
@@ -37,96 +37,73 @@ class WsgiEnvironment extends TaintKind {
)
)
}
}
/** A standard morsel object from a HTTP request, a value in a cookie,
* typically an instance of `http.cookies.Morsel` */
/**
* A standard morsel object from a HTTP request, a value in a cookie,
* typically an instance of `http.cookies.Morsel`
*/
class UntrustedMorsel extends TaintKind {
UntrustedMorsel() {
this = "http.Morsel"
}
UntrustedMorsel() { this = "http.Morsel" }
override TaintKind getTaintOfAttribute(string name) {
result instanceof ExternalStringKind and
(
name = "value"
)
name = "value"
}
}
/** A standard cookie object from a HTTP request, typically an instance of `http.cookies.SimpleCookie` */
class UntrustedCookie extends TaintKind {
UntrustedCookie() {
this = "http.Cookie"
}
UntrustedCookie() { this = "http.Cookie" }
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
tonode.(SubscriptNode).getObject() = fromnode and
result instanceof UntrustedMorsel
}
}
abstract class CookieOperation extends @py_flow_node {
abstract string toString();
abstract ControlFlowNode getKey();
abstract ControlFlowNode getValue();
}
abstract class CookieGet extends CookieOperation {}
abstract class CookieGet extends CookieOperation { }
abstract class CookieSet extends CookieOperation {}
abstract class CookieSet extends CookieOperation { }
/** Generic taint sink in a http response */
abstract class HttpResponseTaintSink extends TaintSink {
override predicate sinks(TaintKind kind) {
kind instanceof ExternalStringKind
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
abstract class HttpRedirectTaintSink extends TaintSink {
override predicate sinks(TaintKind kind) {
kind instanceof ExternalStringKind
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
module Client {
// TODO: user-input in other than URL:
// - `data`, `json` for `requests.post`
// - `body` for `HTTPConnection.request`
// - headers?
// TODO: Add more library support
// - urllib3 https://github.com/urllib3/urllib3
// - httpx https://github.com/encode/httpx
/**
* An outgoing http request
*
* For example:
* conn = HTTPConnection('example.com')
conn.request('GET', '/path')
*/
* An outgoing http request
*
* For example:
* conn = HTTPConnection('example.com')
* conn.request('GET', '/path')
*/
abstract class HttpRequest extends ControlFlowNode {
/** Get any ControlFlowNode that is used to construct the final URL.
*
* In the HTTPConnection example, there is a result for both `'example.com'` and for `'/path'`.
*/
/**
* Get any ControlFlowNode that is used to construct the final URL.
*
* In the HTTPConnection example, there is a result for both `'example.com'` and for `'/path'`.
*/
abstract ControlFlowNode getAUrlPart();
abstract string getMethodUpper();
@@ -134,14 +111,8 @@ module Client {
/** Taint sink for the URL-part of an outgoing http request */
class HttpRequestUrlTaintSink extends TaintSink {
HttpRequestUrlTaintSink() { this = any(HttpRequest r).getAUrlPart() }
HttpRequestUrlTaintSink() {
this = any(HttpRequest r).getAUrlPart()
}
override predicate sinks(TaintKind kind) {
kind instanceof ExternalStringKind
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
}

View File

@@ -1,13 +1,13 @@
/** Gets an http verb */
string httpVerb() {
result = "GET" or result = "POST" or
result = "PUT" or result = "PATCH" or
result = "DELETE" or result = "OPTIONS" or
result = "GET" or
result = "POST" or
result = "PUT" or
result = "PATCH" or
result = "DELETE" or
result = "OPTIONS" or
result = "HEAD"
}
/** Gets an http verb, in lower case */
string httpVerbLower() {
result = httpVerb().toLowerCase()
}
string httpVerbLower() { result = httpVerb().toLowerCase() }

View File

@@ -1,7 +1,5 @@
import python
import semmle.python.security.strings.Basic
import semmle.python.web.django.Redirect
import semmle.python.web.flask.Redirect
import semmle.python.web.tornado.Redirect

View File

@@ -27,9 +27,9 @@ class DjangoRoute extends CallNode {
}
/**
* Get the number of positional arguments that will be passed to the view.
* Will only return a result if there are no named arguments.
*/
* Get the number of positional arguments that will be passed to the view.
* Will only return a result if there are no named arguments.
*/
int getNumPositionalArguments() {
exists(DjangoRouteRegex regex |
django_route(this, regex.getAFlowNode(), _) and

View File

@@ -79,14 +79,13 @@ class DjangoClassBasedViewRequestArgument extends DjangoRequestSource {
/** An argument specified in a url routing table */
class DjangoRequestParameter extends HttpRequestTaintSource {
DjangoRequestParameter() {
exists(DjangoRoute route, Function f |
f = route.getViewFunction().getScope() |
exists(DjangoRoute route, Function f | f = route.getViewFunction().getScope() |
this.(ControlFlowNode).getNode() = f.getArgByName(route.getNamedArgument())
or
exists(int i | i >= 0 |
i < route.getNumPositionalArguments() and
// +1 because first argument is always the request
this.(ControlFlowNode).getNode() = f.getArg(i+1)
this.(ControlFlowNode).getNode() = f.getArg(i + 1)
)
)
}

View File

@@ -6,7 +6,8 @@ ClassValue theFalconAPIClass() { result = Value::named("falcon.API") }
/** Holds if `route` is routed to `resource` */
private predicate api_route(CallNode route_call, ControlFlowNode route, ClassValue resource) {
route_call.getFunction().(AttrNode).getObject("add_route").pointsTo().getClass() = theFalconAPIClass() and
route_call.getFunction().(AttrNode).getObject("add_route").pointsTo().getClass() =
theFalconAPIClass() and
route_call.getArg(0) = route and
route_call.getArg(1).pointsTo().getClass() = resource
}

View File

@@ -18,11 +18,11 @@ predicate isTornadoRequestHandlerInstance(ControlFlowNode node) {
node.pointsTo().getClass() = aTornadoRequestHandlerClass()
or
/*
* In some cases, the points-to analysis won't capture all instances we care
* about. For these, we use the following syntactic check. First, that
* `node` appears inside a method of a subclass of
* `tornado.web.RequestHandler`:
*/
* In some cases, the points-to analysis won't capture all instances we care
* about. For these, we use the following syntactic check. First, that
* `node` appears inside a method of a subclass of
* `tornado.web.RequestHandler`:
*/
node.getScope().getEnclosingScope() = aTornadoRequestHandlerClass().getScope() and
/* Secondly, that `node` refers to the `self` argument: */

View File

@@ -1,10 +1,8 @@
import python
import semmle.python.security.TaintTracking
import semmle.python.web.Http
abstract class BaseWebobRequest extends TaintKind {
bindingset[this]
BaseWebobRequest() { any() }
@@ -17,9 +15,7 @@ abstract class BaseWebobRequest extends TaintKind {
)
or
result instanceof ExternalStringKind and
(
name = "body"
)
name = "body"
}
override TaintKind getTaintOfMethodResult(string name) {
@@ -30,22 +26,13 @@ abstract class BaseWebobRequest extends TaintKind {
name = "copy_body"
)
or
result instanceof ExternalStringKind and
(
name = "as_bytes"
)
result instanceof ExternalStringKind and
name = "as_bytes"
}
}
class WebobRequest extends BaseWebobRequest {
WebobRequest() { this = "webob.Request" }
WebobRequest() {
this = "webob.Request"
}
override ClassValue getType() {
result = Value::named("webob.request.Request")
}
override ClassValue getType() { result = Value::named("webob.request.Request") }
}