@@ -7,11 +7,11 @@ import semmle.code.csharp.frameworks.system.Web
77
88/** Holds if `name` is the `X-Frame-Options` header name, ignoring case. */
99bindingset [ name]
10- predicate isXFrameOptionsHeaderName ( string name ) { name .toLowerCase ( ) = "x-frame-options" }
10+ predicate isXFrameOptionsText ( string name ) { name .toLowerCase ( ) = "x-frame-options" }
1111
1212/** Holds if `name` is the enforced `Content-Security-Policy` header name, ignoring case. */
1313bindingset [ name]
14- predicate isContentSecurityPolicyHeaderName ( string name ) {
14+ predicate isContentSecurityPolicyText ( string name ) {
1515 name .toLowerCase ( ) = "content-security-policy"
1616}
1717
@@ -24,49 +24,42 @@ predicate containsFrameAncestorsDirective(string value) {
2424 value .regexpMatch ( "(?is)(^|.*[;,])\\s*frame-ancestors(\\s|;|$).*" )
2525}
2626
27- private predicate isHeaderNamesField ( Expr name , string fieldName ) {
28- exists ( FieldAccess access |
29- name .stripImplicit ( ) = access and
30- access .getTarget ( ) .hasFullyQualifiedName ( "Microsoft.Net.Http.Headers" , "HeaderNames" , fieldName )
31- )
32- }
33-
3427private predicate isXFrameOptionsHeaderNameExpr ( Expr name ) {
35- isXFrameOptionsHeaderName ( name .stripImplicit ( ) .getValue ( ) )
28+ isXFrameOptionsText ( name .stripImplicit ( ) .getValue ( ) )
3629 or
37- isHeaderNamesField ( name , "XFrameOptions" )
30+ name .stripImplicit ( ) .( FieldAccess ) .getTarget ( ) =
31+ any ( MicrosoftNetHttpHeadersHeaderNames f ) .getXFrameOptionsField ( )
3832}
3933
4034private predicate isContentSecurityPolicyHeaderNameExpr ( Expr name ) {
41- isContentSecurityPolicyHeaderName ( name .stripImplicit ( ) .getValue ( ) )
42- or
43- isHeaderNamesField ( name , "ContentSecurityPolicy" )
35+ isContentSecurityPolicyText ( name .stripImplicit ( ) .getValue ( ) ) or
36+ name . stripImplicit ( ) . ( FieldAccess ) . getTarget ( ) =
37+ any ( MicrosoftNetHttpHeadersHeaderNames f ) . getContentSecurityPolicyField ( )
4438}
4539
4640private predicate containsFrameAncestorsDirectiveExpr ( Expr value ) {
4741 containsFrameAncestorsDirective ( value .stripImplicit ( ) .getValue ( ) )
4842}
4943
5044private predicate isDirectResponseHeadersAccess ( Expr expr ) {
51- exists ( PropertyAccessExpr headers , MicrosoftAspNetCoreHttpHttpResponse response |
45+ exists ( PropertyAccess headers , MicrosoftAspNetCoreHttpHttpResponse response |
5246 expr .stripImplicit ( ) = headers and headers .getProperty ( ) = response .getHeadersProperty ( )
5347 )
5448}
5549
56- private predicate isResponseHeadersAccess ( Expr expr ) {
57- exists ( Expr directAccess |
58- isDirectResponseHeadersAccess ( directAccess ) and
59- DataFlow:: localExprFlow ( directAccess , expr .stripImplicit ( ) )
50+ private predicate isCallOnResponseHeadersAccess ( Call call ) {
51+ exists ( Expr qualifier |
52+ call .( MethodCall ) .getQualifier ( ) = qualifier or
53+ call .( ExtensionMethodCall ) .getArgument ( 0 ) = qualifier or
54+ call .( AccessorCall ) .getQualifier ( ) = qualifier
55+ |
56+ exists ( Expr directAccess |
57+ isDirectResponseHeadersAccess ( directAccess ) and
58+ DataFlow:: localExprFlow ( directAccess , qualifier .stripImplicit ( ) )
59+ )
6060 )
6161}
6262
63- private Expr getHeaderDictionaryReceiver ( MethodCall call ) {
64- result = call .getQualifier ( )
65- or
66- call .getTarget ( ) .isExtensionMethod ( ) and
67- result = call .getArgumentForParameter ( call .getTarget ( ) .getParameter ( 0 ) )
68- }
69-
7063private predicate isClickjackingHeaderCall ( MethodCall call ) {
7164 (
7265 call .getTarget ( ) = any ( SystemWebHttpResponseClass r ) .getAppendHeaderMethod ( ) or
@@ -78,9 +71,14 @@ private predicate isClickjackingHeaderCall(MethodCall call) {
7871 isContentSecurityPolicyHeaderNameExpr ( call .getArgumentForName ( "name" ) ) and
7972 containsFrameAncestorsDirectiveExpr ( call .getArgumentForName ( "value" ) )
8073 )
81- or
82- call .getTarget ( ) .hasUndecoratedName ( [ "Append" , "Add" , "TryAdd" ] ) and
83- isResponseHeadersAccess ( getHeaderDictionaryReceiver ( call ) ) and
74+ }
75+
76+ private predicate isClickjackingHeaderDictionaryLikeWrite ( Call call ) {
77+ (
78+ call .getTarget ( ) .hasUndecoratedName ( [ "Append" , "Add" , "TryAdd" ] )
79+ or
80+ call .( IndexerCall ) .getTarget ( ) instanceof Setter
81+ ) and
8482 (
8583 isXFrameOptionsHeaderNameExpr ( call .getArgumentForName ( "key" ) )
8684 or
@@ -89,39 +87,26 @@ private predicate isClickjackingHeaderCall(MethodCall call) {
8987 )
9088}
9189
92- private predicate isClickjackingHeaderIndexerAssignment ( AssignExpr assignment ) {
93- exists ( IndexerCall indexer |
94- assignment .getLeftOperand ( ) = indexer and
95- isResponseHeadersAccess ( indexer .getQualifier ( ) ) and
96- (
97- isXFrameOptionsHeaderNameExpr ( indexer .getArgument ( 0 ) )
98- or
99- isContentSecurityPolicyHeaderNameExpr ( indexer .getArgument ( 0 ) ) and
100- containsFrameAncestorsDirectiveExpr ( assignment .getRightOperand ( ) )
101- )
102- )
103- }
104-
105- private predicate isClickjackingNamedHeaderPropertyAssignment ( AssignExpr assignment ) {
106- exists ( PropertyAccessExpr header |
107- assignment .getLeftOperand ( ) = header and
108- isResponseHeadersAccess ( header .( QualifiableExpr ) .getQualifier ( ) ) and
109- (
110- header .getProperty ( ) .hasName ( "XFrameOptions" )
111- or
112- header .getProperty ( ) .hasName ( "ContentSecurityPolicy" ) and
113- containsFrameAncestorsDirectiveExpr ( assignment .getRightOperand ( ) )
114- )
90+ private predicate isClickjackingPropertyWrite ( Call c ) {
91+ c .getTarget ( ) instanceof Setter and
92+ (
93+ c .( PropertyCall ) .getProperty ( ) =
94+ any ( MicrosoftAspNetCoreHttpIHeaderDictionary dic ) .getXFrameOptionsProperty ( )
95+ or
96+ c .( PropertyCall ) .getProperty ( ) =
97+ any ( MicrosoftAspNetCoreHttpIHeaderDictionary dic ) .getContentSecurityPolicyProperty ( ) and
98+ containsFrameAncestorsDirectiveExpr ( c .getArgumentForName ( "value" ) )
11599 )
116100}
117101
118102/** Gets an expression that configures a clickjacking-related response header. */
119- Expr getAClickjackingHeaderWrite ( ) {
120- result = any ( MethodCall call | isClickjackingHeaderCall ( call ) )
103+ Call getAClickjackingHeaderWrite ( ) {
104+ isClickjackingHeaderCall ( result )
121105 or
122- result =
123- any ( AssignExpr assignment |
124- isClickjackingHeaderIndexerAssignment ( assignment ) or
125- isClickjackingNamedHeaderPropertyAssignment ( assignment )
126- )
106+ isCallOnResponseHeadersAccess ( result ) and
107+ (
108+ isClickjackingHeaderDictionaryLikeWrite ( result )
109+ or
110+ isClickjackingPropertyWrite ( result )
111+ )
127112}
0 commit comments