mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
Python: CherryPy web framework support -- requests.
This commit is contained in:
@@ -6,3 +6,4 @@ import semmle.python.web.twisted.Request
|
||||
import semmle.python.web.bottle.Request
|
||||
import semmle.python.web.turbogears.Request
|
||||
import semmle.python.web.falcon.Request
|
||||
import semmle.python.web.cherrypy.Request
|
||||
|
||||
54
python/ql/src/semmle/python/web/cherrypy/General.qll
Normal file
54
python/ql/src/semmle/python/web/cherrypy/General.qll
Normal file
@@ -0,0 +1,54 @@
|
||||
import python
|
||||
import semmle.python.web.Http
|
||||
|
||||
module CherryPy {
|
||||
|
||||
FunctionObject expose() {
|
||||
result = ModuleObject::named("cherrypy").attr("expose")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CherryPyExposedFunction extends Function {
|
||||
|
||||
CherryPyExposedFunction() {
|
||||
this.getADecorator().refersTo(CherryPy::expose())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CherryPyRoute extends CallNode {
|
||||
|
||||
CherryPyRoute() {
|
||||
/* cherrypy.quickstart(root, script_name, config) */
|
||||
ModuleObject::named("cherrypy").attr("quickstart").(FunctionObject).getACall() = this
|
||||
or
|
||||
/* cherrypy.tree.mount(root, script_name, config) */
|
||||
this.getFunction().(AttrNode).getObject("mount").refersTo(ModuleObject::named("cherrypy").attr("tree"))
|
||||
}
|
||||
|
||||
ClassObject getAppClass() {
|
||||
this.getArg(0).refersTo(_, result, _)
|
||||
or
|
||||
this.getArgByName("root").refersTo(_, result, _)
|
||||
}
|
||||
|
||||
string getPath() {
|
||||
exists(StringObject path |
|
||||
result = path.getText()
|
||||
|
|
||||
this.getArg(1).refersTo(path)
|
||||
or
|
||||
this.getArgByName("script_name").refersTo(path)
|
||||
)
|
||||
}
|
||||
|
||||
Object getConfig() {
|
||||
this.getArg(2).refersTo(_, result, _)
|
||||
or
|
||||
this.getArgByName("config").refersTo(_, result, _)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
69
python/ql/src/semmle/python/web/cherrypy/Request.qll
Normal file
69
python/ql/src/semmle/python/web/cherrypy/Request.qll
Normal file
@@ -0,0 +1,69 @@
|
||||
import python
|
||||
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.cherrypy.General
|
||||
|
||||
/** A twisted.web.http.Request object */
|
||||
class CherryPyRequest extends TaintKind {
|
||||
|
||||
CherryPyRequest() {
|
||||
this = "cherrypy.request"
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
name = "params" and result instanceof ExternalStringDictKind
|
||||
or
|
||||
name = "cookie" and result instanceof UntrustedCookie
|
||||
}
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
(
|
||||
name = "getHeader" or
|
||||
name = "getCookie" or
|
||||
name = "getUser" or
|
||||
name = "getPassword"
|
||||
) and
|
||||
result instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class CherryPyExposedFunctionParameter extends TaintSource {
|
||||
|
||||
CherryPyExposedFunctionParameter() {
|
||||
exists(Parameter p |
|
||||
p = any(CherryPyExposedFunction f).getAnArg() and
|
||||
not p.isSelf() and
|
||||
p.asName().getAFlowNode() = this
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "CherryPy handler function parameter"
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind instanceof ExternalStringKind
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CherryPyRequestSource extends TaintSource {
|
||||
|
||||
CherryPyRequestSource() {
|
||||
this.(ControlFlowNode).refersTo(ModuleObject::named("cherrypy").attr("request"))
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind instanceof CherryPyRequest
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
| ../../../query-tests/Security/lib/cherrypy/__init__.py:10 | _ThreadLocalProxy() | cherrypy.request |
|
||||
| ../../../query-tests/Security/lib/cherrypy/__init__.py:10 | request | cherrypy.request |
|
||||
| test.py:10 | arg | externally controlled string |
|
||||
| test.py:16 | arg | externally controlled string |
|
||||
10
python/ql/test/library-tests/web/cherrypy/Sources.ql
Normal file
10
python/ql/test/library-tests/web/cherrypy/Sources.ql
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
import python
|
||||
|
||||
import semmle.python.web.HttpRequest
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
|
||||
from TaintSource src, TaintKind kind
|
||||
where src.isSourceOf(kind) and not kind.matches("tornado%")
|
||||
select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind
|
||||
2
python/ql/test/library-tests/web/cherrypy/options
Normal file
2
python/ql/test/library-tests/web/cherrypy/options
Normal file
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: --max-import-depth=3 --lang=3 -p ../../../query-tests/Security/lib/
|
||||
optimize: true
|
||||
11
python/ql/test/library-tests/web/cherrypy/red.py
Normal file
11
python/ql/test/library-tests/web/cherrypy/red.py
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
import cherrypy
|
||||
|
||||
class MultiPath(object):
|
||||
|
||||
@cherrypy.expose(['color', 'colour'])
|
||||
def red(self):
|
||||
return "RED"
|
||||
|
||||
if __name__ == '__main__':
|
||||
cherrypy.quickstart(MultiPath())
|
||||
23
python/ql/test/library-tests/web/cherrypy/test.py
Normal file
23
python/ql/test/library-tests/web/cherrypy/test.py
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
import random
|
||||
import string
|
||||
|
||||
import cherrypy
|
||||
|
||||
class A(object):
|
||||
|
||||
@cherrypy.expose
|
||||
def a(self, arg):
|
||||
return "hello " + arg
|
||||
|
||||
class B(object):
|
||||
|
||||
@cherrypy.expose
|
||||
def b(self, arg):
|
||||
return "bye " + arg
|
||||
|
||||
cherrypy.tree.mount(A(), '/a', a_conf)
|
||||
cherrypy.tree.mount(B(), '/b', b_conf)
|
||||
|
||||
cherrypy.engine.start()
|
||||
cherrypy.engine.block()
|
||||
15
python/ql/test/query-tests/Security/lib/cherrypy/__init__.py
Normal file
15
python/ql/test/query-tests/Security/lib/cherrypy/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
|
||||
from ._helper import expose, popargs, url
|
||||
|
||||
class _ThreadLocalProxy(object):
|
||||
def __getattr__(self, name):
|
||||
pass
|
||||
|
||||
|
||||
request = _ThreadLocalProxy('request')
|
||||
response = _ThreadLocalProxy('response')
|
||||
|
||||
def quickstart(root=None, script_name='', config=None):
|
||||
"""Mount the given root, start the builtin server (and engine), then block."""
|
||||
pass
|
||||
31
python/ql/test/query-tests/Security/lib/cherrypy/_helper.py
Normal file
31
python/ql/test/query-tests/Security/lib/cherrypy/_helper.py
Normal file
@@ -0,0 +1,31 @@
|
||||
def expose(func=None, alias=None):
|
||||
"""Expose the function or class.
|
||||
Optionally provide an alias or set of aliases.
|
||||
"""
|
||||
def expose_(func):
|
||||
func.exposed = True
|
||||
return func
|
||||
|
||||
return expose_
|
||||
|
||||
|
||||
def popargs(*args, **kwargs):
|
||||
"""Decorate _cp_dispatch."""
|
||||
|
||||
def decorated(cls_or_self=None, vpath=None):
|
||||
if inspect.isclass(cls_or_self):
|
||||
# cherrypy.popargs is a class decorator
|
||||
return cls
|
||||
|
||||
# We're in the actual function
|
||||
self = cls_or_self
|
||||
if vpath:
|
||||
return getattr(self, vpath.pop(0), None)
|
||||
else:
|
||||
return self
|
||||
|
||||
return decorated
|
||||
|
||||
def url(path='', qs='', script_name=None, base=None, relative=None):
|
||||
#Do some opaque stuff here...
|
||||
return new_url
|
||||
Reference in New Issue
Block a user