@@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.DataFlow
9
9
private import experimental.semmle.python.Concepts
10
10
private import semmle.python.ApiGraphs
11
11
import semmle.python.dataflow.new.RemoteFlowSources
12
+ private import semmle.python.Concepts
12
13
13
14
private module PrivateDjango {
14
15
private module django {
@@ -32,22 +33,64 @@ private module PrivateDjango {
32
33
module response {
33
34
module HttpResponse {
34
35
API:: Node baseClassRef ( ) {
35
- result = response ( ) .getMember ( "HttpResponse" ) . getReturn ( )
36
+ result = response ( ) .getMember ( "HttpResponse" )
36
37
or
37
38
// Handle `django.http.HttpResponse` alias
38
- result = http ( ) .getMember ( "HttpResponse" ) . getReturn ( )
39
+ result = http ( ) .getMember ( "HttpResponse" )
39
40
}
40
41
42
+ /** Gets a reference to the `django.http.response.HttpResponse` class. */
43
+ API:: Node classRef ( ) { result = baseClassRef ( ) .getASubclass * ( ) }
44
+
45
+ /**
46
+ * A source of instances of `django.http.response.HttpResponse`, extend this class to model new instances.
47
+ *
48
+ * This can include instantiations of the class, return values from function
49
+ * calls, or a special parameter that will be set when functions are called by an external
50
+ * library.
51
+ *
52
+ * Use the predicate `HttpResponse::instance()` to get references to instances of `django.http.response.HttpResponse`.
53
+ */
54
+ abstract class InstanceSource extends HTTP:: Server:: HttpResponse:: Range , DataFlow:: Node {
55
+ }
56
+
57
+ /** A direct instantiation of `django.http.response.HttpResponse`. */
58
+ private class ClassInstantiation extends InstanceSource , DataFlow:: CallCfgNode {
59
+ ClassInstantiation ( ) { this = classRef ( ) .getACall ( ) }
60
+
61
+ override DataFlow:: Node getBody ( ) {
62
+ result in [ this .getArg ( 0 ) , this .getArgByName ( "content" ) ]
63
+ }
64
+
65
+ // How to support the `headers` argument here?
66
+ override DataFlow:: Node getMimetypeOrContentTypeArg ( ) {
67
+ result in [ this .getArg ( 1 ) , this .getArgByName ( "content_type" ) ]
68
+ }
69
+
70
+ override string getMimetypeDefault ( ) { result = "text/html" }
71
+ }
72
+
73
+ /** Gets a reference to an instance of `django.http.response.HttpResponse`. */
74
+ private DataFlow:: TypeTrackingNode instance ( DataFlow:: TypeTracker t ) {
75
+ t .start ( ) and
76
+ result instanceof InstanceSource
77
+ or
78
+ exists ( DataFlow:: TypeTracker t2 | result = instance ( t2 ) .track ( t2 , t ) )
79
+ }
80
+
81
+ /** Gets a reference to an instance of `django.http.response.HttpResponse`. */
82
+ DataFlow:: Node instance ( ) { instance ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( result ) }
83
+
41
84
/** Gets a reference to a header instance. */
42
85
private DataFlow:: LocalSourceNode headerInstance ( DataFlow:: TypeTracker t ) {
43
86
t .start ( ) and
44
87
(
45
88
exists ( SubscriptNode subscript |
46
- subscript .getObject ( ) = baseClassRef ( ) .getAUse ( ) .asCfgNode ( ) and
89
+ subscript .getObject ( ) = baseClassRef ( ) .getReturn ( ) . getAUse ( ) .asCfgNode ( ) and
47
90
result .asCfgNode ( ) = subscript
48
91
)
49
92
or
50
- result .( DataFlow:: AttrRead ) .getObject ( ) = baseClassRef ( ) .getAUse ( )
93
+ result .( DataFlow:: AttrRead ) .getObject ( ) = baseClassRef ( ) .getReturn ( ) . getAUse ( )
51
94
)
52
95
or
53
96
exists ( DataFlow:: TypeTracker t2 | result = headerInstance ( t2 ) .track ( t2 , t ) )
@@ -106,27 +149,35 @@ private module PrivateDjango {
106
149
* * `isHttpOnly()` predicate would succeed.
107
150
* * `isSameSite()` predicate would succeed.
108
151
*/
109
- class DjangoSetCookieCall extends DataFlow:: CallCfgNode , Cookie:: Range {
110
- DjangoSetCookieCall ( ) { this = baseClassRef ( ) .getMember ( "set_cookie" ) .getACall ( ) }
152
+ class DjangoResponseSetCookieCall extends DataFlow:: MethodCallNode , Cookie:: Range {
153
+ DjangoResponseSetCookieCall ( ) {
154
+ this .calls ( django:: http:: response:: HttpResponse:: instance ( ) , "set_cookie" )
155
+ }
111
156
112
- override DataFlow:: Node getNameArg ( ) { result = this .getArg ( 0 ) }
157
+ override DataFlow:: Node getNameArg ( ) {
158
+ result in [ this .getArg ( 0 ) , this .getArgByName ( "key" ) ]
159
+ }
113
160
114
- override DataFlow:: Node getValueArg ( ) { result = this .getArgByName ( "value" ) }
161
+ override DataFlow:: Node getValueArg ( ) {
162
+ result in [ this .getArg ( 1 ) , this .getArgByName ( "value" ) ]
163
+ }
115
164
116
165
override predicate isSecure ( ) {
117
166
DataFlow:: exprNode ( any ( True t ) )
118
167
.( DataFlow:: LocalSourceNode )
119
- .flowsTo ( this .getArgByName ( "secure" ) )
168
+ .flowsTo ( this .( DataFlow :: CallCfgNode ) . getArgByName ( "secure" ) )
120
169
}
121
170
122
171
override predicate isHttpOnly ( ) {
123
172
DataFlow:: exprNode ( any ( True t ) )
124
173
.( DataFlow:: LocalSourceNode )
125
- .flowsTo ( this .getArgByName ( "httponly" ) )
174
+ .flowsTo ( this .( DataFlow :: CallCfgNode ) . getArgByName ( "httponly" ) )
126
175
}
127
176
128
177
override predicate isSameSite ( ) {
129
- this .getArgByName ( "samesite" ) .asExpr ( ) .( Str_ ) .getS ( ) in [ "Strict" , "Lax" ]
178
+ this .( DataFlow:: CallCfgNode ) .getArgByName ( "samesite" ) .asExpr ( ) .( Str_ ) .getS ( ) in [
179
+ "Strict" , "Lax"
180
+ ]
130
181
}
131
182
132
183
override DataFlow:: Node getHeaderArg ( ) { none ( ) }
0 commit comments