-
Notifications
You must be signed in to change notification settings - Fork 1.8k
C#: Promote insecure cookie and httponly cookie queries #20692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
joefarebrother
merged 19 commits into
github:main
from
joefarebrother:csharp-secure-cookie-promote
Nov 10, 2025
+561
−907
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
7bb65fe
Refactor secure cookie query
joefarebrother d3ea675
Simplify checks for assignments to false to creation case
joefarebrother a1864ed
Presere behaviour for insecure cookie constructor
joefarebrother 71ad5a3
Refactor httponly cookie query
joefarebrother a87a03c
Move to main query pack
joefarebrother 3cdfa8e
Update comments and names
joefarebrother bb010fe
Add tests for secure cookie using aspnetcore
joefarebrother a9b97f7
Add tests for insecure cookie using system.web
joefarebrother ae0b997
Add system.web tests for httponly cookie
joefarebrother 6ba7ece
Add httponly tests for aspnet core + fixes
joefarebrother cdd1edd
Remove experimental versions
joefarebrother c734e74
Update qhelp
joefarebrother d8eeae7
Add additional test case for httponly cookies set to true
joefarebrother d29fc9d
Add changenote
joefarebrother 0a085dc
Fix qhelp
joefarebrother 544446b
Minor comment update
joefarebrother 7d5388f
Update integration tests
joefarebrother b813c13
Restrict sinks to fix performance
joefarebrother c9a559a
Restrict Append calls to string arguments
joefarebrother File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
csharp/ql/src/Security Features/CWE-1004/CookieWithoutHttpOnly.qhelp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
|
|
||
| <overview> | ||
| <p>Cookies without the <code>HttpOnly</code> flag set are accessible to client-side scripts such as JavaScript running in the same origin. | ||
| In case of a Cross-Site Scripting (XSS) vulnerability, the cookie can be stolen by a malicious script. | ||
| If a sensitive cookie does not need to be accessed directly by client-side JS, the <code>HttpOnly</code> flag should be set.</p> | ||
| </overview> | ||
|
|
||
| <recommendation> | ||
| <p> | ||
| Set the <code>HttpOnly</code> flag to <code>true</code> for authentication cookies to ensure they are not accessible to client-side scripts. | ||
| </p> | ||
| <p> | ||
| When using ASP.NET Core, <code>CookiePolicyOptions</code> can be used to set a default policy for cookies. | ||
|
|
||
| When using ASP.NET Web Forms, a default may also be configured in the <code>Web.config</code> file, using the <code>httpOnlyCookies</code> attribute of the | ||
| the <code><httpCookies></code> element. | ||
| </p> | ||
| </recommendation> | ||
|
|
||
| <example> | ||
|
|
||
| <p> | ||
| In the example below, <code>Microsoft.AspNetCore.Http.CookieOptions.HttpOnly</code> is set to <code>true</code>. | ||
| </p> | ||
|
|
||
| <sample src="httponlyflagcore.cs" /> | ||
|
|
||
| <p> | ||
| In the following example, <code>CookiePolicyOptions</code> are set programmatically to configure defaults. | ||
| </p> | ||
|
|
||
| <sample src="cookiepolicyoptions.cs" /> | ||
|
|
||
| <p> | ||
| In the example below, <code>System.Web.HttpCookie.HttpOnly</code> is set to <code>true</code>. | ||
| </p> | ||
|
|
||
| <sample src="httponlyflag.cs" /> | ||
|
|
||
| <p> | ||
| In the example below, the <code>httpOnlyCookies</code> attribute is set to <code>true</code> in the <code>Web.config</code> file. | ||
| </p> | ||
| <sample src="Web.config"/> | ||
|
|
||
| </example> | ||
|
|
||
| <references> | ||
|
|
||
| <li>ASP.Net Core docs: <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.cookieoptions.httponly">CookieOptions.HttpOnly Property</a>.</li> | ||
| <li>MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a> Header.</li> | ||
| <li>Web Forms docs: <a href="https://msdn.microsoft.com/en-us/library/system.web.httpcookie.httponly(v=vs.110).aspx">HttpCookie.HttpOnly Property</a>.</li> | ||
| <li>Web Forms docs: <a href="https://msdn.microsoft.com/library/ms228262%28v=vs.100%29.aspx">httpCookies Element</a>.</li> | ||
| <li>PortSwigger: <a href="https://portswigger.net/kb/issues/00500600_cookie-without-httponly-flag-set">Cookie without HttpOnly flag set</a></li> | ||
|
|
||
| </references> | ||
| </qhelp> |
118 changes: 118 additions & 0 deletions
118
csharp/ql/src/Security Features/CWE-1004/CookieWithoutHttpOnly.ql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| /** | ||
| * @name Cookie 'HttpOnly' attribute is not set to true | ||
| * @description Sensitive cookies without the `HttpOnly` property set are accessible by client-side scripts such as JavaScript. | ||
| * This makes them more vulnerable to being stolen by an XSS attack. | ||
| * @kind problem | ||
| * @problem.severity warning | ||
| * @security-severity 5.0 | ||
| * @precision high | ||
| * @id cs/web/cookie-httponly-not-set | ||
| * @tags security | ||
| * external/cwe/cwe-1004 | ||
| */ | ||
|
|
||
| import csharp | ||
| import semmle.code.asp.WebConfig | ||
| import semmle.code.csharp.frameworks.system.Web | ||
| import semmle.code.csharp.frameworks.microsoft.AspNetCore | ||
| import semmle.code.csharp.security.auth.SecureCookies | ||
|
|
||
| predicate cookieAppendHttpOnlyByDefault() { | ||
| // default is set to `Always` | ||
| getAValueForCookiePolicyProp("HttpOnly").getValue() = "1" | ||
| or | ||
| // there is an `OnAppendCookie` callback that sets `HttpOnly` to true | ||
| OnAppendCookieHttpOnlyTracking::flowTo(_) | ||
| } | ||
|
|
||
| predicate httpOnlyFalse(ObjectCreation oc) { | ||
| exists(Assignment a | | ||
| getAValueForProp(oc, a, "HttpOnly") = a.getRValue() and | ||
| a.getRValue().getValue() = "false" | ||
| ) | ||
| } | ||
|
|
||
| predicate httpOnlyFalseOrNotSet(ObjectCreation oc) { | ||
| httpOnlyFalse(oc) | ||
| or | ||
| not isPropertySet(oc, "HttpOnly") | ||
| } | ||
|
|
||
| predicate nonHttpOnlyCookieOptionsCreation(ObjectCreation oc, MethodCall append) { | ||
| // `HttpOnly` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set | ||
| oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and | ||
| httpOnlyFalseOrNotSet(oc) and | ||
| exists(DataFlow::Node creation, DataFlow::Node sink | | ||
| CookieOptionsTracking::flow(creation, sink) and | ||
| creation.asExpr() = oc and | ||
| sink.asExpr() = append.getArgument(2) | ||
| ) | ||
| } | ||
|
|
||
| predicate nonHttpOnlySystemWebSensitiveCookieCreation(ObjectCreation oc) { | ||
| oc.getType() instanceof SystemWebHttpCookie and | ||
| isCookieWithSensitiveName(oc.getArgument(0)) and | ||
| ( | ||
| httpOnlyFalse(oc) | ||
| or | ||
| // the property wasn't explicitly set, so a default value from config is used | ||
| not isPropertySet(oc, "HttpOnly") and | ||
| // the default in config is not set to `true` | ||
| not exists(XmlElement element | | ||
| element instanceof HttpCookiesElement and | ||
| element.(HttpCookiesElement).isHttpOnlyCookies() | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| predicate sensitiveCookieAppend(MethodCall mc) { | ||
| exists(MicrosoftAspNetCoreHttpResponseCookies iResponse | | ||
| iResponse.getAppendMethod() = mc.getTarget() and | ||
| isCookieWithSensitiveName(mc.getArgument(0)) | ||
| ) | ||
| } | ||
|
|
||
| predicate nonHttpOnlyCookieCall(Call c) { | ||
| ( | ||
| not cookieAppendHttpOnlyByDefault() and | ||
| exists(MethodCall mc | | ||
| sensitiveCookieAppend(mc) and | ||
| ( | ||
| nonHttpOnlyCookieOptionsCreation(c, mc) | ||
| or | ||
| // IResponseCookies.Append(String, String) was called, `HttpOnly` is set to `false` by default | ||
| mc = c and | ||
| mc.getNumberOfArguments() < 3 and | ||
| mc.getTarget().getParameter(0).getType() instanceof StringType | ||
| ) | ||
| ) | ||
| or | ||
| nonHttpOnlySystemWebSensitiveCookieCreation(c) | ||
| ) | ||
| } | ||
|
|
||
| predicate nonHttpOnlyCookieBuilderAssignment(Assignment a, Expr val) { | ||
| val.getValue() = "false" and | ||
| exists(PropertyWrite pw | | ||
| ( | ||
| pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieBuilder or | ||
| pw.getProperty().getDeclaringType() instanceof | ||
| MicrosoftAspNetCoreAuthenticationCookiesCookieAuthenticationOptions | ||
| ) and | ||
| pw.getProperty().getName() = "HttpOnly" and | ||
| a.getLValue() = pw and | ||
| DataFlow::localExprFlow(val, a.getRValue()) | ||
| ) | ||
| } | ||
|
|
||
| from Expr httpOnlySink | ||
| where | ||
| ( | ||
| nonHttpOnlyCookieCall(httpOnlySink) | ||
| or | ||
| exists(Assignment a | | ||
| httpOnlySink = a.getRValue() and | ||
| nonHttpOnlyCookieBuilderAssignment(a, _) | ||
| ) | ||
| ) | ||
| select httpOnlySink, "Cookie attribute 'HttpOnly' is not set to true." | ||
4 changes: 2 additions & 2 deletions
4
...equireSSLSystemWeb/ConfigFalse/Web.config → ...src/Security Features/CWE-1004/Web.config
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| <?xml version="1.0" encoding="utf-8" ?> | ||
| <configuration> | ||
| <system.web> | ||
| <httpCookies requireSSL="false" /> | ||
| <httpCookies httpOnlyCookies="true"/> | ||
| </system.web> | ||
| </configuration> | ||
| </configuration> |
File renamed without changes.
File renamed without changes.
File renamed without changes.
61 changes: 61 additions & 0 deletions
61
csharp/ql/src/Security Features/CWE-614/CookieWithoutSecure.qhelp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
|
|
||
| <overview> | ||
| <p>Cookies without the <code>Secure</code> flag set may be transmitted using HTTP instead of HTTPS. | ||
| This leaves them vulnerable to being read by a third party attacker. If a sensitive cookie such as a session | ||
| key is intercepted this way, it would allow the attacker to perform actions on a user's behalf.</p> | ||
| </overview> | ||
|
|
||
| <recommendation> | ||
| <p> | ||
| When using ASP.NET Core, ensure cookies have the secure flag set by setting <code>Microsoft.AspNetCore.Http.CookieOptions.Secure</code> to <code>true</code>, or | ||
| using <code>CookiePolicyOptions</code> to set a default security policy. | ||
| </p> | ||
| <p> | ||
| When using ASP.NET Web Forms, cookies can be configured as secure by default in the <code>Web.config</code> file, setting the <code>requireSSL</code> attribute to <code>true</code> in the <code>forms</code> or <code>httpCookies</code> element. | ||
| Cookies may also be set to be secure programmatically by setting the <code>System.Web.HttpCookie.Secure</code> attribute to <code>true</code>. | ||
| </p> | ||
| </recommendation> | ||
|
|
||
| <example> | ||
|
|
||
| <p> | ||
| In the example below, <code>Microsoft.AspNetCore.Http.CookieOptions.Secure</code> is set to <code>true</code>. | ||
| </p> | ||
|
|
||
| <sample src="secureflagcore.cs" /> | ||
|
|
||
| <p> | ||
| In the following example, <code>CookiePolicyOptions</code> are set programmatically to configure defaults. | ||
| </p> | ||
|
|
||
| <sample src="cookiepolicyoptions.cs" /> | ||
|
|
||
| <p> | ||
| In the example below <code>System.Web.HttpCookie.Secure</code> is set to <code>true</code> programmatically. | ||
| </p> | ||
|
|
||
| <sample src="secureflag.cs" /> | ||
|
|
||
| <p> | ||
| In the example below, the <code>requireSSL</code> attribute is set to <code>true</code> in the <code>forms</code> element of the <code>Web.config</code> file. | ||
| </p> | ||
| <sample src="Web.config" /> | ||
|
|
||
| </example> | ||
|
|
||
| <references> | ||
|
|
||
| <li>ASP.NET Core docs: <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.cookieoptions.secure">CookieOptions.Secure Property</a>.</li> | ||
| <li>MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a> Header.</li> | ||
| <li>Web Forms docs: <a href="https://msdn.microsoft.com/en-us/library/system.web.security.formsauthentication.requiressl(v=vs.110).aspx">FormsAuthentication.RequireSSL Property</a>.</li> | ||
| <li>Web Forms docs: <a href="https://msdn.microsoft.com/en-us/library/1d3t3c61(v=vs.100).aspx">forms Element for authentication</a>.</li> | ||
| <li>Web Forms docs: <a href="https://msdn.microsoft.com/library/ms228262%28v=vs.100%29.aspx">httpCookies Element</a>.</li> | ||
| <li>Detectify: <a href="https://support.detectify.com/support/solutions/articles/48001048982-cookie-lack-secure-flag">Cookie lack Secure flag</a>.</li> | ||
| <li>PortSwigger: <a href="https://portswigger.net/kb/issues/00500200_tls-cookie-without-secure-flag-set">TLS cookie without secure flag set</a>.</li> | ||
|
|
||
| </references> | ||
| </qhelp> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.