From 13b2a0caeaafee3e95632225d198a9c43b730b7e Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 29 Oct 2024 13:37:55 +0100 Subject: [PATCH 1/5] C#: Add a copy of all experimental queries (as is). --- .../src/security/CWE-099/TaintedWebClient.cs | 31 +++ .../security/CWE-099/TaintedWebClient.qhelp | 58 ++++ .../src/security/CWE-099/TaintedWebClient.ql | 24 ++ .../security/CWE-099/TaintedWebClientLib.qll | 90 +++++++ .../CWE-1004/CookieWithoutHttpOnly.qhelp | 51 ++++ .../CWE-1004/CookieWithoutHttpOnly.ql | 105 ++++++++ .../security/CWE-1004/cookiepolicyoptions.cs | 12 + csharp/src/security/CWE-1004/httponlyflag.cs | 7 + .../src/security/CWE-1004/httponlyflagcore.cs | 8 + ...nsafeUsageOfClientSideEncryptionVersion.cs | 44 +++ ...feUsageOfClientSideEncryptionVersion.qhelp | 29 ++ ...nsafeUsageOfClientSideEncryptionVersion.ql | 82 ++++++ .../CWE-614/CookieWithoutSecure.qhelp | 55 ++++ .../security/CWE-614/CookieWithoutSecure.ql | 105 ++++++++ csharp/src/security/CWE-614/Web.config | 13 + .../security/CWE-614/cookiepolicyoptions.cs | 12 + csharp/src/security/CWE-614/secureflag.cs | 7 + csharp/src/security/CWE-614/secureflagcore.cs | 8 + .../src/security/CWE-759/HashWithoutSalt.cs | 65 +++++ .../security/CWE-759/HashWithoutSalt.qhelp | 29 ++ .../src/security/CWE-759/HashWithoutSalt.ql | 198 ++++++++++++++ csharp/src/security/CWE-918/RequestForgery.cs | 33 +++ .../src/security/CWE-918/RequestForgery.qhelp | 35 +++ csharp/src/security/CWE-918/RequestForgery.ql | 20 ++ .../src/security/CWE-918/RequestForgery.qll | 238 +++++++++++++++++ .../JsonWebTokenHandlerLib.qll | 207 +++++++++++++++ ...rity-validations-always-return-true-bad.cs | 10 + ...ity-validations-always-return-true-good.cs | 17 ++ ...urity-validations-always-return-true.qhelp | 28 ++ ...security-validations-always-return-true.ql | 24 ++ .../security-validation-disabled-bad.cs | 13 + .../security-validation-disabled-good.cs | 13 + .../security-validation-disabled.qhelp | 27 ++ .../security-validation-disabled.ql | 26 ++ .../DataSetSerialization.inc.qhelp | 23 ++ .../Serialization/DataSetSerialization.qll | 94 +++++++ .../DefiningDatasetRelatedType.qhelp | 5 + .../DefiningDatasetRelatedType.ql | 17 ++ ...finingPotentiallyUnsafeXmlSerializer.qhelp | 5 + .../DefiningPotentiallyUnsafeXmlSerializer.ql | 21 ++ ...UnsafeTypeUsedDataContractSerializer.qhelp | 5 + .../UnsafeTypeUsedDataContractSerializer.ql | 46 ++++ .../XmlDeserializationWithDataSet.qhelp | 5 + .../XmlDeserializationWithDataSet.ql | 17 ++ .../DangerousNativeFunctionCall.qhelp | 14 + .../backdoor/DangerousNativeFunctionCall.ql | 55 ++++ .../security/backdoor/PotentialTimeBomb.qhelp | 14 + .../security/backdoor/PotentialTimeBomb.ql | 186 +++++++++++++ .../backdoor/ProcessNameToHashTaintFlow.qhelp | 15 ++ .../backdoor/ProcessNameToHashTaintFlow.ql | 49 ++++ .../dataflow/flowsources/AuthCookie.qll | 250 ++++++++++++++++++ 51 files changed, 2545 insertions(+) create mode 100644 csharp/src/security/CWE-099/TaintedWebClient.cs create mode 100644 csharp/src/security/CWE-099/TaintedWebClient.qhelp create mode 100644 csharp/src/security/CWE-099/TaintedWebClient.ql create mode 100644 csharp/src/security/CWE-099/TaintedWebClientLib.qll create mode 100644 csharp/src/security/CWE-1004/CookieWithoutHttpOnly.qhelp create mode 100644 csharp/src/security/CWE-1004/CookieWithoutHttpOnly.ql create mode 100644 csharp/src/security/CWE-1004/cookiepolicyoptions.cs create mode 100644 csharp/src/security/CWE-1004/httponlyflag.cs create mode 100644 csharp/src/security/CWE-1004/httponlyflagcore.cs create mode 100644 csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.cs create mode 100644 csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.qhelp create mode 100644 csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql create mode 100644 csharp/src/security/CWE-614/CookieWithoutSecure.qhelp create mode 100644 csharp/src/security/CWE-614/CookieWithoutSecure.ql create mode 100644 csharp/src/security/CWE-614/Web.config create mode 100644 csharp/src/security/CWE-614/cookiepolicyoptions.cs create mode 100644 csharp/src/security/CWE-614/secureflag.cs create mode 100644 csharp/src/security/CWE-614/secureflagcore.cs create mode 100644 csharp/src/security/CWE-759/HashWithoutSalt.cs create mode 100644 csharp/src/security/CWE-759/HashWithoutSalt.qhelp create mode 100644 csharp/src/security/CWE-759/HashWithoutSalt.ql create mode 100644 csharp/src/security/CWE-918/RequestForgery.cs create mode 100644 csharp/src/security/CWE-918/RequestForgery.qhelp create mode 100644 csharp/src/security/CWE-918/RequestForgery.ql create mode 100644 csharp/src/security/CWE-918/RequestForgery.qll create mode 100644 csharp/src/security/JsonWebTokenHandler/JsonWebTokenHandlerLib.qll create mode 100644 csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true-bad.cs create mode 100644 csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true-good.cs create mode 100644 csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qhelp create mode 100644 csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql create mode 100644 csharp/src/security/JsonWebTokenHandler/security-validation-disabled-bad.cs create mode 100644 csharp/src/security/JsonWebTokenHandler/security-validation-disabled-good.cs create mode 100644 csharp/src/security/JsonWebTokenHandler/security-validation-disabled.qhelp create mode 100644 csharp/src/security/JsonWebTokenHandler/security-validation-disabled.ql create mode 100644 csharp/src/security/Serialization/DataSetSerialization.inc.qhelp create mode 100644 csharp/src/security/Serialization/DataSetSerialization.qll create mode 100644 csharp/src/security/Serialization/DefiningDatasetRelatedType.qhelp create mode 100644 csharp/src/security/Serialization/DefiningDatasetRelatedType.ql create mode 100644 csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qhelp create mode 100644 csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql create mode 100644 csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.qhelp create mode 100644 csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.ql create mode 100644 csharp/src/security/Serialization/XmlDeserializationWithDataSet.qhelp create mode 100644 csharp/src/security/Serialization/XmlDeserializationWithDataSet.ql create mode 100644 csharp/src/security/backdoor/DangerousNativeFunctionCall.qhelp create mode 100644 csharp/src/security/backdoor/DangerousNativeFunctionCall.ql create mode 100644 csharp/src/security/backdoor/PotentialTimeBomb.qhelp create mode 100644 csharp/src/security/backdoor/PotentialTimeBomb.ql create mode 100644 csharp/src/security/backdoor/ProcessNameToHashTaintFlow.qhelp create mode 100644 csharp/src/security/backdoor/ProcessNameToHashTaintFlow.ql create mode 100644 csharp/src/security/dataflow/flowsources/AuthCookie.qll diff --git a/csharp/src/security/CWE-099/TaintedWebClient.cs b/csharp/src/security/CWE-099/TaintedWebClient.cs new file mode 100644 index 00000000..5913e7e1 --- /dev/null +++ b/csharp/src/security/CWE-099/TaintedWebClient.cs @@ -0,0 +1,31 @@ +using System; +using System.IO; +using System.Web; +using System.Net; + +public class TaintedWebClientHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + String url = ctx.Request.QueryString["domain"]; + + // BAD: This could read any file on the filesystem. (../../../../etc/passwd) + using(WebClient client = new WebClient()) { + ctx.Response.Write(client.DownloadString(url)); + } + + // BAD: This could still read any file on the filesystem. (https://../../../../etc/passwd) + if (url.StartsWith("https://")){ + using(WebClient client = new WebClient()) { + ctx.Response.Write(client.DownloadString(url)); + } + } + + // GOOD: IsWellFormedUriString ensures that it is a valid URL + if (Uri.IsWellFormedUriString(url, UriKind.Absolute)){ + using(WebClient client = new WebClient()) { + ctx.Response.Write(client.DownloadString(url)); + } + } + } +} diff --git a/csharp/src/security/CWE-099/TaintedWebClient.qhelp b/csharp/src/security/CWE-099/TaintedWebClient.qhelp new file mode 100644 index 00000000..d7f19590 --- /dev/null +++ b/csharp/src/security/CWE-099/TaintedWebClient.qhelp @@ -0,0 +1,58 @@ + + + +

The WebClient class provides a variety of methods for data transmission and +communication with a particular URI. Despite of the class' naming convention, +the URI scheme can also identify local resources, not only remote ones. Tainted +by user-supplied input, the URI can be leveraged to access resources available +on the local file system, therefore leading to the disclosure of sensitive +information. This can be trivially achieved by supplying path traversal +sequences (../) followed by an existing directory or file path.

+ +

Sanitization of user-supplied URI values using the +StartsWith("https://") method is deemed insufficient in preventing +arbitrary file reads. This is due to the fact that .NET ignores the protocol +handler (https in this case) in URIs like the following: +"https://../../../../etc/passwd".

+ +
+ + +

Validate user input before using it to ensure that is a URI of an external +resource and not a local one. +Potential solutions:

+ +
    +
  • Sanitize potentially tainted paths using +System.Uri.IsWellFormedUriString.
  • +
+ +
+ + +

In the first example, a domain name is read from a HttpRequest +and then this domain is requested using the method DownloadString. +However, a malicious user could enter a local path - for example, +"../../../etc/passwd" instead of a domain. +In the second example, it appears that the user is restricted to the HTTPS +protocol handler. However, a malicious user could still enter a local path, +since as explained above the protocol handler will be ignored by .net. For +example, the string "https://../../../etc/passwd" will result in the code +reading the file located at "/etc/passwd", which is the system's password file. +This file would then be sent back to the user, giving them access to all the +system's passwords.

+ + + +
+ + +
  • +OWASP: +Path Traversal. +
  • + +
    +
    diff --git a/csharp/src/security/CWE-099/TaintedWebClient.ql b/csharp/src/security/CWE-099/TaintedWebClient.ql new file mode 100644 index 00000000..38d99db6 --- /dev/null +++ b/csharp/src/security/CWE-099/TaintedWebClient.ql @@ -0,0 +1,24 @@ +/** + * @name Uncontrolled data used in a WebClient + * @description The WebClient class allows developers to request resources, + * accessing resources influenced by users can allow an attacker to access local files. + * @kind path-problem + * @problem.severity error + * @precision high + * @id cs/webclient-path-injection + * @tags security + * experimental + * external/cwe/cwe-099 + * external/cwe/cwe-023 + * external/cwe/cwe-036 + * external/cwe/cwe-073 + */ + +import csharp +import TaintedWebClientLib +import TaintedWebClient::PathGraph + +from TaintedWebClient::PathNode source, TaintedWebClient::PathNode sink +where TaintedWebClient::flowPath(source, sink) +select sink.getNode(), source, sink, "A method of WebClient depepends on a $@.", source.getNode(), + "user-provided value" diff --git a/csharp/src/security/CWE-099/TaintedWebClientLib.qll b/csharp/src/security/CWE-099/TaintedWebClientLib.qll new file mode 100644 index 00000000..716702ca --- /dev/null +++ b/csharp/src/security/CWE-099/TaintedWebClientLib.qll @@ -0,0 +1,90 @@ +import csharp +import semmle.code.csharp.frameworks.system.Net +import semmle.code.csharp.frameworks.System +import semmle.code.csharp.security.dataflow.flowsources.FlowSources +import semmle.code.csharp.security.Sanitizers + +//If this leaves experimental this should probably go in semmle.code.csharp.frameworks.system.Net +/** The `System.Net.WebClient` class. */ +class SystemNetWebClientClass extends SystemNetClass { + SystemNetWebClientClass() { this.hasName("WebClient") } + + /** Gets the `DownloadString` method. */ + Method getDownloadStringMethod() { result = this.getAMethod("DownloadString") } +} + +//If this leaves experimental this should probably go in semmle.code.csharp.frameworks.System +//Extend the already existent SystemUriClass to not touch the stdlib. +/** The `System.Uri` class. */ +class SystemUriClassExtra extends SystemUriClass { + /** Gets the `IsWellFormedUriString` method. */ + Method getIsWellFormedUriStringMethod() { result = this.getAMethod("IsWellFormedUriString") } +} + +//If this leaves experimental this should probably go in semmle.code.csharp.frameworks.system +/** + * A data flow source for uncontrolled data in path expression vulnerabilities. + */ +abstract class Source extends DataFlow::Node { } + +/** + * A data flow sink for uncontrolled data in path expression vulnerabilities. + */ +abstract class Sink extends DataFlow::ExprNode { } + +/** + * A sanitizer for uncontrolled data in path expression vulnerabilities. + */ +abstract class Sanitizer extends DataFlow::ExprNode { } + +/** + * A taint-tracking configuration for uncontrolled data in path expression vulnerabilities. + */ +private module TaintedWebClientConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** + * A taint-tracking module for uncontrolled data in path expression vulnerabilities. + */ +module TaintedWebClient = TaintTracking::Global; + +/** + * DEPRECATED: Use `ThreatModelSource` instead. + * + * A source of remote user input. + */ +deprecated class RemoteSource extends DataFlow::Node instanceof RemoteFlowSource { } + +/** A source supported by the current threat model. */ +class ThreatModelSource extends Source instanceof ActiveThreatModelSource { } + +/** + * A path argument to a `WebClient` method call that has an address argument. + */ +class WebClientSink extends Sink { + WebClientSink() { + exists(Method m | m = any(SystemNetWebClientClass f).getAMethod() | + this.getExpr() = m.getACall().getArgumentForName("address") + ) + } +} + +/** + * A call to `System.Uri.IsWellFormedUriString` that is considered to sanitize the input. + */ +class RequestMapPathSanitizer extends Sanitizer { + RequestMapPathSanitizer() { + exists(Method m | m = any(SystemUriClassExtra uri).getIsWellFormedUriStringMethod() | + this.getExpr() = m.getACall().getArgument(0) + ) + } +} + +private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { } + +private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { } diff --git a/csharp/src/security/CWE-1004/CookieWithoutHttpOnly.qhelp b/csharp/src/security/CWE-1004/CookieWithoutHttpOnly.qhelp new file mode 100644 index 00000000..c7c10a3a --- /dev/null +++ b/csharp/src/security/CWE-1004/CookieWithoutHttpOnly.qhelp @@ -0,0 +1,51 @@ + + + + +

    +Cookies without HttpOnly flag are accessible to JavaScript running in the same origin. In case of +Cross-Site Scripting (XSS) vulnerability the cookie can be stolen by malicious script. +

    +
    + + +

    +Protect sensitive cookies, such as related to authentication, by setting HttpOnly to true to make +them not accessible to JavaScript. In ASP.NET case it is also possible to set the attribute via <httpCookies> element +of web.config with the attribute httpOnlyCookies="true". +

    +
    + + + +

    +In the example below Microsoft.AspNetCore.Http.CookieOptions.HttpOnly is set to true. +

    + + + +

    +In the following example CookiePolicyOptions are set programmatically to configure defaults. +

    + + + +

    +In the example below System.Web.HttpCookie.HttpOnly is set to true. +

    + + + +
    + + + +
  • CookieOptions.HttpOnly Property,
  • +
  • Set-Cookie Header,
  • +
  • HttpCookie.HttpOnly Property,
  • +
  • httpCookies Element,
  • + +
    +
    diff --git a/csharp/src/security/CWE-1004/CookieWithoutHttpOnly.ql b/csharp/src/security/CWE-1004/CookieWithoutHttpOnly.ql new file mode 100644 index 00000000..560dcc6d --- /dev/null +++ b/csharp/src/security/CWE-1004/CookieWithoutHttpOnly.ql @@ -0,0 +1,105 @@ +/** + * @name 'HttpOnly' attribute is not set to true + * @description Omitting the 'HttpOnly' attribute for security sensitive data allows + * malicious JavaScript to steal it in case of XSS vulnerability. Always set + * 'HttpOnly' to 'true' to authentication related cookie to make it + * not accessible by JavaScript. + * @kind problem + * @problem.severity warning + * @precision high + * @id cs/web/cookie-httponly-not-set + * @tags security + * experimental + * 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 experimental.dataflow.flowsources.AuthCookie + +from Expr httpOnlySink +where + exists(Assignment a, Expr val | + httpOnlySink = a.getRValue() and + val.getValue() = "false" and + ( + exists(ObjectCreation oc | + getAValueForProp(oc, a, "HttpOnly") = val and + ( + oc.getType() instanceof SystemWebHttpCookie and + isCookieWithSensitiveName(oc.getArgument(0)) + or + exists(MethodCall mc, MicrosoftAspNetCoreHttpResponseCookies iResponse | + oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and + iResponse.getAppendMethod() = mc.getTarget() and + isCookieWithSensitiveName(mc.getArgument(0)) and + // there is no callback `OnAppendCookie` that sets `HttpOnly` to true + not OnAppendCookieHttpOnlyTracking::flowTo(_) and + // Passed as third argument to `IResponseCookies.Append` + exists(DataFlow::Node creation, DataFlow::Node append | + CookieOptionsTracking::flow(creation, append) and + creation.asExpr() = oc and + append.asExpr() = mc.getArgument(2) + ) + ) + ) + ) + or + 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()) + ) + ) + ) + or + exists(Call c | + httpOnlySink = c and + ( + exists(MicrosoftAspNetCoreHttpResponseCookies iResponse, MethodCall mc | + // default is not configured or is not set to `Always` + not getAValueForCookiePolicyProp("HttpOnly").getValue() = "1" and + // there is no callback `OnAppendCookie` that sets `HttpOnly` to true + not OnAppendCookieHttpOnlyTracking::flowTo(_) and + iResponse.getAppendMethod() = mc.getTarget() and + isCookieWithSensitiveName(mc.getArgument(0)) and + ( + // `HttpOnly` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set + exists(ObjectCreation oc | + oc = c and + oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and + not isPropertySet(oc, "HttpOnly") and + exists(DataFlow::Node creation | + CookieOptionsTracking::flow(creation, _) and + creation.asExpr() = oc + ) + ) + or + // IResponseCookies.Append(String, String) was called, `HttpOnly` is set to `false` by default + mc = c and + mc.getNumberOfArguments() < 3 + ) + ) + or + exists(ObjectCreation oc | + oc = c and + oc.getType() instanceof SystemWebHttpCookie and + isCookieWithSensitiveName(oc.getArgument(0)) and + // 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() + ) + ) + ) + ) +select httpOnlySink, "Cookie attribute 'HttpOnly' is not set to true." diff --git a/csharp/src/security/CWE-1004/cookiepolicyoptions.cs b/csharp/src/security/CWE-1004/cookiepolicyoptions.cs new file mode 100644 index 00000000..a9adf0d9 --- /dev/null +++ b/csharp/src/security/CWE-1004/cookiepolicyoptions.cs @@ -0,0 +1,12 @@ +public class Startup +{ + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCookiePolicy(new CookiePolicyOptions() + { + Secure = Microsoft.AspNetCore.Http.CookieSecurePolicy.Always, + HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.Always + }); + } +} \ No newline at end of file diff --git a/csharp/src/security/CWE-1004/httponlyflag.cs b/csharp/src/security/CWE-1004/httponlyflag.cs new file mode 100644 index 00000000..09f8dd8b --- /dev/null +++ b/csharp/src/security/CWE-1004/httponlyflag.cs @@ -0,0 +1,7 @@ +class MyController : Controller +{ + void Login() + { + var cookie = new System.Web.HttpCookie("cookieName") { HttpOnly = true }; + } +} \ No newline at end of file diff --git a/csharp/src/security/CWE-1004/httponlyflagcore.cs b/csharp/src/security/CWE-1004/httponlyflagcore.cs new file mode 100644 index 00000000..455675b5 --- /dev/null +++ b/csharp/src/security/CWE-1004/httponlyflagcore.cs @@ -0,0 +1,8 @@ +class MyController : Controller +{ + void Login() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { HttpOnly = true }; + Response.Cookies.Append("auth", "secret", cookieOptions); + } +} \ No newline at end of file diff --git a/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.cs b/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.cs new file mode 100644 index 00000000..0810516e --- /dev/null +++ b/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.cs @@ -0,0 +1,44 @@ + +{ + SymmetricKey aesKey = new SymmetricKey(kid: "symencryptionkey"); + + // BAD: Using the outdated client side encryption version V1_0 + BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(key: aesKey, keyResolver: null); + BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy }; + + MemoryStream stream = new MemoryStream(buffer); + blob.UploadFromStream(stream, length: size, accessCondition: null, options: uploadOptions); +} + +var client = new BlobClient(myConnectionString, new SpecializedBlobClientOptions() +{ + // BAD: Using an outdated SDK that does not support client side encryption version V2_0 + ClientSideEncryption = new ClientSideEncryptionOptions() + { + KeyEncryptionKey = myKey, + KeyResolver = myKeyResolver, + KeyWrapAlgorithm = myKeyWrapAlgorithm + } +}); + +var client = new BlobClient(myConnectionString, new SpecializedBlobClientOptions() +{ + // BAD: Using the outdated client side encryption version V1_0 + ClientSideEncryption = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V1_0) + { + KeyEncryptionKey = myKey, + KeyResolver = myKeyResolver, + KeyWrapAlgorithm = myKeyWrapAlgorithm + } +}); + +var client = new BlobClient(myConnectionString, new SpecializedBlobClientOptions() +{ + // GOOD: Using client side encryption version V2_0 + ClientSideEncryption = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V2_0) + { + KeyEncryptionKey = myKey, + KeyResolver = myKeyResolver, + KeyWrapAlgorithm = myKeyWrapAlgorithm + } +}); \ No newline at end of file diff --git a/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.qhelp b/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.qhelp new file mode 100644 index 00000000..54c9a499 --- /dev/null +++ b/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.qhelp @@ -0,0 +1,29 @@ + + + + + +

    Azure Storage .NET, Java, and Python SDKs support encryption on the client with a customer-managed key that is maintained in Azure Key Vault or another key store.

    +

    Current release versions of the Azure Storage SDKs use cipher block chaining (CBC mode) for client-side encryption (referred to as v1).

    + +
    + + +

    Consider switching to v2 client-side encryption.

    + +
    + + + + + + +
  • + Azure Storage Client Encryption Blog. +
  • +
  • + CVE-2022-30187 +
  • + +
    +
    diff --git a/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql b/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql new file mode 100644 index 00000000..e112d284 --- /dev/null +++ b/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql @@ -0,0 +1,82 @@ +/** + * @name Unsafe usage of v1 version of Azure Storage client-side encryption (CVE-2022-30187). + * @description Unsafe usage of v1 version of Azure Storage client-side encryption, please refer to http://aka.ms/azstorageclientencryptionblog + * @kind problem + * @tags security + * cryptography + * experimental + * external/cwe/cwe-327 + * @id cs/azure-storage/unsafe-usage-of-client-side-encryption-version + * @problem.severity error + * @precision high + */ + +import csharp + +/** + * Holds if `oc` is creating an object of type `c` = `Azure.Storage.ClientSideEncryptionOptions` + * and `e` is the `version` argument to the constructor + */ +predicate isCreatingAzureClientSideEncryptionObject(ObjectCreation oc, Class c, Expr e) { + exists(Parameter p | p.hasName("version") | + c.hasFullyQualifiedName("Azure.Storage", "ClientSideEncryptionOptions") and + oc.getTarget() = c.getAConstructor() and + e = oc.getArgumentForParameter(p) + ) +} + +/** + * Holds if `oc` is an object creation of the outdated type `c` = `Microsoft.Azure.Storage.Blob.BlobEncryptionPolicy` + */ +predicate isCreatingOutdatedAzureClientSideEncryptionObject(ObjectCreation oc, Class c) { + c.hasFullyQualifiedName("Microsoft.Azure.Storage.Blob", "BlobEncryptionPolicy") and + oc.getTarget() = c.getAConstructor() +} + +/** + * Holds if the Azure.Storage assembly for `c` is a version known to support + * version 2+ for client-side encryption + */ +predicate doesAzureStorageAssemblySupportSafeClientSideEncryption(Assembly asm) { + exists(int versionCompare | + versionCompare = asm.getVersion().compareTo("12.12.0.0") and + versionCompare >= 0 + ) and + asm.getName() = "Azure.Storage.Common" +} + +/** + * Holds if the Azure.Storage assembly for `c` is a version known to support + * version 2+ for client-side encryption and if the argument for the constructor `version` + * is set to a secure value. + */ +predicate isObjectCreationArgumentSafeAndUsingSafeVersionOfAssembly(Expr versionExpr, Assembly asm) { + // Check if the Azure.Storage assembly version has the fix + doesAzureStorageAssemblySupportSafeClientSideEncryption(asm) and + // and that the version argument for the constructor is guaranteed to be Version2 + isExprAnAccessToSafeClientSideEncryptionVersionValue(versionExpr) +} + +/** + * Holds if the expression `e` is an access to a safe version of the enum `ClientSideEncryptionVersion` + * or an equivalent numeric value + */ +predicate isExprAnAccessToSafeClientSideEncryptionVersionValue(Expr e) { + exists(EnumConstant ec | + ec.hasFullyQualifiedName("Azure.Storage.ClientSideEncryptionVersion", "V2_0") and + ec.getAnAccess() = e + ) +} + +from Expr e, Class c, Assembly asm +where + asm = c.getLocation() and + ( + exists(Expr e2 | + isCreatingAzureClientSideEncryptionObject(e, c, e2) and + not isObjectCreationArgumentSafeAndUsingSafeVersionOfAssembly(e2, asm) + ) + or + isCreatingOutdatedAzureClientSideEncryptionObject(e, c) + ) +select e, "Unsafe usage of v1 version of Azure Storage client-side encryption." diff --git a/csharp/src/security/CWE-614/CookieWithoutSecure.qhelp b/csharp/src/security/CWE-614/CookieWithoutSecure.qhelp new file mode 100644 index 00000000..ddf825ae --- /dev/null +++ b/csharp/src/security/CWE-614/CookieWithoutSecure.qhelp @@ -0,0 +1,55 @@ + + + + +

    +Sensitive data that is transmitted using HTTP is vulnerable to being read by a third party. By default, +cookies are sent via HTTP, not HTTPS. +

    +
    + + +

    +In ASP.NET case when using cookies ensure that HTTPS is used by setting the property Microsoft.AspNetCore.Http.CookieOptions.Secure to true. +

    +

    +In ASP.NET Core case when using cookies, ensure that HTTPS is used, either via the <forms> attribute above, or +the <httpCookies> element, with the attribute requireSSL="true". It is also possible to require cookies +to use HTTPS programmatically, by setting the property System.Web.HttpCookie.Secure to true. +

    +
    + + + +

    +In the example below Microsoft.AspNetCore.Http.CookieOptions.Secure is set to true programmatically. +

    + + + +

    +In the following example CookiePolicyOptions are set programmatically to configure defaults. +

    + + + +

    +In the example below System.Web.HttpCookie.Secure is set to true programmatically. +

    + + + +
    + + + +
  • CookieOptions.Secure Property,
  • +
  • Set-Cookie Header,
  • +
  • FormsAuthentication.RequireSSL Property,
  • +
  • forms Element for authentication,
  • +
  • httpCookies Element,
  • + +
    +
    diff --git a/csharp/src/security/CWE-614/CookieWithoutSecure.ql b/csharp/src/security/CWE-614/CookieWithoutSecure.ql new file mode 100644 index 00000000..417c5e59 --- /dev/null +++ b/csharp/src/security/CWE-614/CookieWithoutSecure.ql @@ -0,0 +1,105 @@ +/** + * @name 'Secure' attribute is not set to true + * @description Omitting the 'Secure' attribute allows data to be transmitted insecurely + * using HTTP. Always set 'Secure' to 'true' to ensure that HTTPS + * is used at all times. + * @kind problem + * @problem.severity error + * @precision high + * @id cs/web/cookie-secure-not-set + * @tags security + * experimental + * external/cwe/cwe-319 + * external/cwe/cwe-614 + */ + +import csharp +import semmle.code.asp.WebConfig +import semmle.code.csharp.frameworks.system.Web +import semmle.code.csharp.frameworks.microsoft.AspNetCore +import experimental.dataflow.flowsources.AuthCookie + +from Expr secureSink +where + exists(Call c | + secureSink = c and + ( + // default is not configured or is not set to `Always` or `SameAsRequest` + not ( + getAValueForCookiePolicyProp("Secure").getValue() = "0" or + getAValueForCookiePolicyProp("Secure").getValue() = "1" + ) and + // there is no callback `OnAppendCookie` that sets `Secure` to true + not OnAppendCookieSecureTracking::flowTo(_) and + ( + // `Secure` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set + exists(ObjectCreation oc | + oc = c and + oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and + not isPropertySet(oc, "Secure") and + exists(DataFlow::Node creation | + CookieOptionsTracking::flow(creation, _) and + creation.asExpr() = oc + ) + ) + or + // IResponseCookies.Append(String, String) was called, `Secure` is set to `false` by default + exists(MethodCall mc, MicrosoftAspNetCoreHttpResponseCookies iResponse | + mc = c and + iResponse.getAppendMethod() = mc.getTarget() and + mc.getNumberOfArguments() < 3 + ) + ) + or + exists(ObjectCreation oc | + oc = c and + oc.getType() instanceof SystemWebHttpCookie and + // the property wasn't explicitly set, so a default value from config is used + not isPropertySet(oc, "Secure") and + // the default in config is not set to `true` + // the `exists` below covers the `cs/web/requiressl-not-set` + not exists(XmlElement element | + element instanceof FormsElement and + element.(FormsElement).isRequireSsl() + or + element instanceof HttpCookiesElement and + element.(HttpCookiesElement).isRequireSsl() + ) + ) + ) + ) + or + exists(Assignment a, Expr val | + secureSink = a.getRValue() and + ( + exists(ObjectCreation oc | + getAValueForProp(oc, a, "Secure") = val and + val.getValue() = "false" and + ( + oc.getType() instanceof SystemWebHttpCookie + or + oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and + // there is no callback `OnAppendCookie` that sets `Secure` to true + not OnAppendCookieSecureTracking::flowTo(_) and + // the cookie option is passed to `Append` + exists(DataFlow::Node creation | + CookieOptionsTracking::flow(creation, _) and + creation.asExpr() = oc + ) + ) + ) + or + exists(PropertyWrite pw | + ( + pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieBuilder or + pw.getProperty().getDeclaringType() instanceof + MicrosoftAspNetCoreAuthenticationCookiesCookieAuthenticationOptions + ) and + pw.getProperty().getName() = "SecurePolicy" and + a.getLValue() = pw and + DataFlow::localExprFlow(val, a.getRValue()) and + val.getValue() = "2" // None + ) + ) + ) +select secureSink, "Cookie attribute 'Secure' is not set to true." diff --git a/csharp/src/security/CWE-614/Web.config b/csharp/src/security/CWE-614/Web.config new file mode 100644 index 00000000..89d4561c --- /dev/null +++ b/csharp/src/security/CWE-614/Web.config @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/csharp/src/security/CWE-614/cookiepolicyoptions.cs b/csharp/src/security/CWE-614/cookiepolicyoptions.cs new file mode 100644 index 00000000..a9adf0d9 --- /dev/null +++ b/csharp/src/security/CWE-614/cookiepolicyoptions.cs @@ -0,0 +1,12 @@ +public class Startup +{ + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCookiePolicy(new CookiePolicyOptions() + { + Secure = Microsoft.AspNetCore.Http.CookieSecurePolicy.Always, + HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.Always + }); + } +} \ No newline at end of file diff --git a/csharp/src/security/CWE-614/secureflag.cs b/csharp/src/security/CWE-614/secureflag.cs new file mode 100644 index 00000000..4542d863 --- /dev/null +++ b/csharp/src/security/CWE-614/secureflag.cs @@ -0,0 +1,7 @@ +class MyController : Controller +{ + void Login() + { + var cookie = new System.Web.HttpCookie("cookieName") { Secure = true }; + } +} \ No newline at end of file diff --git a/csharp/src/security/CWE-614/secureflagcore.cs b/csharp/src/security/CWE-614/secureflagcore.cs new file mode 100644 index 00000000..5d8163cd --- /dev/null +++ b/csharp/src/security/CWE-614/secureflagcore.cs @@ -0,0 +1,8 @@ +class MyController : Controller +{ + void Login() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { Secure = true }; + Response.Cookies.Append("auth", "secret", cookieOptions); + } +} \ No newline at end of file diff --git a/csharp/src/security/CWE-759/HashWithoutSalt.cs b/csharp/src/security/CWE-759/HashWithoutSalt.cs new file mode 100644 index 00000000..309d2e0d --- /dev/null +++ b/csharp/src/security/CWE-759/HashWithoutSalt.cs @@ -0,0 +1,65 @@ +public class Test +{ + private const int SaltSize = 32; + + // BAD - Hash without a salt. + public static String HashPassword(string password, string strAlgName ="SHA256") + { + IBuffer passBuff = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8); + HashAlgorithmProvider algProvider = HashAlgorithmProvider.OpenAlgorithm(strAlgName); + IBuffer hashBuff = algProvider.HashData(passBuff); + return CryptographicBuffer.EncodeToBase64String(hashBuff); + } + + // GOOD - Hash with a salt. + public static string HashPassword2(string password, string salt, string strAlgName ="SHA256") + { + // Concatenate the salt with the password. + IBuffer passBuff = CryptographicBuffer.ConvertStringToBinary(password+salt, BinaryStringEncoding.Utf8); + HashAlgorithmProvider algProvider = HashAlgorithmProvider.OpenAlgorithm(strAlgName); + IBuffer hashBuff = algProvider.HashData(passBuff); + return CryptographicBuffer.EncodeToBase64String(hashBuff); + } + + // BAD - Hash without a salt. + public static string HashPassword(string password) + { + SHA256 sha256Hash = SHA256.Create(); + byte[] passBytes = System.Text.Encoding.ASCII.GetBytes(password); + byte[] hashBytes = sha256Hash.ComputeHash(passBytes); + return Convert.ToBase64String(hashBytes); + } + + // GOOD - Hash with a salt. + public static string HashPassword2(string password) + { + byte[] passBytes = System.Text.Encoding.ASCII.GetBytes(password); + byte[] saltBytes = GenerateSalt(); + + // Add the salt to the hash. + byte[] rawSalted = new byte[passBytes.Length + saltBytes.Length]; + passBytes.CopyTo(rawSalted, 0); + saltBytes.CopyTo(rawSalted, passBytes.Length); + + //Create the salted hash. + SHA256 sha256 = SHA256.Create(); + byte[] saltedPassBytes = sha256.ComputeHash(rawSalted); + + // Add the salt value to the salted hash. + byte[] dbPassword = new byte[saltedPassBytes.Length + saltBytes.Length]; + saltedPassBytes.CopyTo(dbPassword, 0); + saltBytes.CopyTo(dbPassword, saltedPassBytes.Length); + + return Convert.ToBase64String(dbPassword); + } + + public static byte[] GenerateSalt() + { + using (var rng = new RNGCryptoServiceProvider()) + { + var randomNumber = new byte[SaltSize]; + rng.GetBytes(randomNumber); + return randomNumber; + } + } +} diff --git a/csharp/src/security/CWE-759/HashWithoutSalt.qhelp b/csharp/src/security/CWE-759/HashWithoutSalt.qhelp new file mode 100644 index 00000000..3e0583f9 --- /dev/null +++ b/csharp/src/security/CWE-759/HashWithoutSalt.qhelp @@ -0,0 +1,29 @@ + + + + +

    In cryptography, a salt is some random data used as an additional input to a one-way function that hashes a password or pass-phrase. It makes dictionary attacks more difficult.

    + +

    Without a salt, it is much easier for attackers to pre-compute the hash value using dictionary attack techniques such as rainbow tables to crack passwords.

    +
    + + +

    Use a long random salt of at least 32 bytes then use the combination of password and salt to hash a password or password phrase.

    +
    + + +

    The following example shows two ways of hashing. In the 'BAD' cases, no salt is provided. In the 'GOOD' cases, a salt is provided.

    + +
    + + +
  • + DZone: + A Look at Java Cryptography +
  • +
  • + CWE: + CWE-759: Use of a One-Way Hash without a Salt +
  • +
    +
    diff --git a/csharp/src/security/CWE-759/HashWithoutSalt.ql b/csharp/src/security/CWE-759/HashWithoutSalt.ql new file mode 100644 index 00000000..f9c279e0 --- /dev/null +++ b/csharp/src/security/CWE-759/HashWithoutSalt.ql @@ -0,0 +1,198 @@ +/** + * @name Use of a hash function without a salt + * @description Hashed passwords without a salt are vulnerable to dictionary attacks. + * @kind path-problem + * @problem.severity error + * @id cs/hash-without-salt + * @tags security + * experimental + * external/cwe/cwe-759 + */ + +import csharp +import HashWithoutSalt::PathGraph + +/** The C# class `Windows.Security.Cryptography.Core.HashAlgorithmProvider`. */ +class HashAlgorithmProvider extends RefType { + HashAlgorithmProvider() { + this.hasFullyQualifiedName("Windows.Security.Cryptography.Core", "HashAlgorithmProvider") + } +} + +/** The C# class `System.Security.Cryptography.HashAlgorithm`. */ +class HashAlgorithm extends RefType { + HashAlgorithm() { this.hasFullyQualifiedName("System.Security.Cryptography", "HashAlgorithm") } +} + +/** The C# class `System.Security.Cryptography.KeyedHashAlgorithm`. */ +class KeyedHashAlgorithm extends RefType { + KeyedHashAlgorithm() { + this.hasFullyQualifiedName("System.Security.Cryptography", "KeyedHashAlgorithm") + } +} + +/** + * The method `ComputeHash()`, `ComputeHashAsync`, `TryComputeHash`, `HashData`, or + * `TryHashData` declared in `System.Security.Cryptography.HashAlgorithm` and the method + * `HashData()` declared in `Windows.Security.Cryptography.Core.HashAlgorithmProvider`. + */ +class HashMethod extends Method { + HashMethod() { + this.getDeclaringType().getABaseType*() instanceof HashAlgorithm and + this.getName().matches(["%ComputeHash%", "%HashData"]) + or + this.getDeclaringType().getABaseType*() instanceof HashAlgorithmProvider and + this.hasName("HashData") + } +} + +/** + * Gets a regular expression for matching common names of variables that indicate the + * value being held is a password. + */ +string getPasswordRegex() { result = "(?i)pass(wd|word|code|phrase)" } + +/** Finds variables that hold password information judging by their names. */ +class PasswordVarExpr extends Expr { + PasswordVarExpr() { + exists(Variable v | this = v.getAnAccess() | v.getName().regexpMatch(getPasswordRegex())) + } +} + +/** + * Holds if `mc` is a hashing method call or invokes a hashing method call + * directly or indirectly. + */ +predicate isHashCall(MethodCall mc) { + mc.getTarget() instanceof HashMethod + or + exists(MethodCall mcc | + mc.getTarget().calls(mcc.getTarget()) and + isHashCall(mcc) and + DataFlow::localExprFlow(mc.getTarget().getAParameter().getAnAccess(), mcc.getAnArgument()) + ) +} + +/** Holds if there is another hashing method call. */ +predicate hasAnotherHashCall(MethodCall mc) { + exists(MethodCall mc2, DataFlow::Node src, DataFlow::Node sink | + isHashCall(mc2) and + mc2 != mc and + ( + src.asExpr() = mc.getQualifier() or + src.asExpr() = mc.getAnArgument() or + src.asExpr() = mc + ) and + ( + sink.asExpr() = mc2.getQualifier() or + sink.asExpr() = mc2.getAnArgument() + ) and + DataFlow::localFlow(src, sink) + ) +} + +/** Holds if a password hash without salt is further processed in another method call. */ +predicate hasFurtherProcessing(MethodCall mc) { + mc.getTarget().fromLibrary() and + ( + mc.getTarget().hasFullyQualifiedName("System", "Array", "Copy") or // Array.Copy(passwordHash, 0, password.Length), 0, key, 0, keyLen); + mc.getTarget().hasFullyQualifiedName("System", "String", "Concat") or // string.Concat(passwordHash, saltkey) + mc.getTarget().hasFullyQualifiedName("System", "Buffer", "BlockCopy") or // Buffer.BlockCopy(passwordHash, 0, allBytes, 0, 20) + mc.getTarget().hasFullyQualifiedName("System", "String", "Format") // String.Format("{0}:{1}:{2}", username, salt, password) + ) +} + +/** + * Holds if `mc` is part of a call graph that satisfies `isHashCall` but is not at the + * top of the call hierarchy. + */ +predicate hasHashAncestor(MethodCall mc) { + exists(MethodCall mpc | + mpc.getTarget().calls(mc.getTarget()) and + isHashCall(mpc) and + DataFlow::localExprFlow(mpc.getTarget().getAParameter().getAnAccess(), mc.getAnArgument()) + ) +} + +/** + * Taint configuration tracking flow from an expression whose name suggests it holds + * password data to a method call that generates a hash without a salt. + */ +module HashWithoutSaltConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr } + + predicate isSink(DataFlow::Node sink) { + exists(MethodCall mc | + sink.asExpr() = mc.getArgument(0) and + isHashCall(mc) and + not hasAnotherHashCall(mc) and + not hasHashAncestor(mc) and + not exists(MethodCall mmc | + hasFurtherProcessing(mmc) and + DataFlow::localExprFlow(mc, mmc.getAnArgument()) + ) and + not exists(Call c | + ( + c.getTarget().getDeclaringType().getABaseType*() instanceof HashAlgorithm or + c.getTarget() + .getDeclaringType() + .getABaseType*() + .hasFullyQualifiedName("System.Security.Cryptography", "DeriveBytes") + ) and + DataFlow::localExprFlow(mc, c.getAnArgument()) + ) + ) + } + + predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodCall mc | + mc.getTarget() + .hasFullyQualifiedName("Windows.Security.Cryptography", "CryptographicBuffer", + "ConvertStringToBinary") and + mc.getArgument(0) = node1.asExpr() and + mc = node2.asExpr() + ) + } + + /** + * Holds if a password is concatenated with a salt then hashed together through calls such as `System.Array.CopyTo()`, for example, + * `byte[] rawSalted = new byte[passBytes.Length + salt.Length];` + * `passBytes.CopyTo(rawSalted, 0);` + * `salt.CopyTo(rawSalted, passBytes.Length);` + * `byte[] saltedPassword = sha256.ComputeHash(rawSalted);` + * Or the password is concatenated with a salt as a string. + */ + predicate isBarrier(DataFlow::Node node) { + exists(MethodCall mc | + hasFurtherProcessing(mc) and + mc.getAnArgument() = node.asExpr() + ) + or + exists(AddExpr e | node.asExpr() = e.getAnOperand()) // password+salt + or + exists(InterpolatedStringExpr e | node.asExpr() = e.getAnInsert()) + or + exists(Call c | + c.getTarget() + .getDeclaringType() + .getABaseType*() + .hasFullyQualifiedName("System.Security.Cryptography", "DeriveBytes") + ) + or + // a salt or key is included in subclasses of `KeyedHashAlgorithm` + exists(MethodCall mc, Assignment a, ObjectCreation oc | + a.getRValue() = oc and + oc.getObjectType().getABaseType+() instanceof KeyedHashAlgorithm and + mc.getTarget() instanceof HashMethod and + a.getLValue() = mc.getQualifier().(VariableAccess).getTarget().getAnAccess() and + mc.getArgument(0) = node.asExpr() + ) + } +} + +module HashWithoutSalt = TaintTracking::Global; + +from HashWithoutSalt::PathNode source, HashWithoutSalt::PathNode sink +where HashWithoutSalt::flowPath(source, sink) +select sink.getNode(), source, sink, "$@ is hashed without a salt.", source.getNode(), + "The password" diff --git a/csharp/src/security/CWE-918/RequestForgery.cs b/csharp/src/security/CWE-918/RequestForgery.cs new file mode 100644 index 00000000..d9b83eee --- /dev/null +++ b/csharp/src/security/CWE-918/RequestForgery.cs @@ -0,0 +1,33 @@ +namespace RequestForgery.Controllers +{ + public class SSRFController : Controller + { + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Bad(string url) + { + var request = new HttpRequestMessage(HttpMethod.Get, url); + + var client = new HttpClient(); + await client.SendAsync(request); + + return View(); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Good(string url) + { + string baseUrl = "www.mysecuresite.com/"; + if (url.StartsWith(baseUrl)) + { + var request = new HttpRequestMessage(HttpMethod.Get, url); + var client = new HttpClient(); + await client.SendAsync(request); + + } + + return View(); + } + } +} \ No newline at end of file diff --git a/csharp/src/security/CWE-918/RequestForgery.qhelp b/csharp/src/security/CWE-918/RequestForgery.qhelp new file mode 100644 index 00000000..fb04540e --- /dev/null +++ b/csharp/src/security/CWE-918/RequestForgery.qhelp @@ -0,0 +1,35 @@ + + + + + +

    Directly incorporating user input into a HTTP request without validating the input +can facilitate Server Side Request Forgery (SSRF) attacks. In these attacks, the server +may be tricked into making a request and interacting with an attacker-controlled server. +

    + +
    + + +

    To guard against SSRF attacks, it is advisable to avoid putting user input +directly into the request URL. Instead, maintain a list of authorized +URLs on the server; then choose from that list based on the user input provided.

    + +
    + + +

    The following example shows an HTTP request parameter being used directly in a forming a +new request without validating the input, which facilitates SSRF attacks. +It also shows how to remedy the problem by validating the user input against a known fixed string. +

    + + + +
    + +
  • + OWASP SSRF +
  • + +
    +
    diff --git a/csharp/src/security/CWE-918/RequestForgery.ql b/csharp/src/security/CWE-918/RequestForgery.ql new file mode 100644 index 00000000..9f59da7e --- /dev/null +++ b/csharp/src/security/CWE-918/RequestForgery.ql @@ -0,0 +1,20 @@ +/** + * @name Server-side request forgery + * @description Making a network request with user-controlled data in the URL allows for request forgery attacks. + * @kind path-problem + * @problem.severity error + * @precision high + * @id cs/request-forgery + * @tags security + * experimental + * external/cwe/cwe-918 + */ + +import csharp +import RequestForgery::RequestForgery +import RequestForgeryFlow::PathGraph + +from RequestForgeryFlow::PathNode source, RequestForgeryFlow::PathNode sink +where RequestForgeryFlow::flowPath(source, sink) +select sink.getNode(), source, sink, "The URL of this request depends on a $@.", source.getNode(), + "user-provided value" diff --git a/csharp/src/security/CWE-918/RequestForgery.qll b/csharp/src/security/CWE-918/RequestForgery.qll new file mode 100644 index 00000000..6d06ca5f --- /dev/null +++ b/csharp/src/security/CWE-918/RequestForgery.qll @@ -0,0 +1,238 @@ +import csharp + +module RequestForgery { + import semmle.code.csharp.controlflow.Guards + import semmle.code.csharp.frameworks.System + import semmle.code.csharp.frameworks.system.Web + import semmle.code.csharp.frameworks.Format + import semmle.code.csharp.security.dataflow.flowsources.FlowSources + + /** + * A data flow source for server side request forgery vulnerabilities. + */ + abstract private class Source extends DataFlow::Node { } + + /** + * A data flow sink for server side request forgery vulnerabilities. + */ + abstract private class Sink extends DataFlow::ExprNode { } + + /** + * A data flow Barrier that blocks the flow of taint for + * server side request forgery vulnerabilities. + */ + abstract private class Barrier extends DataFlow::Node { } + + /** + * A data flow configuration for detecting server side request forgery vulnerabilities. + */ + private module RequestForgeryFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isAdditionalFlowStep(DataFlow::Node prev, DataFlow::Node succ) { + interpolatedStringFlowStep(prev, succ) + or + stringReplaceStep(prev, succ) + or + uriCreationStep(prev, succ) + or + formatConvertStep(prev, succ) + or + toStringStep(prev, succ) + or + stringConcatStep(prev, succ) + or + stringFormatStep(prev, succ) + or + pathCombineStep(prev, succ) + } + + predicate isBarrier(DataFlow::Node node) { node instanceof Barrier } + } + + /** + * A data flow module for detecting server side request forgery vulnerabilities. + */ + module RequestForgeryFlow = DataFlow::Global; + + /** + * A dataflow source for Server Side Request Forgery(SSRF) Vulnerabilities. + */ + private class ThreatModelSource extends Source instanceof ActiveThreatModelSource { } + + /** + * An url argument to a `HttpRequestMessage` constructor call + * taken as a sink for Server Side Request Forgery(SSRF) Vulnerabilities. + */ + private class SystemWebHttpRequestMessageSink extends Sink { + SystemWebHttpRequestMessageSink() { + exists(Class c | c.hasFullyQualifiedName("System.Net.Http", "HttpRequestMessage") | + c.getAConstructor().getACall().getArgument(1) = this.asExpr() + ) + } + } + + /** + * An argument to a `WebRequest.Create` call taken as a + * sink for Server Side Request Forgery(SSRF) Vulnerabilities. * + */ + private class SystemNetWebRequestCreateSink extends Sink { + SystemNetWebRequestCreateSink() { + exists(Method m | + m.getDeclaringType().hasFullyQualifiedName("System.Net", "WebRequest") and + m.hasName("Create") + | + m.getACall().getArgument(0) = this.asExpr() + ) + } + } + + /** + * An argument to a new HTTP Request call of a `System.Net.Http.HttpClient` object + * taken as a sink for Server Side Request Forgery(SSRF) Vulnerabilities. + */ + private class SystemNetHttpClientSink extends Sink { + SystemNetHttpClientSink() { + exists(Method m | + m.getDeclaringType().hasFullyQualifiedName("System.Net.Http", "HttpClient") and + m.hasName([ + "DeleteAsync", "GetAsync", "GetByteArrayAsync", "GetStreamAsync", "GetStringAsync", + "PatchAsync", "PostAsync", "PutAsync" + ]) + | + m.getACall().getArgument(0) = this.asExpr() + ) + } + } + + /** + * An url argument to a method call of a `System.Net.WebClient` object + * taken as a sink for Server Side Request Forgery(SSRF) Vulnerabilities. + */ + private class SystemNetClientBaseAddressSink extends Sink { + SystemNetClientBaseAddressSink() { + exists(Property p, Type t | + p.hasName("BaseAddress") and + t = p.getDeclaringType() and + ( + t.hasFullyQualifiedName("System.Net", "WebClient") or + t.hasFullyQualifiedName("System.Net.Http", "HttpClient") + ) + | + p.getAnAssignedValue() = this.asExpr() + ) + } + } + + /** + * A method call which checks the base of the tainted uri is assumed + * to be a guard for Server Side Request Forgery(SSRF) Vulnerabilities. + * This guard considers all checks as valid. + */ + private predicate baseUriGuard(Guard g, Expr e, AbstractValue v) { + g.(MethodCall).getTarget().hasFullyQualifiedName("System", "Uri", "IsBaseOf") and + // we consider any checks against the tainted value to sainitize the taint. + // This implies any check such as shown below block the taint flow. + // Uri url = new Uri("whitelist.com") + // if (url.isBaseOf(`taint1)) + (e = g.(MethodCall).getArgument(0) or e = g.(MethodCall).getQualifier()) and + v.(AbstractValues::BooleanValue).getValue() = true + } + + private class BaseUriBarrier extends Barrier { + BaseUriBarrier() { this = DataFlow::BarrierGuard::getABarrierNode() } + } + + /** + * A method call which checks if the Uri starts with a white-listed string is assumed + * to be a guard for Server Side Request Forgery(SSRF) Vulnerabilities. + * This guard considers all checks as valid. + */ + private predicate stringStartsWithGuard(Guard g, Expr e, AbstractValue v) { + g.(MethodCall).getTarget().hasFullyQualifiedName("System", "String", "StartsWith") and + // Any check such as the ones shown below + // "https://myurl.com/".startsWith(`taint`) + // `taint`.startsWith("https://myurl.com/") + // are assumed to sainitize the taint + (e = g.(MethodCall).getQualifier() or g.(MethodCall).getArgument(0) = e) and + v.(AbstractValues::BooleanValue).getValue() = true + } + + private class StringStartsWithBarrier extends Barrier { + StringStartsWithBarrier() { + this = DataFlow::BarrierGuard::getABarrierNode() + } + } + + private predicate stringFormatStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(FormatCall c | c.getArgument(0) = prev.asExpr() and c = succ.asExpr()) + } + + private predicate pathCombineStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(MethodCall combineCall | + combineCall.getTarget().hasFullyQualifiedName("System.IO", "Path", "Combine") and + combineCall.getArgument(0) = prev.asExpr() and + combineCall = succ.asExpr() + ) + } + + private predicate uriCreationStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(ObjectCreation oc | + oc.getTarget().getDeclaringType().hasFullyQualifiedName("System", "Uri") and + oc.getArgument(0) = prev.asExpr() and + oc = succ.asExpr() + ) + } + + private predicate interpolatedStringFlowStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(InterpolatedStringExpr i | + // allow `$"http://{`taint`}/blabla/");"` or + // allow `$"https://{`taint`}/blabla/");"` + i.getText(0).getValue().matches(["http://", "http://"]) and + i.getInsert(1) = prev.asExpr() and + succ.asExpr() = i + or + // allow `$"{`taint`}/blabla/");"` + i.getInsert(0) = prev.asExpr() and + succ.asExpr() = i + ) + } + + private predicate stringReplaceStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(MethodCall mc, SystemStringClass s | + mc = s.getReplaceMethod().getACall() and + mc.getQualifier() = prev.asExpr() and + succ.asExpr() = mc + ) + } + + private predicate stringConcatStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(AddExpr a | + a.getLeftOperand() = prev.asExpr() + or + a.getRightOperand() = prev.asExpr() and + a.getLeftOperand().(StringLiteral).getValue() = ["http://", "https://"] + | + a = succ.asExpr() + ) + } + + private predicate formatConvertStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(Method m | + m.hasFullyQualifiedName("System", "Convert", + ["FromBase64String", "FromHexString", "FromBase64CharArray"]) and + m.getParameter(0) = prev.asParameter() and + succ.asExpr() = m.getACall() + ) + } + + private predicate toStringStep(DataFlow::Node prev, DataFlow::Node succ) { + exists(MethodCall ma | + ma.getTarget().hasName("ToString") and + ma.getQualifier() = prev.asExpr() and + succ.asExpr() = ma + ) + } +} diff --git a/csharp/src/security/JsonWebTokenHandler/JsonWebTokenHandlerLib.qll b/csharp/src/security/JsonWebTokenHandler/JsonWebTokenHandlerLib.qll new file mode 100644 index 00000000..476b17e4 --- /dev/null +++ b/csharp/src/security/JsonWebTokenHandler/JsonWebTokenHandlerLib.qll @@ -0,0 +1,207 @@ +import csharp +import DataFlow + +/** + * A sensitive property for `TokenValidationParameters` that updates the underlying value. + */ +class TokenValidationParametersPropertySensitiveValidation extends Property { + TokenValidationParametersPropertySensitiveValidation() { + exists(Class c | + c.hasFullyQualifiedName("Microsoft.IdentityModel.Tokens", "TokenValidationParameters") + | + c.getAProperty() = this and + this.getName() in [ + "ValidateIssuer", "ValidateAudience", "ValidateLifetime", "RequireExpirationTime", + "RequireAudience" + ] + ) + } +} + +/** + * A dataflow configuration from a `false` value to a write sensitive property for `TokenValidationParameters`. + */ +private module FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidationConfig + implements DataFlow::ConfigSig +{ + predicate isSource(DataFlow::Node source) { + source.asExpr().getValue() = "false" and + source.asExpr().getType() instanceof BoolType + } + + predicate isSink(DataFlow::Node sink) { + sink.asExpr() = any(TokenValidationParametersPropertySensitiveValidation p).getAnAssignedValue() + } +} + +module FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation = + DataFlow::Global; + +/** + * Holds if `assemblyName` is older than version `ver` + */ +bindingset[ver] +predicate isAssemblyOlderVersion(string assemblyName, string ver) { + exists(Assembly a | + a.getName() = assemblyName and + a.getVersion().isEarlierThan(ver) + ) +} + +/** + * A method `ValidateToken` for `Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler` or other Token handler that shares the same behavior characteristics + */ +class JsonWebTokenHandlerValidateTokenMethod extends Method { + JsonWebTokenHandlerValidateTokenMethod() { + this.hasFullyQualifiedName("Microsoft.IdentityModel.JsonWebTokens", "JsonWebTokenHandler", + "ValidateToken") or + this.hasFullyQualifiedName("Microsoft.AzureAD.DeviceIdentification.Common.Tokens", + "JwtValidator", "ValidateEncryptedToken") + } +} + +/** + * A Call to `Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateToken` + */ +class JsonWebTokenHandlerValidateTokenCall extends MethodCall { + JsonWebTokenHandlerValidateTokenCall() { + this.getTarget() instanceof JsonWebTokenHandlerValidateTokenMethod + } +} + +/** + * A read access for properties `IsValid` or `Exception` for `Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateToken` + */ +private class TokenValidationResultIsValidCall extends PropertyRead { + TokenValidationResultIsValidCall() { + exists(Property p | p.getAnAccess() = this | + p.hasName("IsValid") or + p.hasName("Exception") + ) + } +} + +/** + * A security-sensitive property for `Microsoft.IdentityModel.Tokens.TokenValidationParameters` + */ +class TokenValidationParametersProperty extends Property { + TokenValidationParametersProperty() { + exists(Class c | + c.hasFullyQualifiedName("Microsoft.IdentityModel.Tokens", "TokenValidationParameters") + | + c.getAProperty() = this and + this.getName() in [ + "SignatureValidator", "TokenReplayValidator", "AlgorithmValidator", "AudienceValidator", + "IssuerSigningKeyValidator", "LifetimeValidator" + ] + ) + } +} + +/** + * Holds if the callable has a return statement and it always returns true for all such statements + */ +predicate callableHasAReturnStmtAndAlwaysReturnsTrue(Callable c) { + c.getReturnType() instanceof BoolType and + not callableMayThrowException(c) and + forex(ReturnStmt rs | rs.getEnclosingCallable() = c | + rs.getNumberOfChildren() = 1 and + isExpressionAlwaysTrue(rs.getChildExpr(0)) + ) +} + +/** + * Holds if the lambda expression `le` always returns true + */ +predicate lambdaExprReturnsOnlyLiteralTrue(AnonymousFunctionExpr le) { + isExpressionAlwaysTrue(le.getExpressionBody()) +} + +class CallableAlwaysReturnsTrue extends Callable { + CallableAlwaysReturnsTrue() { + callableHasAReturnStmtAndAlwaysReturnsTrue(this) + or + lambdaExprReturnsOnlyLiteralTrue(this) + } +} + +/** + * Holds if any exception being thrown by the callable is of type `System.ArgumentNullException` + * It will also hold if no exceptions are thrown by the callable + */ +predicate callableOnlyThrowsArgumentNullException(Callable c) { + forall(ThrowElement thre | c = thre.getEnclosingCallable() | + thre.getThrownExceptionType().hasFullyQualifiedName("System", "ArgumentNullException") + ) +} + +/** + * A callable that returns a `string` and has a `string` as 1st argument + */ +private class CallableReturnsStringAndArg0IsString extends Callable { + CallableReturnsStringAndArg0IsString() { + this.getReturnType() instanceof StringType and + this.getParameter(0).getType() instanceof StringType + } +} + +/** + * A Callable that always return the 1st argument, both of `string` type + */ +class CallableAlwaysReturnsParameter0 extends CallableReturnsStringAndArg0IsString { + CallableAlwaysReturnsParameter0() { + forex(Expr ret | this.canReturn(ret) | + ret = this.getParameter(0).getAnAccess() + or + exists(CallableAlwaysReturnsParameter0 c | + ret = c.getACall() and + ret.(Call).getArgument(0) = this.getParameter(0).getAnAccess() + ) + ) + } +} + +/** + * A Callable that always return the 1st argument, both of `string` type. Higher precision + */ +class CallableAlwaysReturnsParameter0MayThrowExceptions extends CallableReturnsStringAndArg0IsString +{ + CallableAlwaysReturnsParameter0MayThrowExceptions() { + forex(Expr ret | this.canReturn(ret) | + ret = this.getParameter(0).getAnAccess() + or + exists(CallableAlwaysReturnsParameter0MayThrowExceptions c | + ret = c.getACall() and + ret.(Call).getArgument(0) = this.getParameter(0).getAnAccess() + ) + ) + } +} + +/** + * Hold if the `Expr` e is a `BoolLiteral` with value true, + * the expression has a predictable value == `true`, + * or if it is a `ConditionalExpr` where the `then` and `else` expressions meet `isExpressionAlwaysTrue` criteria + */ +predicate isExpressionAlwaysTrue(Expr e) { + e.(BoolLiteral).getBoolValue() = true + or + e.getValue() = "true" + or + e instanceof ConditionalExpr and + isExpressionAlwaysTrue(e.(ConditionalExpr).getThen()) and + isExpressionAlwaysTrue(e.(ConditionalExpr).getElse()) + or + exists(Callable callable | + callableHasAReturnStmtAndAlwaysReturnsTrue(callable) and + callable.getACall() = e + ) +} + +/** + * Holds if the `Callable` c throws any exception other than `ThrowsArgumentNullException` + */ +predicate callableMayThrowException(Callable c) { + exists(ThrowStmt thre | c = thre.getEnclosingCallable()) and + not callableOnlyThrowsArgumentNullException(c) +} diff --git a/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true-bad.cs b/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true-bad.cs new file mode 100644 index 00000000..2eda6821 --- /dev/null +++ b/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true-bad.cs @@ -0,0 +1,10 @@ +using System; +using Microsoft.IdentityModel.Tokens; +class TestClass +{ + public void TestMethod() + { + TokenValidationParameters parameters = new TokenValidationParameters(); + parameters.AudienceValidator = (audiences, token, tvp) => { return true; }; + } +} \ No newline at end of file diff --git a/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true-good.cs b/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true-good.cs new file mode 100644 index 00000000..28ba1d6f --- /dev/null +++ b/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true-good.cs @@ -0,0 +1,17 @@ +using System; +using Microsoft.IdentityModel.Tokens; +class TestClass +{ + public void TestMethod() + { + TokenValidationParameters parameters = new TokenValidationParameters(); + parameters.AudienceValidator = (audiences, token, tvp) => + { + // Implement your own custom audience validation + if (PerformCustomAudienceValidation(audiences, token)) + return true; + else + return false; + }; + } +} \ No newline at end of file diff --git a/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qhelp b/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qhelp new file mode 100644 index 00000000..8c4f8dff --- /dev/null +++ b/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qhelp @@ -0,0 +1,28 @@ + + + +

    By setting critical TokenValidationParameter validation delegates to always return true, important authentication safeguards are disabled. Disabling safeguards can lead to incorrect validation of tokens from any issuer or expired tokens.

    + +
    + +

    Improve the logic of the delegate so not all code paths return true, which effectively disables that type of validation; or throw SecurityTokenInvalidAudienceException or SecurityTokenInvalidLifetimeException in failure cases when you want to fail validation and have other cases pass by returning true. +

    +
    + + +

    This example delegates AudienceValidator to a callable that always returns true.

    + + +

    To fix it, use a callable that performs a validation, and fails when appropriate.

    + + +
    + + + +
  • azure-activedirectory-identitymodel-extensions-for-dotnet ValidatingTokens wiki
  • + +
    +
    \ No newline at end of file diff --git a/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql b/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql new file mode 100644 index 00000000..39aaa809 --- /dev/null +++ b/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql @@ -0,0 +1,24 @@ +/** + * @name Delegated security sensitive validations for JsonWebTokenHandler always return true, medium precision + * @description Security sensitive validations for `JsonWebTokenHandler` are being delegated to a function that seems to always return true. + * Higher precision version checks for exception throws, so less false positives are expected. + * @kind problem + * @tags security + * experimental + * JsonWebTokenHandler + * manual-verification-required + * @id cs/json-webtoken-handler/delegated-security-validations-always-return-true + * @problem.severity error + * @precision high + */ + +import csharp +import DataFlow +import JsonWebTokenHandlerLib +import semmle.code.csharp.commons.QualifiedName + +from TokenValidationParametersProperty p, CallableAlwaysReturnsTrue e, string qualifier, string name +where e = p.getAnAssignedValue() and p.hasFullyQualifiedName(qualifier, name) +select e, + "JsonWebTokenHandler security-sensitive property $@ is being delegated to this callable that always returns \"true\".", + p, getQualifiedName(qualifier, name) diff --git a/csharp/src/security/JsonWebTokenHandler/security-validation-disabled-bad.cs b/csharp/src/security/JsonWebTokenHandler/security-validation-disabled-bad.cs new file mode 100644 index 00000000..81df44fe --- /dev/null +++ b/csharp/src/security/JsonWebTokenHandler/security-validation-disabled-bad.cs @@ -0,0 +1,13 @@ +using System; +using Microsoft.IdentityModel.Tokens; +class TestClass +{ + public void TestMethod() + { + TokenValidationParameters parameters = new TokenValidationParameters(); + parameters.RequireExpirationTime = false; + parameters.ValidateAudience = false; + parameters.ValidateIssuer = false; + parameters.ValidateLifetime = false; + } +} \ No newline at end of file diff --git a/csharp/src/security/JsonWebTokenHandler/security-validation-disabled-good.cs b/csharp/src/security/JsonWebTokenHandler/security-validation-disabled-good.cs new file mode 100644 index 00000000..e2f74c06 --- /dev/null +++ b/csharp/src/security/JsonWebTokenHandler/security-validation-disabled-good.cs @@ -0,0 +1,13 @@ +using System; +using Microsoft.IdentityModel.Tokens; +class TestClass +{ + public void TestMethod() + { + TokenValidationParameters parameters = new TokenValidationParameters(); + parameters.RequireExpirationTime = true; + parameters.ValidateAudience = true; + parameters.ValidateIssuer = true; + parameters.ValidateLifetime = true; + } +} \ No newline at end of file diff --git a/csharp/src/security/JsonWebTokenHandler/security-validation-disabled.qhelp b/csharp/src/security/JsonWebTokenHandler/security-validation-disabled.qhelp new file mode 100644 index 00000000..5c027ac3 --- /dev/null +++ b/csharp/src/security/JsonWebTokenHandler/security-validation-disabled.qhelp @@ -0,0 +1,27 @@ + + + +

    Token validation checks ensure that while validating tokens, all aspects are analyzed and verified. Turning off validation can lead to security holes by allowing untrusted tokens to make it through validation.

    + +
    + +

    Set Microsoft.IdentityModel.Tokens.TokenValidationParameters properties RequireExpirationTime, ValidateAudience, ValidateIssuer, or ValidateLifetime to true. Or, remove the assignment to false because the default value is true.

    +
    + + +

    This example disabled the validation.

    + + +

    To fix it, do not disable the validations or use the default value.

    + + +
    + + + +
  • azure-activedirectory-identitymodel-extensions-for-dotnet ValidatingTokens wiki
  • + +
    +
    \ No newline at end of file diff --git a/csharp/src/security/JsonWebTokenHandler/security-validation-disabled.ql b/csharp/src/security/JsonWebTokenHandler/security-validation-disabled.ql new file mode 100644 index 00000000..679e6c3b --- /dev/null +++ b/csharp/src/security/JsonWebTokenHandler/security-validation-disabled.ql @@ -0,0 +1,26 @@ +/** + * @name Security sensitive JsonWebTokenHandler validations are disabled + * @description Check if security sensitive token validations for `JsonWebTokenHandler` are being disabled. + * @kind problem + * @tags security + * experimental + * JsonWebTokenHandler + * manual-verification-required + * @id cs/json-webtoken-handler/security-validations-disabled + * @problem.severity error + * @precision high + */ + +import csharp +import JsonWebTokenHandlerLib +import semmle.code.csharp.commons.QualifiedName + +from + DataFlow::Node source, DataFlow::Node sink, + TokenValidationParametersPropertySensitiveValidation pw, string qualifier, string name +where + FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation::flow(source, sink) and + sink.asExpr() = pw.getAnAssignedValue() and + pw.hasFullyQualifiedName(qualifier, name) +select sink, "The security sensitive property $@ is being disabled by the following value: $@.", pw, + getQualifiedName(qualifier, name), source, "false" diff --git a/csharp/src/security/Serialization/DataSetSerialization.inc.qhelp b/csharp/src/security/Serialization/DataSetSerialization.inc.qhelp new file mode 100644 index 00000000..7575352f --- /dev/null +++ b/csharp/src/security/Serialization/DataSetSerialization.inc.qhelp @@ -0,0 +1,23 @@ + + + +

    The DataSet and DataTable types are legacy .NET components that you can use to represent data sets as managed objects.

    + +

    While DataSet and DataTable do impose default limitations on the types that are allowed to be present while deserializing XML payloads, DataSet and DataTable are in general not safe when populated with untrusted input.

    + +

    Please visit DataSet and DataTable security guidance for more details.

    + +
    + + +

    Please review the DataSet and DataTable security guidance before making use of these types for serialization.

    + +
    + + +
  • Microsoft DocsDataSet and DataTable security guidance.
  • + +
    +
    diff --git a/csharp/src/security/Serialization/DataSetSerialization.qll b/csharp/src/security/Serialization/DataSetSerialization.qll new file mode 100644 index 00000000..ca508617 --- /dev/null +++ b/csharp/src/security/Serialization/DataSetSerialization.qll @@ -0,0 +1,94 @@ +/** + * Provides classes for `DataSet` or `DataTable` deserialization queries. + * + * Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. + */ + +import csharp + +/** + * Abstract class that depends or inherits from `DataSet` or `DataTable` types. + */ +abstract class DataSetOrTableRelatedClass extends Class { } + +/** + * `DataSet`, `DataTable` types, or any types derived from them. + */ +class DataSetOrTable extends DataSetOrTableRelatedClass { + DataSetOrTable() { + this.getABaseType*().hasFullyQualifiedName("System.Data", "DataTable") or + this.getABaseType*().hasFullyQualifiedName("System.Data", "DataSet") + } +} + +/** + * A Class that include a property or generic collection of type `DataSet` and `DataTable` + */ +class ClassWithDataSetOrTableMember extends DataSetOrTableRelatedClass { + ClassWithDataSetOrTableMember() { + this.getAMember().(AssignableMember).getType() instanceof DataSetOrTable + or + exists(Property p | p = this.getAProperty() | + p.getType() instanceof DataSetOrTable or + p.getType().(ConstructedGeneric).getATypeArgument() instanceof DataSetOrTable + ) + } +} + +/** + * Serializable types + */ +class SerializableClass extends Class { + SerializableClass() { + ( + this.getABaseType*() + .hasFullyQualifiedName("System.Xml.Serialization", ["XmlSerializer", "IXmlSerializable"]) or + this.getABaseType*() + .hasFullyQualifiedName("System.Runtime.Serialization", + [ + "ISerializable", "XmlObjectSerializer", "ISerializationSurrogateProvider", + "XmlSerializableServices" + ]) + ) + or + exists(Attribute a | a = this.getAnAttribute() | + a.getType().hasFullyQualifiedName("System", "SerializableAttribute") + ) + } +} + +/** + * Holds if the serializable class `c` has a property or field `m` that is of `DataSet` or `DataTable` related type + */ +predicate isClassUnsafeXmlSerializerImplementation(SerializableClass c, AssignableMember am) { + am = c.getAMember() and + am.getType() instanceof DataSetOrTableRelatedClass +} + +/** + * Serializable class that has a property or field that is of `DataSet` or `DataTable` related type + */ +class UnsafeXmlSerializerImplementation extends SerializableClass { + UnsafeXmlSerializerImplementation() { isClassUnsafeXmlSerializerImplementation(this, _) } +} + +/** + * Method that may be unsafe when used to deserialize DataSet and DataTable related types + */ +class UnsafeXmlReadMethod extends Method { + UnsafeXmlReadMethod() { + this.hasFullyQualifiedName("System.Data", ["DataTable", "DataSet"], ["ReadXml", "ReadXmlSchema"]) + or + this.getName().matches("ReadXml%") and + exists(Class c | c.getAMethod() = this | + c.getABaseType*() instanceof DataSetOrTableRelatedClass + ) + } +} + +/** + * MethodCall that may be unsafe when used to deserialize DataSet and DataTable related types + */ +class UnsafeXmlReadMethodCall extends MethodCall { + UnsafeXmlReadMethodCall() { exists(UnsafeXmlReadMethod uxrm | uxrm.getACall() = this) } +} diff --git a/csharp/src/security/Serialization/DefiningDatasetRelatedType.qhelp b/csharp/src/security/Serialization/DefiningDatasetRelatedType.qhelp new file mode 100644 index 00000000..bbc0a82f --- /dev/null +++ b/csharp/src/security/Serialization/DefiningDatasetRelatedType.qhelp @@ -0,0 +1,5 @@ + + + diff --git a/csharp/src/security/Serialization/DefiningDatasetRelatedType.ql b/csharp/src/security/Serialization/DefiningDatasetRelatedType.ql new file mode 100644 index 00000000..47153f92 --- /dev/null +++ b/csharp/src/security/Serialization/DefiningDatasetRelatedType.ql @@ -0,0 +1,17 @@ +/** + * @name Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types + * @description Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types may lead to the usage of dangerous functionality. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. + * @kind problem + * @problem.severity warning + * @id cs/dataset-serialization/defining-dataset-related-type + * @tags security + * experimental + */ + +import csharp +import DataSetSerialization + +from DataSetOrTableRelatedClass dstc +where dstc.fromSource() +select dstc, + "Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details." diff --git a/csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qhelp b/csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qhelp new file mode 100644 index 00000000..bbc0a82f --- /dev/null +++ b/csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qhelp @@ -0,0 +1,5 @@ + + + diff --git a/csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql b/csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql new file mode 100644 index 00000000..0e87f724 --- /dev/null +++ b/csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql @@ -0,0 +1,21 @@ +/** + * @name Defining a potentially unsafe XML serializer + * @description Defining an XML serializable class that includes members that derive from DataSet or DataTable type may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. + * @kind problem + * @problem.severity error + * @precision medium + * @id cs/dataset-serialization/defining-potentially-unsafe-xml-serializer + * @tags security + * experimental + */ + +import csharp +import DataSetSerialization + +from UnsafeXmlSerializerImplementation c, Member m +where + c.fromSource() and + isClassUnsafeXmlSerializerImplementation(c, m) +select m, + "Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.", + c, c.toString(), m, m.toString() diff --git a/csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.qhelp b/csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.qhelp new file mode 100644 index 00000000..bbc0a82f --- /dev/null +++ b/csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.qhelp @@ -0,0 +1,5 @@ + + + diff --git a/csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.ql b/csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.ql new file mode 100644 index 00000000..74eea145 --- /dev/null +++ b/csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.ql @@ -0,0 +1,46 @@ +/** + * @name Unsafe type is used in data contract serializer + * @description Unsafe type is used in data contract serializer. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details." + * @kind problem + * @problem.severity error + * @precision medium + * @id cs/dataset-serialization/unsafe-type-used-data-contract-serializer + * @tags security + * experimental + */ + +import csharp +import DataSetSerialization + +predicate xmlSerializerConstructorArgument(Expr e) { + exists(ObjectCreation oc, Constructor c | e = oc.getArgument(0) | + c = oc.getTarget() and + c.getDeclaringType() + .getABaseType*() + .hasFullyQualifiedName("System.Xml.Serialization", "XmlSerializer") + ) +} + +predicate unsafeDataContractTypeCreation(Expr e) { + exists(MethodCall gt | + gt.getTarget().getName() = "GetType" and + e = gt and + gt.getQualifier().getType() instanceof DataSetOrTableRelatedClass + ) + or + e.(TypeofExpr).getTypeAccess().getTarget() instanceof DataSetOrTableRelatedClass +} + +module FlowToDataSerializerConstructorConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) } + + predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) } +} + +module FlowToDataSerializerConstructor = DataFlow::Global; + +from DataFlow::Node source, DataFlow::Node sink +where FlowToDataSerializerConstructor::flow(source, sink) +select sink, + "Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source.", + source, source.toString() diff --git a/csharp/src/security/Serialization/XmlDeserializationWithDataSet.qhelp b/csharp/src/security/Serialization/XmlDeserializationWithDataSet.qhelp new file mode 100644 index 00000000..bbc0a82f --- /dev/null +++ b/csharp/src/security/Serialization/XmlDeserializationWithDataSet.qhelp @@ -0,0 +1,5 @@ + + + diff --git a/csharp/src/security/Serialization/XmlDeserializationWithDataSet.ql b/csharp/src/security/Serialization/XmlDeserializationWithDataSet.ql new file mode 100644 index 00000000..fbcba87b --- /dev/null +++ b/csharp/src/security/Serialization/XmlDeserializationWithDataSet.ql @@ -0,0 +1,17 @@ +/** + * @name XML deserialization with a type type derived from DataSet or DataTable + * @description Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details." + * @kind problem + * @problem.severity error + * @precision medium + * @id cs/dataset-serialization/xml-deserialization-with-dataset + * @tags security + * experimental + */ + +import csharp +import DataSetSerialization + +from UnsafeXmlReadMethodCall mc +select mc, + "Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details." diff --git a/csharp/src/security/backdoor/DangerousNativeFunctionCall.qhelp b/csharp/src/security/backdoor/DangerousNativeFunctionCall.qhelp new file mode 100644 index 00000000..f499eebf --- /dev/null +++ b/csharp/src/security/backdoor/DangerousNativeFunctionCall.qhelp @@ -0,0 +1,14 @@ + + + +

    This query finds native calls to external functions that are often used in creating backdoors or are generally attributed to unsafe code practices. This is an example of a query that may be useful for detecting potential backdoors. Solorigate is one example that uses this mechanism.

    +
    + + +

    Any findings from this rule are only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack. There is no certainty that the code is related or that the code is part of any attack.

    +

    For more information about Solorigate, please visit https://aka.ms/solorigate.

    +
    + +
    \ No newline at end of file diff --git a/csharp/src/security/backdoor/DangerousNativeFunctionCall.ql b/csharp/src/security/backdoor/DangerousNativeFunctionCall.ql new file mode 100644 index 00000000..b0f066ba --- /dev/null +++ b/csharp/src/security/backdoor/DangerousNativeFunctionCall.ql @@ -0,0 +1,55 @@ +/** + * @name Potential dangerous use of native functions + * @description Detects the use of native functions that can be used for malicious intent or unsafe handling. + * @kind problem + * @problem.severity warning + * @precision low + * @id cs/backdoor/dangerous-native-functions + * @tags security + * experimental + * solorigate + */ + +import csharp +import semmle.code.csharp.frameworks.system.runtime.InteropServices + +predicate isDangerousMethod(Method m) { + m.getName() = "OpenProcessToken" or + m.getName() = "OpenThreadToken" or + m.getName() = "DuplicateToken" or + m.getName() = "DuplicateTokenEx" or + m.getName().matches("LogonUser%") or + m.getName().matches("WNetAddConnection%") or + m.getName() = "DeviceIoControl" or + m.getName().matches("LoadLibrary%") or + m.getName() = "GetProcAddress" or + m.getName().matches("CreateProcess%") or + m.getName().matches("InitiateSystemShutdown%") or + m.getName() = "GetCurrentProcess" or + m.getName() = "GetCurrentProcessToken" or + m.getName() = "GetCurrentThreadToken" or + m.getName() = "GetCurrentThreadEffectiveToken" or + m.getName() = "OpenThreadToken" or + m.getName() = "SetTokenInformation" or + m.getName().matches("LookupPrivilegeValue%") or + m.getName() = "AdjustTokenPrivileges" or + m.getName() = "SetProcessPrivilege" or + m.getName() = "ImpersonateLoggedOnUser" or + m.getName().matches("Add%Ace%") +} + +predicate isExternMethod(Method externMethod) { + externMethod.isExtern() + or + externMethod.getAnAttribute().getType() instanceof + SystemRuntimeInteropServicesDllImportAttributeClass + or + externMethod.getDeclaringType().getAnAttribute().getType() instanceof + SystemRuntimeInteropServicesComImportAttributeClass +} + +from MethodCall mc +where + isExternMethod(mc.getTarget()) and + isDangerousMethod(mc.getTarget()) +select mc, "Call to an external method '" + mc.getTarget().getName() + "'." diff --git a/csharp/src/security/backdoor/PotentialTimeBomb.qhelp b/csharp/src/security/backdoor/PotentialTimeBomb.qhelp new file mode 100644 index 00000000..57a8c571 --- /dev/null +++ b/csharp/src/security/backdoor/PotentialTimeBomb.qhelp @@ -0,0 +1,14 @@ + + + +

    This query detects situations in which an offset to a last file modification time is used to conditionally execute a particular block of code. This is a common pattern in backdoors, where the file's modification timestamp is the time at which the backdoor was planted, and the time offset is used as a time bomb before a particular code block is executed.

    +
    + + +

    Any findings from this rule are only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack. There is no certainty that the code is related or that the code is part of any attack.

    +

    For more information about Solorigate, please visit https://aka.ms/solorigate.

    +
    + +
    \ No newline at end of file diff --git a/csharp/src/security/backdoor/PotentialTimeBomb.ql b/csharp/src/security/backdoor/PotentialTimeBomb.ql new file mode 100644 index 00000000..47b69d3e --- /dev/null +++ b/csharp/src/security/backdoor/PotentialTimeBomb.ql @@ -0,0 +1,186 @@ +/** + * @name Potential Timebomb + * @description If there is data flow from a file's last modification date and an offset to a condition statement, this could trigger a "time bomb". + * @kind path-problem + * @precision Low + * @problem.severity warning + * @id cs/backdoor/potential-time-bomb + * @tags security + * experimental + * solorigate + */ + +import csharp +import Flow::PathGraph + +query predicate edges(Flow::PathNode a, Flow::PathNode b, string key, string val) { + Flow::PathGraph::edges(a, b, key, val) + or + FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallableConfig::isSink(a.getNode()) and + FlowsFromTimeSpanArithmeticToTimeComparisonCallableConfig::isSource(b.getNode()) and + key = "provenance" and + val = "" + or + FlowsFromTimeSpanArithmeticToTimeComparisonCallableConfig::isSink(a.getNode()) and + FlowsFromTimeComparisonCallableToSelectionStatementConditionConfig::isSource(b.getNode()) and + key = "provenance" and + val = "" +} + +/** + * Class that will help to find the source for the trigger file-modification date. + * + * May be extended as new patterns for similar time bombs are found. + */ +class GetLastWriteTimeMethod extends Method { + GetLastWriteTimeMethod() { + this.hasFullyQualifiedName("System.IO.File", + ["GetLastWriteTime", "GetFileCreationTime", "GetCreationTimeUtc", "GetLastAccessTimeUtc"]) + } +} + +/** + * Abstracts `System.DateTime` structure + */ +class DateTimeStruct extends Struct { + DateTimeStruct() { this.hasFullyQualifiedName("System", "DateTime") } + + /** + * holds if the Callable is used for DateTime arithmetic operations + */ + Callable getATimeSpanArithmeticCallable() { + (result = this.getAnOperator() or result = this.getAMethod()) and + result.getName() in [ + "Add", "AddDays", "AddHours", "AddMilliseconds", "AddMinutes", "AddMonths", "AddSeconds", + "AddTicks", "AddYears", "+", "-" + ] + } + + /** + * Holds if the Callable is used for DateTime comparison + */ + Callable getAComparisonCallable() { + (result = this.getAnOperator() or result = this.getAMethod()) and + result.getName() in ["Compare", "CompareTo", "Equals", "==", "!=", "<", ">", "<=", ">="] + } +} + +/** + * Configuration to find flow from a GetLastWriteTime source to a DateTime arithmetic operation + */ +private module FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallableConfig implements + DataFlow::ConfigSig +{ + predicate isSource(DataFlow::Node source) { + exists(Call call, GetLastWriteTimeMethod m | + m.getACall() = call and + source.asExpr() = call + ) + } + + predicate isSink(DataFlow::Node sink) { + exists(Call call, DateTimeStruct dateTime | + call.getAChild*() = sink.asExpr() and + call = dateTime.getATimeSpanArithmeticCallable().getACall() + ) + } +} + +/** + * Tainttracking module to find flow from a GetLastWriteTime source to a DateTime arithmetic operation + */ +private module FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable = + TaintTracking::Global; + +/** + * Configuration to find flow from a DateTime arithmetic operation to a DateTime comparison operation + */ +private module FlowsFromTimeSpanArithmeticToTimeComparisonCallableConfig implements + DataFlow::ConfigSig +{ + predicate isSource(DataFlow::Node source) { + exists(DateTimeStruct dateTime, Call call | source.asExpr() = call | + call = dateTime.getATimeSpanArithmeticCallable().getACall() + ) + } + + predicate isSink(DataFlow::Node sink) { + exists(Call call, DateTimeStruct dateTime | + call.getAnArgument().getAChild*() = sink.asExpr() and + call = dateTime.getAComparisonCallable().getACall() + ) + } +} + +/** + * Tainttracking module to find flow from a DateTime arithmetic operation to a DateTime comparison operation + */ +private module FlowsFromTimeSpanArithmeticToTimeComparisonCallable = + TaintTracking::Global; + +/** + * Configuration to find flow from a DateTime comparison operation to a Selection Statement (such as an If) + */ +private module FlowsFromTimeComparisonCallableToSelectionStatementConditionConfig implements + DataFlow::ConfigSig +{ + predicate isSource(DataFlow::Node source) { + exists(DateTimeStruct dateTime, Call call | source.asExpr() = call | + call = dateTime.getAComparisonCallable().getACall() + ) + } + + predicate isSink(DataFlow::Node sink) { + exists(SelectionStmt sel | sel.getCondition().getAChild*() = sink.asExpr()) + } +} + +/** + * Tainttracking module to find flow from a DateTime comparison operation to a Selection Statement (such as an If) + */ +private module FlowsFromTimeComparisonCallableToSelectionStatementCondition = + TaintTracking::Global; + +private module Flow = + DataFlow::MergePathGraph3; + +/** + * Holds if the last file modification date from the call to getLastWriteTimeMethodCall will be used in a DateTime arithmetic operation timeArithmeticCall, + * which is then used for a DateTime comparison timeComparisonCall and the result flows to a Selection statement which is likely a TimeBomb trigger + */ +predicate isPotentialTimeBomb( + Flow::PathNode pathSource, Flow::PathNode pathSink, Call getLastWriteTimeMethodCall, + Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement +) { + exists(DataFlow::Node sink, DateTimeStruct dateTime, DataFlow::Node sink2, DataFlow::Node sink3 | + pathSource.getNode() = DataFlow::exprNode(getLastWriteTimeMethodCall) and + FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable::flow(DataFlow::exprNode(getLastWriteTimeMethodCall), + sink) and + timeArithmeticCall = dateTime.getATimeSpanArithmeticCallable().getACall() and + timeArithmeticCall.getAChild*() = sink.asExpr() and + FlowsFromTimeSpanArithmeticToTimeComparisonCallable::flow(DataFlow::exprNode(timeArithmeticCall), + sink2) and + timeComparisonCall = dateTime.getAComparisonCallable().getACall() and + timeComparisonCall.getAnArgument().getAChild*() = sink2.asExpr() and + FlowsFromTimeComparisonCallableToSelectionStatementCondition::flow(DataFlow::exprNode(timeComparisonCall), + sink3) and + selStatement.getCondition().getAChild*() = sink3.asExpr() and + pathSink.getNode() = sink3 + ) +} + +from + Flow::PathNode source, Flow::PathNode sink, Call getLastWriteTimeMethodCall, + Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement +where + isPotentialTimeBomb(source, sink, getLastWriteTimeMethodCall, timeArithmeticCall, + timeComparisonCall, selStatement) +select selStatement, source, sink, + "Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger.", + timeComparisonCall, timeComparisonCall.toString(), timeArithmeticCall, "offset", + getLastWriteTimeMethodCall, "last modification time of a file" diff --git a/csharp/src/security/backdoor/ProcessNameToHashTaintFlow.qhelp b/csharp/src/security/backdoor/ProcessNameToHashTaintFlow.qhelp new file mode 100644 index 00000000..cb1faf86 --- /dev/null +++ b/csharp/src/security/backdoor/ProcessNameToHashTaintFlow.qhelp @@ -0,0 +1,15 @@ + + + +

    This query detects code flow from ProcessName property on the Process class into a hash function.

    +

    Such flow is often used in code backdoors to detect running processes and compare them to an obfuscated list of antivirus processes to avoid detection. Solorigate is one example that uses this mechanism.

    +
    + + +

    Any findings from this rule are only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack. There is no certainty that the code is related or that the code is part of any attack.

    +

    For more information about Solorigate, please visit https://aka.ms/solorigate.

    +
    + +
    \ No newline at end of file diff --git a/csharp/src/security/backdoor/ProcessNameToHashTaintFlow.ql b/csharp/src/security/backdoor/ProcessNameToHashTaintFlow.ql new file mode 100644 index 00000000..2835ac19 --- /dev/null +++ b/csharp/src/security/backdoor/ProcessNameToHashTaintFlow.ql @@ -0,0 +1,49 @@ +/** + * @name ProcessName to hash function flow + * @description Flow from a function retrieving process name to a hash function. + * @kind path-problem + * @tags security + * experimental + * solorigate + * @problem.severity warning + * @precision medium + * @id cs/backdoor/process-name-to-hash-function + */ + +import csharp +import experimental.code.csharp.Cryptography.NonCryptographicHashes +import DataFlowFromMethodToHash::PathGraph + +module DataFlowFromMethodToHashConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { isSuspiciousPropertyName(source.asExpr()) } + + predicate isSink(DataFlow::Node sink) { isGetHash(sink.asExpr()) } +} + +module DataFlowFromMethodToHash = TaintTracking::Global; + +predicate isGetHash(Expr arg) { + exists(MethodCall mc | + ( + mc.getTarget().getName().matches("%Hash%") or + mc.getTarget().getName().regexpMatch("Md[4-5]|Sha[1-9]{1,3}") + ) and + mc.getAnArgument() = arg + ) + or + exists(Callable callable, Parameter param, Call call | + isCallableAPotentialNonCryptographicHashFunction(callable, param) and + call = callable.getACall() and + arg = call.getArgumentForParameter(param) + ) +} + +predicate isSuspiciousPropertyName(PropertyRead pr) { + pr.getTarget().hasFullyQualifiedName("System.Diagnostics", "Process", "ProcessName") +} + +from DataFlowFromMethodToHash::PathNode src, DataFlowFromMethodToHash::PathNode sink +where DataFlowFromMethodToHash::flow(src.getNode(), sink.getNode()) +select src.getNode(), src, sink, + "The hash is calculated on $@, may be related to a backdoor. Please review the code for possible malicious intent.", + sink.getNode(), "this process name" diff --git a/csharp/src/security/dataflow/flowsources/AuthCookie.qll b/csharp/src/security/dataflow/flowsources/AuthCookie.qll new file mode 100644 index 00000000..928cf3bd --- /dev/null +++ b/csharp/src/security/dataflow/flowsources/AuthCookie.qll @@ -0,0 +1,250 @@ +/** + * Provides classes and predicates for detecting insecure cookies. + */ + +import csharp +import semmle.code.csharp.frameworks.microsoft.AspNetCore + +/** + * Holds if the expression is a variable with a sensitive name. + */ +predicate isCookieWithSensitiveName(Expr cookieExpr) { + exists(DataFlow::Node sink | + AuthCookieName::flowTo(sink) and + sink.asExpr() = cookieExpr + ) +} + +/** + * Configuration for tracking if a variable with a sensitive name is used as an argument. + */ +private module AuthCookieNameConfig implements DataFlow::ConfigSig { + private predicate isAuthVariable(Expr expr) { + exists(string val | + ( + val = expr.getValue() or + val = expr.(Access).getTarget().getName() + ) and + val.regexpMatch("(?i).*(session|login|token|user|auth|credential).*") and + not val.regexpMatch("(?i).*(xsrf|csrf|forgery).*") + ) + } + + predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) } + + predicate isSink(DataFlow::Node sink) { exists(Call c | sink.asExpr() = c.getAnArgument()) } +} + +/** + * Tracks if a variable with a sensitive name is used as an argument. + */ +private module AuthCookieName = DataFlow::Global; + +/** + * Configuration module tracking creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)` + * calls as a third parameter. + */ +private module CookieOptionsTrackingConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source.asExpr().(ObjectCreation).getType() instanceof MicrosoftAspNetCoreHttpCookieOptions + } + + predicate isSink(DataFlow::Node sink) { + exists(MicrosoftAspNetCoreHttpResponseCookies iResponse, MethodCall mc | + iResponse.getAppendMethod() = mc.getTarget() and + mc.getArgument(2) = sink.asExpr() + ) + } +} + +/** + * Tracking creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)` + * calls as a third parameter. + */ +module CookieOptionsTracking = DataFlow::Global; + +/** + * Looks for property value of `CookiePolicyOptions` passed to `app.UseCookiePolicy` in `Startup.Configure`. + */ +Expr getAValueForCookiePolicyProp(string prop) { + exists(Method m, MethodCall mc, ObjectCreation oc, Expr val | + m.getName() = "Configure" and + m.getDeclaringType().getName() = "Startup" and + m.getBody().getAChild+() = mc and + mc.getTarget() = + any(MicrosoftAspNetCoreBuilderCookiePolicyAppBuilderExtensions e).getUseCookiePolicyMethod() and + oc.getType() instanceof MicrosoftAspNetCoreBuilderCookiePolicyOptions and + getAValueForProp(oc, _, prop) = val and + result = val + ) +} + +/** + * A simplistic points-to alternative: given an object creation and a property name, get the values that property can be assigned. + * + * Assumptions: + * - we don't reassign the variable that the creation is stored in + * - we always access the creation through the same variable it is initially assigned to + * + * This should cover most typical patterns... + */ +Expr getAValueForProp(ObjectCreation create, Assignment a, string prop) { + // values set in object init + exists(MemberInitializer init, Expr src, PropertyAccess pa | + a.getLValue() = pa and + pa.getTarget().hasName(prop) and + init = create.getInitializer().(ObjectInitializer).getAMemberInitializer() and + init.getLValue() = pa and + DataFlow::localExprFlow(src, init.getRValue()) and + result = src + ) + or + // values set on var that create is assigned to + exists(Expr src, PropertyAccess pa | + a.getLValue() = pa and + pa.getTarget().hasName(prop) and + DataFlow::localExprFlow(create, pa.getQualifier()) and + DataFlow::localExprFlow(src, a.getRValue()) and + result = src + ) +} + +/** + * Checks if the given property was explicitly set to a value. + */ +predicate isPropertySet(ObjectCreation oc, string prop) { exists(getAValueForProp(oc, _, prop)) } + +/** + * Tracks if a callback used in `OnAppendCookie` sets a cookie property to `true`. + */ +abstract deprecated private class OnAppendCookieTrackingConfig extends DataFlow::Configuration { + bindingset[this] + OnAppendCookieTrackingConfig() { any() } + + /** + * Specifies the cookie property name to track. + */ + abstract string propertyName(); + + override predicate isSource(DataFlow::Node source) { + exists(PropertyWrite pw, Assignment delegateAssign, Callable c | + pw.getProperty().getName() = "OnAppendCookie" and + pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreBuilderCookiePolicyOptions and + delegateAssign.getLValue() = pw and + ( + exists(LambdaExpr lambda | + delegateAssign.getRValue() = lambda and + lambda = c + ) + or + exists(DelegateCreation delegate | + delegateAssign.getRValue() = delegate and + delegate.getArgument().(CallableAccess).getTarget() = c + ) + ) and + c.getParameter(0) = source.asParameter() + ) + } + + override predicate isSink(DataFlow::Node sink) { + exists(PropertyWrite pw, Assignment a | + pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieOptions and + pw.getProperty().getName() = this.propertyName() and + a.getLValue() = pw and + exists(Expr val | + DataFlow::localExprFlow(val, a.getRValue()) and + val.getValue() = "true" + ) and + sink.asExpr() = pw.getQualifier() + ) + } + + override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + node2.asExpr() = + any(PropertyRead pr | + pr.getQualifier() = node1.asExpr() and + pr.getProperty().getDeclaringType() instanceof + MicrosoftAspNetCoreCookiePolicyAppendCookieContext + ) + } +} + +private signature string propertyName(); + +/** + * Configuration for tracking if a callback used in `OnAppendCookie` sets a cookie property to `true`. + */ +private module OnAppendCookieTrackingConfig implements + DataFlow::ConfigSig +{ + /** + * Specifies the cookie property name to track. + */ + predicate isSource(DataFlow::Node source) { + exists(PropertyWrite pw, Assignment delegateAssign, Callable c | + pw.getProperty().getName() = "OnAppendCookie" and + pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreBuilderCookiePolicyOptions and + delegateAssign.getLValue() = pw and + ( + exists(LambdaExpr lambda | + delegateAssign.getRValue() = lambda and + lambda = c + ) + or + exists(DelegateCreation delegate | + delegateAssign.getRValue() = delegate and + delegate.getArgument().(CallableAccess).getTarget() = c + ) + ) and + c.getParameter(0) = source.asParameter() + ) + } + + predicate isSink(DataFlow::Node sink) { + exists(PropertyWrite pw, Assignment a | + pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieOptions and + pw.getProperty().getName() = getPropertyName() and + a.getLValue() = pw and + exists(Expr val | + DataFlow::localExprFlow(val, a.getRValue()) and + val.getValue() = "true" + ) and + sink.asExpr() = pw.getQualifier() + ) + } + + predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + node2.asExpr() = + any(PropertyRead pr | + pr.getQualifier() = node1.asExpr() and + pr.getProperty().getDeclaringType() instanceof + MicrosoftAspNetCoreCookiePolicyAppendCookieContext + ) + } +} + +private string getPropertyNameSecure() { result = "Secure" } + +/** + * Configuration module for tracking if a callback used in `OnAppendCookie` sets `Secure` to `true`. + */ +private module OnAppendCookieSecureTrackingConfig = + OnAppendCookieTrackingConfig; + +/** + * Tracks if a callback used in `OnAppendCookie` sets `Secure` to `true`. + */ +module OnAppendCookieSecureTracking = DataFlow::Global; + +private string getPropertyNameHttpOnly() { result = "HttpOnly" } + +/** + * Configuration module for tracking if a callback used in `OnAppendCookie` sets `HttpOnly` to `true`. + */ +private module OnAppendCookieHttpOnlyTrackingConfig = + OnAppendCookieTrackingConfig; + +/** + * Tracks if a callback used in `OnAppendCookie` sets `HttpOnly` to `true`. + */ +module OnAppendCookieHttpOnlyTracking = DataFlow::Global; From b1ab77f7198bfb57425e0544705886afd1d8bbbc Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 29 Oct 2024 13:51:19 +0100 Subject: [PATCH 2/5] C#: Add a copy of all experimental query tests (as is). --- .../CookieBuilder/HttpOnly.expected | 2 + .../CookieBuilder/HttpOnly.qlref | 1 + .../CookieBuilder/Program.cs | 23 ++ .../NoPolicy/HttpOnly.expected | 4 + .../NoPolicy/HttpOnly.qlref | 1 + .../NoPolicy/Program.cs | 71 ++++++ .../UseCookiePolicyCallback/HttpOnly.expected | 0 .../UseCookiePolicyCallback/HttpOnly.qlref | 1 + .../UseCookiePolicyCallback/Program.cs | 37 ++++ .../CookieHttpOnlyFalseAspNetCore/options | 3 + .../HttpOnly.expected | 4 + .../HttpOnly.qlref | 1 + .../CookieHttpOnlyFalseSystemWeb/Program.cs | 56 +++++ .../CookieHttpOnlyFalseSystemWeb/Web.config | 6 + .../CookieHttpOnlyFalseSystemWeb/options | 3 + .../NoPolicy/HttpOnly.expected | 2 + .../NoPolicy/HttpOnly.qlref | 1 + .../NoPolicy/Program.cs | 52 +++++ .../UseCookiePolicyAlways/HttpOnly.expected | 0 .../UseCookiePolicyAlways/HttpOnly.qlref | 1 + .../UseCookiePolicyAlways/Program.cs | 25 +++ .../UseCookiePolicyCallback/HttpOnly.expected | 0 .../UseCookiePolicyCallback/HttpOnly.qlref | 1 + .../UseCookiePolicyCallback/Program.cs | 36 ++++ .../UseCookiePolicyNone/HttpOnly.expected | 2 + .../UseCookiePolicyNone/HttpOnly.qlref | 1 + .../UseCookiePolicyNone/Program.cs | 25 +++ .../CookieWithoutHttpOnlyAspNetCore/options | 3 + .../ConfigEmpty/HttpOnly.expected | 1 + .../ConfigEmpty/HttpOnly.qlref | 1 + .../ConfigEmpty/Program.cs | 36 ++++ .../ConfigEmpty/Web.config | 6 + .../ConfigEmpty/options | 3 + .../ConfigFalse/HttpOnly.expected | 1 + .../ConfigFalse/HttpOnly.qlref | 1 + .../ConfigFalse/Program.cs | 36 ++++ .../ConfigFalse/Web.config | 6 + .../ConfigFalse/options | 3 + .../HttpCookiesTrue/HttpOnly.expected | 0 .../HttpCookiesTrue/HttpOnly.qlref | 1 + .../HttpCookiesTrue/Program.cs | 36 ++++ .../HttpCookiesTrue/Web.config | 6 + .../HttpCookiesTrue/options | 3 + .../RequireSSLAspNetCore/NoPolicy/Program.cs | 47 ++++ .../NoPolicy/RequireSSL.expected | 2 + .../NoPolicy/RequireSSL.qlref | 1 + .../UseCookiePolicyAlways/Program.cs | 25 +++ .../UseCookiePolicyAlways/RequireSSL.expected | 0 .../UseCookiePolicyAlways/RequireSSL.qlref | 1 + .../UseCookiePolicyCallback/Program.cs | 41 ++++ .../RequireSSL.expected | 0 .../UseCookiePolicyCallback/RequireSSL.qlref | 1 + .../UseCookiePolicyNone/Program.cs | 25 +++ .../UseCookiePolicyNone/RequireSSL.expected | 2 + .../UseCookiePolicyNone/RequireSSL.qlref | 1 + .../CWE-614/RequireSSLAspNetCore/options | 3 + .../CookieBuilder/Program.cs | 23 ++ .../CookieBuilder/RequireSSL.expected | 2 + .../CookieBuilder/RequireSSL.qlref | 1 + .../NoPolicy/Program.cs | 64 ++++++ .../NoPolicy/RequireSSL.expected | 4 + .../NoPolicy/RequireSSL.qlref | 1 + .../UseCookiePolicyCallback/Program.cs | 37 ++++ .../RequireSSL.expected | 0 .../UseCookiePolicyCallback/RequireSSL.qlref | 1 + .../CWE-614/RequireSSLFalseAspNetCore/options | 3 + .../RequireSSLFalseSystemWeb/Program.cs | 50 +++++ .../RequireSSL.expected | 4 + .../RequireSSLFalseSystemWeb/RequireSSL.qlref | 1 + .../RequireSSLFalseSystemWeb/Web.config | 6 + .../CWE-614/RequireSSLFalseSystemWeb/options | 3 + .../ConfigEmpty/Program.cs | 31 +++ .../ConfigEmpty/RequireSSL.expected | 1 + .../ConfigEmpty/RequireSSL.qlref | 1 + .../ConfigEmpty/Web.config | 6 + .../RequireSSLSystemWeb/ConfigEmpty/options | 3 + .../ConfigFalse/Program.cs | 31 +++ .../ConfigFalse/RequireSSL.expected | 1 + .../ConfigFalse/RequireSSL.qlref | 1 + .../ConfigFalse/Web.config | 6 + .../RequireSSLSystemWeb/ConfigFalse/options | 3 + .../RequireSSLSystemWeb/FormsTrue/Program.cs | 31 +++ .../FormsTrue/RequireSSL.expected | 0 .../FormsTrue/RequireSSL.qlref | 1 + .../RequireSSLSystemWeb/FormsTrue/Web.config | 9 + .../RequireSSLSystemWeb/FormsTrue/options | 3 + .../HttpCookiesTrue/Program.cs | 31 +++ .../HttpCookiesTrue/RequireSSL.expected | 0 .../HttpCookiesTrue/RequireSSL.qlref | 1 + .../HttpCookiesTrue/Web.config | 6 + .../HttpCookiesTrue/options | 3 + .../test/security/CWE-759/HashWithoutSalt.cs | 202 ++++++++++++++++++ .../security/CWE-759/HashWithoutSalt.expected | 30 +++ .../security/CWE-759/HashWithoutSalt.qlref | 2 + csharp/test/security/CWE-759/Sha1Utils.cs | 53 +++++ csharp/test/security/CWE-759/Stubs.cs | 45 ++++ csharp/test/security/CWE-759/options | 1 + .../test/security/CWE-918/RequestForgery.cs | 38 ++++ .../security/CWE-918/RequestForgery.expected | 8 + .../security/CWE-918/RequestForgery.qlref | 1 + csharp/test/security/CWE-918/options | 3 + ...ty-validations-always-return-true.expected | 7 + ...urity-validations-always-return-true.qlref | 1 + .../JsonWebTokenHandler/delegation-test.cs | 137 ++++++++++++ .../security-validation-disabled-test.cs | 43 ++++ .../security-validation-disabled.expected | 5 + .../security-validation-disabled.qlref | 1 + .../security/JsonWebTokenHandler/stubs.cs | 115 ++++++++++ .../DefiningDatasetRelatedType.expected | 2 + .../DefiningDatasetRelatedType.qlref | 1 + ...ingPotentiallyUnsafeXmlSerializer.expected | 2 + ...finingPotentiallyUnsafeXmlSerializer.qlref | 1 + ...afeTypeUsedDataContractSerializer.expected | 2 + ...UnsafeTypeUsedDataContractSerializer.qlref | 1 + .../XmlDeserializationWithDataSet.expected | 1 + .../XmlDeserializationWithDataSet.qlref | 1 + csharp/test/security/Serialization/options | 1 + csharp/test/security/Serialization/test0.cs | 99 +++++++++ .../DangerousNativeFunctionCall.expected | 1 + .../DangerousNativeFunctionCall.qlref | 1 + .../backdoor/PotentialTimeBomb.expected | 23 ++ .../security/backdoor/PotentialTimeBomb.qlref | 1 + .../ProcessNameToHashTaintFlow.expected | 4 + .../backdoor/ProcessNameToHashTaintFlow.qlref | 1 + csharp/test/security/backdoor/test.cs | 77 +++++++ 125 files changed, 1931 insertions(+) create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/options create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/Web.config create mode 100644 csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/options create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/options create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/Web.config create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/options create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/Web.config create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/options create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.expected create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.qlref create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/Program.cs create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/Web.config create mode 100644 csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/options create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLAspNetCore/options create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/options create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/Web.config create mode 100644 csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/options create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/Web.config create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/options create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/Web.config create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/options create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/Web.config create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/options create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/Program.cs create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.expected create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.qlref create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/Web.config create mode 100644 csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/options create mode 100644 csharp/test/security/CWE-759/HashWithoutSalt.cs create mode 100644 csharp/test/security/CWE-759/HashWithoutSalt.expected create mode 100644 csharp/test/security/CWE-759/HashWithoutSalt.qlref create mode 100644 csharp/test/security/CWE-759/Sha1Utils.cs create mode 100644 csharp/test/security/CWE-759/Stubs.cs create mode 100644 csharp/test/security/CWE-759/options create mode 100644 csharp/test/security/CWE-918/RequestForgery.cs create mode 100644 csharp/test/security/CWE-918/RequestForgery.expected create mode 100644 csharp/test/security/CWE-918/RequestForgery.qlref create mode 100644 csharp/test/security/CWE-918/options create mode 100644 csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.expected create mode 100644 csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref create mode 100644 csharp/test/security/JsonWebTokenHandler/delegation-test.cs create mode 100644 csharp/test/security/JsonWebTokenHandler/security-validation-disabled-test.cs create mode 100644 csharp/test/security/JsonWebTokenHandler/security-validation-disabled.expected create mode 100644 csharp/test/security/JsonWebTokenHandler/security-validation-disabled.qlref create mode 100644 csharp/test/security/JsonWebTokenHandler/stubs.cs create mode 100644 csharp/test/security/Serialization/DefiningDatasetRelatedType.expected create mode 100644 csharp/test/security/Serialization/DefiningDatasetRelatedType.qlref create mode 100644 csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected create mode 100644 csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref create mode 100644 csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.expected create mode 100644 csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.qlref create mode 100644 csharp/test/security/Serialization/XmlDeserializationWithDataSet.expected create mode 100644 csharp/test/security/Serialization/XmlDeserializationWithDataSet.qlref create mode 100644 csharp/test/security/Serialization/options create mode 100644 csharp/test/security/Serialization/test0.cs create mode 100644 csharp/test/security/backdoor/DangerousNativeFunctionCall.expected create mode 100644 csharp/test/security/backdoor/DangerousNativeFunctionCall.qlref create mode 100644 csharp/test/security/backdoor/PotentialTimeBomb.expected create mode 100644 csharp/test/security/backdoor/PotentialTimeBomb.qlref create mode 100644 csharp/test/security/backdoor/ProcessNameToHashTaintFlow.expected create mode 100644 csharp/test/security/backdoor/ProcessNameToHashTaintFlow.qlref create mode 100644 csharp/test/security/backdoor/test.cs diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.expected new file mode 100644 index 00000000..cf0986a4 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.expected @@ -0,0 +1,2 @@ +| Program.cs:13:33:13:37 | false | Cookie attribute 'HttpOnly' is not set to true. | +| Program.cs:20:39:20:43 | false | Cookie attribute 'HttpOnly' is not set to true. | diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/Program.cs b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/Program.cs new file mode 100644 index 00000000..4f51bdb5 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/Program.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authentication; + +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddAuthentication().AddCookie(o => + { + o.Cookie.HttpOnly = false; + o.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.None; + }); + + services.AddSession(options => + { + options.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.None; + options.Cookie.HttpOnly = false; + }); + } +} diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.expected new file mode 100644 index 00000000..968e2897 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.expected @@ -0,0 +1,4 @@ +| Program.cs:25:34:25:38 | false | Cookie attribute 'HttpOnly' is not set to true. | +| Program.cs:38:88:38:92 | false | Cookie attribute 'HttpOnly' is not set to true. | +| Program.cs:61:34:61:34 | access to local variable v | Cookie attribute 'HttpOnly' is not set to true. | +| Program.cs:68:88:68:88 | access to local variable v | Cookie attribute 'HttpOnly' is not set to true. | diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/Program.cs b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/Program.cs new file mode 100644 index 00000000..6f12958f --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/Program.cs @@ -0,0 +1,71 @@ +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDelete() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Delete("auth", cookieOptions); // GOOD: Delete call + } + + void CookieDirectTrue() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + cookieOptions.HttpOnly = true; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { HttpOnly = true }; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD + } + + void CookieDirectFalse() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + cookieOptions.HttpOnly = false; + Response.Cookies.Append("auth", "secret", cookieOptions); // BAD + } + + void CookieDirectFalseForgery() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + cookieOptions.HttpOnly = false; + Response.Cookies.Append("antiforgerytoken", "secret", cookieOptions); // GOOD: not an auth cookie + } + + void CookieDirectFalseInitializer() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { HttpOnly = false }; + Response.Cookies.Append("auth", "secret", cookieOptions); // BAD + } + + void CookieIntermediateTrue() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + bool v = true; + cookieOptions.HttpOnly = v; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { HttpOnly = v }; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: should track local data flow + } + + void CookieIntermediateFalse() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + bool v = false; + cookieOptions.HttpOnly = v; + Response.Cookies.Append("auth", "secret", cookieOptions); // BAD + } + + void CookieIntermediateFalseInitializer() + { + bool v = false; + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { HttpOnly = v }; + Response.Cookies.Append("auth", "secret", cookieOptions); // BAD + } +} diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.expected new file mode 100644 index 00000000..e69de29b diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/Program.cs b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/Program.cs new file mode 100644 index 00000000..60f217ef --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/Program.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Http; + +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDefault() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + cookieOptions.HttpOnly = false; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: HttpOnly is set in callback + } +} + +public class Startup +{ + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCookiePolicy(); + } + + public void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + options.OnAppendCookie = cookieContext => SetCookies(cookieContext.CookieOptions); + }); + } + + private void SetCookies(CookieOptions options) + { + options.Secure = true; + options.HttpOnly = true; + } +} diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/options b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/options new file mode 100644 index 00000000..ce3f295e --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.expected new file mode 100644 index 00000000..28844595 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.expected @@ -0,0 +1,4 @@ +| Program.cs:23:27:23:31 | false | Cookie attribute 'HttpOnly' is not set to true. | +| Program.cs:28:74:28:78 | false | Cookie attribute 'HttpOnly' is not set to true. | +| Program.cs:48:27:48:27 | access to local variable v | Cookie attribute 'HttpOnly' is not set to true. | +| Program.cs:54:74:54:74 | access to local variable v | Cookie attribute 'HttpOnly' is not set to true. | diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/Program.cs b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/Program.cs new file mode 100644 index 00000000..6ab389f6 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/Program.cs @@ -0,0 +1,56 @@ +class Program +{ + void CookieDirectTrue() + { + var cookie = new System.Web.HttpCookie("sessionID"); + cookie.HttpOnly = true; // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookie = new System.Web.HttpCookie("sessionID") { HttpOnly = true }; // GOOD + } + + void CookieForgeryDirectFalse() + { + var cookie = new System.Web.HttpCookie("antiforgerytoken"); + cookie.HttpOnly = false; // GOOD: not an auth cookie + } + + void CookieDirectFalse() + { + var cookie = new System.Web.HttpCookie("sessionID"); + cookie.HttpOnly = false; // BAD + } + + void CookieDirectFalseInitializer() + { + var cookie = new System.Web.HttpCookie("sessionID") { HttpOnly = false }; // BAD + } + + void CookieIntermediateTrue() + { + var cookie = new System.Web.HttpCookie("sessionID"); + bool v = true; + cookie.HttpOnly = v; // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookie = new System.Web.HttpCookie("sessionID") { HttpOnly = v }; // GOOD: should track local data flow + } + + void CookieIntermediateFalse() + { + var cookie = new System.Web.HttpCookie("sessionID"); + bool v = false; + cookie.HttpOnly = v; // BAD + } + + void CookieIntermediateFalseInitializer() + { + bool v = false; + var cookie = new System.Web.HttpCookie("sessionID") { HttpOnly = v }; // BAD + } +} diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/Web.config b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/Web.config new file mode 100644 index 00000000..96fd10c0 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/Web.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/options b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/options new file mode 100644 index 00000000..9290f65d --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.expected new file mode 100644 index 00000000..aac50988 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.expected @@ -0,0 +1,2 @@ +| Program.cs:5:9:5:49 | call to method Append | Cookie attribute 'HttpOnly' is not set to true. | +| Program.cs:15:29:15:73 | object creation of type CookieOptions | Cookie attribute 'HttpOnly' is not set to true. | diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/Program.cs b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/Program.cs new file mode 100644 index 00000000..945c5be5 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/Program.cs @@ -0,0 +1,52 @@ +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDefault() + { + Response.Cookies.Append("auth", "secret"); // BAD: HttpOnly is set to false by default + } + + public void CookieDefaultForgery() + { + Response.Cookies.Append("antiforgerytoken", "secret"); // GOOD: not an auth cookie + } + + public void CookieDefault2() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Append("auth", "secret", cookieOptions); // BAD: HttpOnly is set to false by default + } + + public void CookieDelete() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Delete("auth", cookieOptions); // GOOD: Delete call + } + + void CookieDirectTrue() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + cookieOptions.HttpOnly = true; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { HttpOnly = true }; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD + } + + void CookieIntermediateTrue() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + bool v = true; + cookieOptions.HttpOnly = v; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { HttpOnly = v }; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: should track local data flow + } +} diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.expected new file mode 100644 index 00000000..e69de29b diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/Program.cs b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/Program.cs new file mode 100644 index 00000000..115f448a --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/Program.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; + +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDefault() + { + Response.Cookies.Append("auth", "secret"); // GOOD: HttpOnly is set in policy + } + + public void CookieDefault2() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: HttpOnly is set in policy + } +} + +public class Startup +{ + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCookiePolicy(new CookiePolicyOptions() { HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.Always}); + } +} diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.expected new file mode 100644 index 00000000..e69de29b diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/Program.cs b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/Program.cs new file mode 100644 index 00000000..417b1f77 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/Program.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Http; + +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDefault() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: HttpOnly is set in callback + } +} + +public class Startup +{ + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCookiePolicy(); + } + + public void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + options.OnAppendCookie = cookieContext => SetCookies(cookieContext.CookieOptions); + }); + } + + private void SetCookies(CookieOptions options) + { + options.Secure = true; + options.HttpOnly = true; + } +} diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.expected new file mode 100644 index 00000000..adfb1ab3 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.expected @@ -0,0 +1,2 @@ +| Program.cs:8:9:8:49 | call to method Append | Cookie attribute 'HttpOnly' is not set to true. | +| Program.cs:13:29:13:73 | object creation of type CookieOptions | Cookie attribute 'HttpOnly' is not set to true. | diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/Program.cs b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/Program.cs new file mode 100644 index 00000000..7be845aa --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/Program.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; + +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDefault() + { + Response.Cookies.Append("auth", "secret"); // Bad: HttpOnly policy set to None + } + + public void CookieDefault2() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Append("auth", "secret", cookieOptions); // Bad: HttpOnly policy set to None + } +} + +public class Startup +{ + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCookiePolicy(new CookiePolicyOptions() { HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.None }); + } +} diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/options b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/options new file mode 100644 index 00000000..ce3f295e --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.expected new file mode 100644 index 00000000..85b07c94 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.expected @@ -0,0 +1 @@ +| Program.cs:5:22:5:59 | object creation of type HttpCookie | Cookie attribute 'HttpOnly' is not set to true. | diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/Program.cs b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/Program.cs new file mode 100644 index 00000000..bc66b526 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/Program.cs @@ -0,0 +1,36 @@ +class Program +{ + void CookieDefault() + { + var cookie = new System.Web.HttpCookie("sessionID"); // BAD: httpOnlyCookies is set to false by default + } + + void CookieDefaultForgery() + { + var cookie = new System.Web.HttpCookie("anticsrftoken"); // GOOD: not an auth cookie + } + + void CookieDirectTrue() + { + var cookie = new System.Web.HttpCookie("sessionID"); + cookie.HttpOnly = true; // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookie = new System.Web.HttpCookie("sessionID") { HttpOnly = true }; // GOOD + } + + void CookieIntermediateTrue() + { + var cookie = new System.Web.HttpCookie("sessionID"); + bool v = true; + cookie.HttpOnly = v; // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookie = new System.Web.HttpCookie("sessionID") { HttpOnly = v }; // GOOD: should track local data flow + } +} diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/Web.config b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/Web.config new file mode 100644 index 00000000..96fd10c0 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/Web.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/options b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/options new file mode 100644 index 00000000..9d05f9bf --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.expected new file mode 100644 index 00000000..85b07c94 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.expected @@ -0,0 +1 @@ +| Program.cs:5:22:5:59 | object creation of type HttpCookie | Cookie attribute 'HttpOnly' is not set to true. | diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/Program.cs b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/Program.cs new file mode 100644 index 00000000..52ef1337 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/Program.cs @@ -0,0 +1,36 @@ +class Program +{ + void CookieDefault() + { + var cookie = new System.Web.HttpCookie("sessionID"); // BAD: httpOnlyCookies is set to false in config + } + + void CookieDefaultForgery() + { + var cookie = new System.Web.HttpCookie("anticsrftoken"); // GOOD: not an auth cookie + } + + void CookieDirectTrue() + { + var cookie = new System.Web.HttpCookie("sessionID"); + cookie.HttpOnly = true; // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookie = new System.Web.HttpCookie("sessionID") { HttpOnly = true }; // GOOD + } + + void CookieIntermediateTrue() + { + var cookie = new System.Web.HttpCookie("sessionID"); + bool v = true; + cookie.HttpOnly = v; // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookie = new System.Web.HttpCookie("sessionID") { HttpOnly = v }; // GOOD: should track local data flow + } +} diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/Web.config b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/Web.config new file mode 100644 index 00000000..d6202a55 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/Web.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/options b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/options new file mode 100644 index 00000000..9d05f9bf --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.expected b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.expected new file mode 100644 index 00000000..e69de29b diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.qlref new file mode 100644 index 00000000..91ce2260 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/Program.cs b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/Program.cs new file mode 100644 index 00000000..6eeb4f6d --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/Program.cs @@ -0,0 +1,36 @@ +class Program +{ + void CookieDefault() + { + var cookie = new System.Web.HttpCookie("sessionID"); // GOOD: httpOnlyCookies is set to true in config + } + + void CookieDefaultForgery() + { + var cookie = new System.Web.HttpCookie("anticsrftoken"); // GOOD: not an auth cookie + } + + void CookieDirectTrue() + { + var cookie = new System.Web.HttpCookie("sessionID"); + cookie.HttpOnly = true; // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookie = new System.Web.HttpCookie("sessionID") { HttpOnly = true }; // GOOD + } + + void CookieIntermediateTrue() + { + var cookie = new System.Web.HttpCookie("sessionID"); + bool v = true; + cookie.HttpOnly = v; // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookie = new System.Web.HttpCookie("sessionID") { HttpOnly = v }; // GOOD: should track local data flow + } +} diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/Web.config b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/Web.config new file mode 100644 index 00000000..fc262149 --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/Web.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/options b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/options new file mode 100644 index 00000000..9d05f9bf --- /dev/null +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/Program.cs b/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/Program.cs new file mode 100644 index 00000000..9c214169 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/Program.cs @@ -0,0 +1,47 @@ +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDefault() + { + Response.Cookies.Append("name", "value"); // BAD: requireSSL is set to false by default + } + + public void CookieDefault2() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Append("name", "value", cookieOptions); // BAD: requireSSL is set to false by default + } + + public void CookieDelete() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Delete("name", cookieOptions); // GOOD: Delete call + } + + void CookieDirectTrue() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + cookieOptions.Secure = true; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { Secure = true }; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD + } + + void CookieIntermediateTrue() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + bool v = true; + cookieOptions.Secure = v; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { Secure = v }; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: should track local data flow + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.expected new file mode 100644 index 00000000..f96df31a --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.expected @@ -0,0 +1,2 @@ +| Program.cs:5:9:5:48 | call to method Append | Cookie attribute 'Secure' is not set to true. | +| Program.cs:10:29:10:73 | object creation of type CookieOptions | Cookie attribute 'Secure' is not set to true. | diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/Program.cs b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/Program.cs new file mode 100644 index 00000000..7c125f92 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/Program.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; + +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDefault() + { + Response.Cookies.Append("auth", "secret"); // GOOD: Secure is set in policy + } + + public void CookieDefault2() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: Secure is set in policy + } +} + +public class Startup +{ + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCookiePolicy(new CookiePolicyOptions() { Secure = Microsoft.AspNetCore.Http.CookieSecurePolicy.Always }); + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.expected new file mode 100644 index 00000000..e69de29b diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/Program.cs b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/Program.cs new file mode 100644 index 00000000..85bd3bed --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/Program.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Http; + +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDefault() + { + Response.Cookies.Append("auth", "secret"); // GOOD: Secure is set in callback + } + + public void CookieDefault2() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: Secure is set in callback + } +} + +public class Startup +{ + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCookiePolicy(); + } + + public void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + options.OnAppendCookie = cookieContext => SetCookies(cookieContext.CookieOptions); + }); + } + + private void SetCookies(CookieOptions options) + { + options.Secure = true; + options.HttpOnly = true; + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.expected new file mode 100644 index 00000000..e69de29b diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/Program.cs b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/Program.cs new file mode 100644 index 00000000..9db1f538 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/Program.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; + +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDefault() + { + Response.Cookies.Append("auth", "secret"); // Bad: Secure policy set to None + } + + public void CookieDefault2() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Append("auth", "secret", cookieOptions); // Bad: Secure policy set to None + } +} + +public class Startup +{ + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCookiePolicy(new CookiePolicyOptions() { Secure = Microsoft.AspNetCore.Http.CookieSecurePolicy.None }); + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.expected new file mode 100644 index 00000000..030293f7 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.expected @@ -0,0 +1,2 @@ +| Program.cs:8:9:8:49 | call to method Append | Cookie attribute 'Secure' is not set to true. | +| Program.cs:13:29:13:73 | object creation of type CookieOptions | Cookie attribute 'Secure' is not set to true. | diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/options b/csharp/test/security/CWE-614/RequireSSLAspNetCore/options new file mode 100644 index 00000000..ce3f295e --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/Program.cs b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/Program.cs new file mode 100644 index 00000000..4f51bdb5 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/Program.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authentication; + +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddAuthentication().AddCookie(o => + { + o.Cookie.HttpOnly = false; + o.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.None; + }); + + services.AddSession(options => + { + options.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.None; + options.Cookie.HttpOnly = false; + }); + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.expected new file mode 100644 index 00000000..fdddb535 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.expected @@ -0,0 +1,2 @@ +| Program.cs:14:37:14:85 | access to constant None | Cookie attribute 'Secure' is not set to true. | +| Program.cs:19:43:19:91 | access to constant None | Cookie attribute 'Secure' is not set to true. | diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/Program.cs b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/Program.cs new file mode 100644 index 00000000..b1ad1aed --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/Program.cs @@ -0,0 +1,64 @@ +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDelete() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + Response.Cookies.Delete("name", cookieOptions); // GOOD: Delete call + } + + void CookieDirectTrue() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + cookieOptions.Secure = true; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { Secure = true }; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD + } + + void CookieDirectFalse() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + cookieOptions.Secure = false; + Response.Cookies.Append("auth", "secret", cookieOptions); // BAD + } + + void CookieDirectFalseInitializer() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { Secure = false }; + Response.Cookies.Append("auth", "secret", cookieOptions); // BAD + } + + void CookieIntermediateTrue() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + bool v = true; + cookieOptions.Secure = v; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { Secure = v }; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: should track local data flow + } + + void CookieIntermediateFalse() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + bool v = false; + cookieOptions.Secure = v; + Response.Cookies.Append("auth", "secret", cookieOptions); // BAD + } + + void CookieIntermediateFalseInitializer() + { + bool v = false; + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions() { Secure = v }; + Response.Cookies.Append("auth", "secret", cookieOptions); // BAD + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.expected new file mode 100644 index 00000000..7b7bc343 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.expected @@ -0,0 +1,4 @@ +| Program.cs:25:32:25:36 | false | Cookie attribute 'Secure' is not set to true. | +| Program.cs:31:86:31:90 | false | Cookie attribute 'Secure' is not set to true. | +| Program.cs:54:32:54:32 | access to local variable v | Cookie attribute 'Secure' is not set to true. | +| Program.cs:61:86:61:86 | access to local variable v | Cookie attribute 'Secure' is not set to true. | diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/Program.cs b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/Program.cs new file mode 100644 index 00000000..542b1a29 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/Program.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Http; + +public class MyController : Microsoft.AspNetCore.Mvc.Controller +{ + public void CookieDefault() + { + var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions(); + cookieOptions.Secure = false; + Response.Cookies.Append("auth", "secret", cookieOptions); // GOOD: Secure is set in callback + } +} + +public class Startup +{ + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseCookiePolicy(); + } + + public void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + options.OnAppendCookie = cookieContext => SetCookies(cookieContext.CookieOptions); + }); + } + + private void SetCookies(CookieOptions options) + { + options.Secure = true; + options.HttpOnly = true; + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.expected new file mode 100644 index 00000000..e69de29b diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/options b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/options new file mode 100644 index 00000000..ce3f295e --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj diff --git a/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/Program.cs b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/Program.cs new file mode 100644 index 00000000..3a6d80b5 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/Program.cs @@ -0,0 +1,50 @@ +class Program +{ + void CookieDirectTrue() + { + var cookie = new System.Web.HttpCookie("cookieName"); + cookie.Secure = true; // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookie = new System.Web.HttpCookie("cookieName") { Secure = true }; // GOOD + } + + void CookieDirectFalse() + { + var cookie = new System.Web.HttpCookie("cookieName"); + cookie.Secure = false; // BAD + } + + void CookieDirectFalseInitializer() + { + var cookie = new System.Web.HttpCookie("cookieName") { Secure = false }; // BAD + } + + void CookieIntermediateTrue() + { + var cookie = new System.Web.HttpCookie("cookieName"); + bool v = true; + cookie.Secure = v; // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookie = new System.Web.HttpCookie("cookieName") { Secure = v }; // GOOD: should track local data flow + } + + void CookieIntermediateFalse() + { + var cookie = new System.Web.HttpCookie("cookieName"); + bool v = false; + cookie.Secure = v; // BAD + } + + void CookieIntermediateFalseInitializer() + { + bool v = false; + var cookie = new System.Web.HttpCookie("cookieName") { Secure = v }; // BAD + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.expected new file mode 100644 index 00000000..fb6b5e84 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.expected @@ -0,0 +1,4 @@ +| Program.cs:17:25:17:29 | false | Cookie attribute 'Secure' is not set to true. | +| Program.cs:22:73:22:77 | false | Cookie attribute 'Secure' is not set to true. | +| Program.cs:42:25:42:25 | access to local variable v | Cookie attribute 'Secure' is not set to true. | +| Program.cs:48:73:48:73 | access to local variable v | Cookie attribute 'Secure' is not set to true. | diff --git a/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/Web.config b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/Web.config new file mode 100644 index 00000000..96fd10c0 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/Web.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/options b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/options new file mode 100644 index 00000000..9290f65d --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/Program.cs b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/Program.cs new file mode 100644 index 00000000..4011a7d1 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/Program.cs @@ -0,0 +1,31 @@ +class Program +{ + void CookieDefault() + { + var cookie = new System.Web.HttpCookie("cookieName"); // BAD: requireSSL is set to false by default + } + + void CookieDirectTrue() + { + var cookie = new System.Web.HttpCookie("cookieName"); + cookie.Secure = true; // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookie = new System.Web.HttpCookie("cookieName") { Secure = true }; // GOOD + } + + void CookieIntermediateTrue() + { + var cookie = new System.Web.HttpCookie("cookieName"); + bool v = true; + cookie.Secure = v; // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookie = new System.Web.HttpCookie("cookieName") { Secure = v }; // GOOD: should track local data flow + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.expected new file mode 100644 index 00000000..6c224aab --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.expected @@ -0,0 +1 @@ +| Program.cs:5:22:5:60 | object creation of type HttpCookie | Cookie attribute 'Secure' is not set to true. | diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/Web.config b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/Web.config new file mode 100644 index 00000000..96fd10c0 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/Web.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/options b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/options new file mode 100644 index 00000000..9d05f9bf --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/Program.cs b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/Program.cs new file mode 100644 index 00000000..392366a7 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/Program.cs @@ -0,0 +1,31 @@ +class Program +{ + void CookieDefault() + { + var cookie = new System.Web.HttpCookie("cookieName"); // BAD: requireSSL is set to false in config + } + + void CookieDirectTrue() + { + var cookie = new System.Web.HttpCookie("cookieName"); + cookie.Secure = true; // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookie = new System.Web.HttpCookie("cookieName") { Secure = true }; // GOOD + } + + void CookieIntermediateTrue() + { + var cookie = new System.Web.HttpCookie("cookieName"); + bool v = true; + cookie.Secure = v; // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookie = new System.Web.HttpCookie("cookieName") { Secure = v }; // GOOD: should track local data flow + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.expected new file mode 100644 index 00000000..6c224aab --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.expected @@ -0,0 +1 @@ +| Program.cs:5:22:5:60 | object creation of type HttpCookie | Cookie attribute 'Secure' is not set to true. | diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/Web.config b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/Web.config new file mode 100644 index 00000000..ec7b8876 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/Web.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/options b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/options new file mode 100644 index 00000000..9d05f9bf --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/Program.cs b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/Program.cs new file mode 100644 index 00000000..be53a64a --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/Program.cs @@ -0,0 +1,31 @@ +class Program +{ + void CookieDefault() + { + var cookie = new System.Web.HttpCookie("cookieName"); // GOOD: requireSSL is set to true in config + } + + void CookieDirectTrue() + { + var cookie = new System.Web.HttpCookie("cookieName"); + cookie.Secure = true; // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookie = new System.Web.HttpCookie("cookieName") { Secure = true }; // GOOD + } + + void CookieIntermediateTrue() + { + var cookie = new System.Web.HttpCookie("cookieName"); + bool v = true; + cookie.Secure = v; // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookie = new System.Web.HttpCookie("cookieName") { Secure = v }; // GOOD: should track local data flow + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.expected new file mode 100644 index 00000000..e69de29b diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/Web.config b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/Web.config new file mode 100644 index 00000000..c65c506b --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/Web.config @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/options b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/options new file mode 100644 index 00000000..9d05f9bf --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/Program.cs b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/Program.cs new file mode 100644 index 00000000..be53a64a --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/Program.cs @@ -0,0 +1,31 @@ +class Program +{ + void CookieDefault() + { + var cookie = new System.Web.HttpCookie("cookieName"); // GOOD: requireSSL is set to true in config + } + + void CookieDirectTrue() + { + var cookie = new System.Web.HttpCookie("cookieName"); + cookie.Secure = true; // GOOD + } + + void CookieDirectTrueInitializer() + { + var cookie = new System.Web.HttpCookie("cookieName") { Secure = true }; // GOOD + } + + void CookieIntermediateTrue() + { + var cookie = new System.Web.HttpCookie("cookieName"); + bool v = true; + cookie.Secure = v; // GOOD: should track local data flow + } + + void CookieIntermediateTrueInitializer() + { + bool v = true; + var cookie = new System.Web.HttpCookie("cookieName") { Secure = v }; // GOOD: should track local data flow + } +} diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.expected b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.expected new file mode 100644 index 00000000..e69de29b diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.qlref new file mode 100644 index 00000000..f76146a8 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.qlref @@ -0,0 +1 @@ +experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/Web.config b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/Web.config new file mode 100644 index 00000000..831693f0 --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/Web.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/options b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/options new file mode 100644 index 00000000..9d05f9bf --- /dev/null +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-759/HashWithoutSalt.cs b/csharp/test/security/CWE-759/HashWithoutSalt.cs new file mode 100644 index 00000000..302936c0 --- /dev/null +++ b/csharp/test/security/CWE-759/HashWithoutSalt.cs @@ -0,0 +1,202 @@ +// semmle-extractor-options: /r:System.Security.Cryptography.Primitives.dll /r:System.Security.Cryptography.Csp.dll /r:System.Security.Cryptography.Algorithms.dll + +using System; +using System.Text; +using System.Security.Cryptography; + +using Windows.Security.Cryptography; +using Windows.Security.Cryptography.Core; +using Windows.Storage.Streams; + +public class Test +{ + private const int SaltSize = 32; + + // BAD - Hash without a salt. + public static String HashPassword(string password, string strAlgName ="SHA256") + { + IBuffer passBuff = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8); + HashAlgorithmProvider algProvider = HashAlgorithmProvider.OpenAlgorithm(strAlgName); + IBuffer hashBuff = algProvider.HashData(passBuff); + return CryptographicBuffer.EncodeToBase64String(hashBuff); + } + + // GOOD - Hash with a salt. + public static string HashPassword2(string password, string salt, string strAlgName ="SHA256") + { + // Concatenate the salt with the password. + IBuffer passBuff = CryptographicBuffer.ConvertStringToBinary(password+salt, BinaryStringEncoding.Utf8); + HashAlgorithmProvider algProvider = HashAlgorithmProvider.OpenAlgorithm(strAlgName); + IBuffer hashBuff = algProvider.HashData(passBuff); + return CryptographicBuffer.EncodeToBase64String(hashBuff); + } + + // BAD - Hash without a salt. + public static string HashPassword(string password) + { + SHA256 sha256Hash = SHA256.Create(); + byte[] passBytes = System.Text.Encoding.ASCII.GetBytes(password); + byte[] hashBytes = sha256Hash.ComputeHash(passBytes); + return Convert.ToBase64String(hashBytes); + } + + // GOOD - Hash with a salt. + public static string HashPassword2(string password) + { + byte[] passBytes = System.Text.Encoding.ASCII.GetBytes(password); + byte[] saltBytes = GenerateSalt(); + + // Add the salt to the hash. + byte[] rawSalted = new byte[passBytes.Length + saltBytes.Length]; + passBytes.CopyTo(rawSalted, 0); + saltBytes.CopyTo(rawSalted, passBytes.Length); + + //Create the salted hash. + SHA256 sha256 = SHA256.Create(); + byte[] saltedPassBytes = sha256.ComputeHash(rawSalted); + + // Add the salt value to the salted hash. + byte[] dbPassword = new byte[saltedPassBytes.Length + saltBytes.Length]; + saltedPassBytes.CopyTo(dbPassword, 0); + saltBytes.CopyTo(dbPassword, saltedPassBytes.Length); + + return Convert.ToBase64String(dbPassword); + } + + // BAD - Hash without a salt. + public static string HashPassword3(string password) + { + HashAlgorithm hashAlg = new SHA256CryptoServiceProvider(); + byte[] passBytes = System.Text.Encoding.ASCII.GetBytes(password); + byte[] hashBytes = hashAlg.ComputeHash(passBytes); + return Convert.ToBase64String(hashBytes); + } + + // GOOD - Hash with a salt. + public bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt) + { + using(var hmac = new System.Security.Cryptography.HMACSHA512(passwordSalt)) + { + var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password)); + for(int i = 0;i throw null; + + public static string EncodeToBase64String(Windows.Storage.Streams.IBuffer buffer) => throw null; + } +} + +namespace Windows.Storage.Streams +{ + public interface IBuffer { + public uint Capacity { get; } + + public uint Length { get; set; } + } +} + +namespace Windows.Security.Cryptography.Core +{ + public sealed class CryptographicKey { } + + public sealed class SymmetricKeyAlgorithmProvider + { + public CryptographicKey CreateSymmetricKey(Windows.Storage.Streams.IBuffer keyMaterial) => throw null; + } + + public sealed class HashAlgorithmProvider { + public string AlgorithmName { get; } + + public uint HashLength { get; } + + public static HashAlgorithmProvider OpenAlgorithm(string algorithm) => throw null; + + public Windows.Storage.Streams.IBuffer HashData(Windows.Storage.Streams.IBuffer data) => throw null; + } +} diff --git a/csharp/test/security/CWE-759/options b/csharp/test/security/CWE-759/options new file mode 100644 index 00000000..2d27f665 --- /dev/null +++ b/csharp/test/security/CWE-759/options @@ -0,0 +1 @@ +semmle-extractor-options: /r:System.Security.Cryptography.dll \ No newline at end of file diff --git a/csharp/test/security/CWE-918/RequestForgery.cs b/csharp/test/security/CWE-918/RequestForgery.cs new file mode 100644 index 00000000..02e851d8 --- /dev/null +++ b/csharp/test/security/CWE-918/RequestForgery.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading.Tasks; +using System.Web.Mvc; +using System.Net.Http; + +namespace RequestForgery.Controllers +{ + public class SSRFController : Controller + { + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Bad(string url) + { + var request = new HttpRequestMessage(HttpMethod.Get, url); + + var client = new HttpClient(); + await client.SendAsync(request); + + return View(); + } + + [HttpPost] + [ValidateAntiForgeryToken] + public async Task Good(string url) + { + string baseUrl = "www.mysecuresite.com/"; + if (url.StartsWith(baseUrl)) + { + var request = new HttpRequestMessage(HttpMethod.Get, url); + var client = new HttpClient(); + await client.SendAsync(request); + + } + + return View(); + } + } +} diff --git a/csharp/test/security/CWE-918/RequestForgery.expected b/csharp/test/security/CWE-918/RequestForgery.expected new file mode 100644 index 00000000..37cc9ded --- /dev/null +++ b/csharp/test/security/CWE-918/RequestForgery.expected @@ -0,0 +1,8 @@ +edges +| RequestForgery.cs:12:52:12:54 | url : String | RequestForgery.cs:14:66:14:68 | access to parameter url | provenance | | +nodes +| RequestForgery.cs:12:52:12:54 | url : String | semmle.label | url : String | +| RequestForgery.cs:14:66:14:68 | access to parameter url | semmle.label | access to parameter url | +subpaths +#select +| RequestForgery.cs:14:66:14:68 | access to parameter url | RequestForgery.cs:12:52:12:54 | url : String | RequestForgery.cs:14:66:14:68 | access to parameter url | The URL of this request depends on a $@. | RequestForgery.cs:12:52:12:54 | url | user-provided value | diff --git a/csharp/test/security/CWE-918/RequestForgery.qlref b/csharp/test/security/CWE-918/RequestForgery.qlref new file mode 100644 index 00000000..3d529ae5 --- /dev/null +++ b/csharp/test/security/CWE-918/RequestForgery.qlref @@ -0,0 +1 @@ +experimental/CWE-918/RequestForgery.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-918/options b/csharp/test/security/CWE-918/options new file mode 100644 index 00000000..09b08bf4 --- /dev/null +++ b/csharp/test/security/CWE-918/options @@ -0,0 +1,3 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../resources/stubs/System.Web.cs \ No newline at end of file diff --git a/csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.expected b/csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.expected new file mode 100644 index 00000000..a76e9660 --- /dev/null +++ b/csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.expected @@ -0,0 +1,7 @@ +| delegation-test.cs:101:63:101:186 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to this callable that always returns "true". | stubs.cs:54:34:54:50 | LifetimeValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.LifetimeValidator | +| delegation-test.cs:102:63:102:178 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to this callable that always returns "true". | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | +| delegation-test.cs:115:63:115:190 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to this callable that always returns "true". | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | +| delegation-test.cs:116:63:116:180 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to this callable that always returns "true". | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | +| delegation-test.cs:117:63:117:217 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to this callable that always returns "true". | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | +| delegation-test.cs:118:63:118:248 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to this callable that always returns "true". | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | +| delegation-test.cs:119:63:119:177 | (...) => ... | JsonWebTokenHandler security-sensitive property $@ is being delegated to this callable that always returns "true". | stubs.cs:55:34:55:50 | AudienceValidator | Microsoft.IdentityModel.Tokens.TokenValidationParameters.AudienceValidator | diff --git a/csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref b/csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref new file mode 100644 index 00000000..527ea925 --- /dev/null +++ b/csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref @@ -0,0 +1 @@ +experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql \ No newline at end of file diff --git a/csharp/test/security/JsonWebTokenHandler/delegation-test.cs b/csharp/test/security/JsonWebTokenHandler/delegation-test.cs new file mode 100644 index 00000000..01af41c4 --- /dev/null +++ b/csharp/test/security/JsonWebTokenHandler/delegation-test.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using Microsoft.IdentityModel.Tokens; +using Microsoft.IdentityModel.JsonWebTokens; + +namespace JsonWebTokenHandlerTest +{ + public class JsonWebTokenHandler_00 + { + public static object ThrowIfNull(string name, object value) + { + if (value == null) + { + throw new System.ArgumentNullException(name); + } + return value; + } + + private static bool MayThrowException(SecurityToken token) + { + if (token.Id == null) + { + throw new Exception("foobar"); + } + return true; + } + + private static void DoesNotThrowException(SecurityToken token) + { + int x = 0; + } + + private static bool ValidateLifetime_FP01( + SecurityToken token, + TokenValidationParameters validationParameters) + { + if (token == null) + { + throw new System.ArgumentNullException("token"); + } + + MayThrowException(token); + + return true; + } + + private static bool ValidateLifetime_P01( + SecurityToken token, + TokenValidationParameters validationParameters) + { + if (token == null) + { + throw new System.ArgumentNullException("token"); + } + + DoesNotThrowException(token); + + return true; + } + + + internal static bool ValidateLifetimeAlwaysTrue( + SecurityToken token, + TokenValidationParameters validationParameters) + { + if (token is null) + { + return true; + } + return true; + } + + internal static bool ValidateLifetime( + string token, + TokenValidationParameters validationParameters) + { + if (token is null) + { + return false; + } + return true; + } + + public void TestCase01() + { + TokenValidationParameters tokenValidationParamsBaseline = new TokenValidationParameters + { + ClockSkew = TimeSpan.FromMinutes(5), + ValidateActor = true, + ValidateIssuerSigningKey = true, + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + RequireExpirationTime = true, + ValidateTokenReplay = true, + RequireSignedTokens = true, + RequireAudience = true, + SaveSigninToken = true + }; + + tokenValidationParamsBaseline.LifetimeValidator = (notBefore, expires, securityToken, validationParameters) => ValidateLifetimeAlwaysTrue(securityToken, validationParameters); // BUG delegated-security-validations-always-return-true + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => true; // BUG delegated-security-validations-always-return-true + tokenValidationParamsBaseline.TokenReplayValidator = (DateTime? expirationTime, string securityToken, TokenValidationParameters validationParameters) => // GOOD + { + if (securityToken is null) + { + return false; + } + return true; + }; + + tokenValidationParamsBaseline.LifetimeValidator = (notBefore, expires, securityToken, validationParameters) => ValidateLifetime02(securityToken, validationParameters); // GOOD + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => {return securityToken is null?false:true; }; // GOOD + + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => { return true; }; // BUG + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => !false ; // BUG + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => { return securityToken is null?true:true; }; // BUG + tokenValidationParamsBaseline.AudienceValidator = (IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) => { return ValidateLifetimeAlwaysTrue(securityToken, validationParameters);}; //BUG + tokenValidationParamsBaseline.AudienceValidator = (audiences, securityToken, validationParameters) => ValidateLifetimeAlwaysTrue(securityToken, validationParameters); //BUG + + } + + internal static bool ValidateLifetime02( + SecurityToken token, + TokenValidationParameters validationParameters) + { + return token is null?false:true; + } + + internal static bool ValidateLifetimeAlwaysTrue02( + SecurityToken token, + TokenValidationParameters validationParameters) + { + return !false; + } + } +} \ No newline at end of file diff --git a/csharp/test/security/JsonWebTokenHandler/security-validation-disabled-test.cs b/csharp/test/security/JsonWebTokenHandler/security-validation-disabled-test.cs new file mode 100644 index 00000000..505aba41 --- /dev/null +++ b/csharp/test/security/JsonWebTokenHandler/security-validation-disabled-test.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Microsoft.IdentityModel.Tokens; + +namespace JsonWebTokenHandlerTest +{ + public class JsonWebTokenHandler_class01 + { + public void TestCase01() + { + TokenValidationParameters tokenValidationParamsBaseline = new TokenValidationParameters + { + ClockSkew = TimeSpan.FromMinutes(5), + ValidateActor = true, + ValidateIssuerSigningKey = true, + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + RequireExpirationTime = true, + ValidateTokenReplay = true, + RequireSignedTokens = true, + RequireAudience = true, + SaveSigninToken = true + }; + + TokenValidationParameters tokenValidationParams = new TokenValidationParameters + { + ClockSkew = TimeSpan.FromMinutes(5), + ValidateActor = false, + ValidateIssuerSigningKey = false, + ValidateIssuer = false, // BUG + ValidateAudience = false, // BUG + ValidateLifetime = false, // BUG + RequireExpirationTime = false, // BUG + ValidateTokenReplay = false, + RequireSignedTokens = false, + RequireAudience = false, // BUG + SaveSigninToken = false + }; + } + + } +} \ No newline at end of file diff --git a/csharp/test/security/JsonWebTokenHandler/security-validation-disabled.expected b/csharp/test/security/JsonWebTokenHandler/security-validation-disabled.expected new file mode 100644 index 00000000..4a0a5afc --- /dev/null +++ b/csharp/test/security/JsonWebTokenHandler/security-validation-disabled.expected @@ -0,0 +1,5 @@ +| security-validation-disabled-test.cs:31:34:31:38 | false | The security sensitive property $@ is being disabled by the following value: $@. | stubs.cs:43:21:43:34 | ValidateIssuer | Microsoft.IdentityModel.Tokens.TokenValidationParameters.ValidateIssuer | security-validation-disabled-test.cs:31:34:31:38 | false | false | +| security-validation-disabled-test.cs:32:36:32:40 | false | The security sensitive property $@ is being disabled by the following value: $@. | stubs.cs:44:21:44:36 | ValidateAudience | Microsoft.IdentityModel.Tokens.TokenValidationParameters.ValidateAudience | security-validation-disabled-test.cs:32:36:32:40 | false | false | +| security-validation-disabled-test.cs:33:36:33:40 | false | The security sensitive property $@ is being disabled by the following value: $@. | stubs.cs:45:21:45:36 | ValidateLifetime | Microsoft.IdentityModel.Tokens.TokenValidationParameters.ValidateLifetime | security-validation-disabled-test.cs:33:36:33:40 | false | false | +| security-validation-disabled-test.cs:34:41:34:45 | false | The security sensitive property $@ is being disabled by the following value: $@. | stubs.cs:51:21:51:41 | RequireExpirationTime | Microsoft.IdentityModel.Tokens.TokenValidationParameters.RequireExpirationTime | security-validation-disabled-test.cs:34:41:34:45 | false | false | +| security-validation-disabled-test.cs:37:35:37:39 | false | The security sensitive property $@ is being disabled by the following value: $@. | stubs.cs:50:21:50:35 | RequireAudience | Microsoft.IdentityModel.Tokens.TokenValidationParameters.RequireAudience | security-validation-disabled-test.cs:37:35:37:39 | false | false | diff --git a/csharp/test/security/JsonWebTokenHandler/security-validation-disabled.qlref b/csharp/test/security/JsonWebTokenHandler/security-validation-disabled.qlref new file mode 100644 index 00000000..ee07957f --- /dev/null +++ b/csharp/test/security/JsonWebTokenHandler/security-validation-disabled.qlref @@ -0,0 +1 @@ +experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.ql \ No newline at end of file diff --git a/csharp/test/security/JsonWebTokenHandler/stubs.cs b/csharp/test/security/JsonWebTokenHandler/stubs.cs new file mode 100644 index 00000000..1d0e0de0 --- /dev/null +++ b/csharp/test/security/JsonWebTokenHandler/stubs.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; + +namespace Microsoft.IdentityModel +{ + +} + +namespace Microsoft.IdentityModel.Tokens +{ + public abstract class SecurityToken + { + protected SecurityToken() { } + public string Id { get; } + public string Issuer { get; } + public DateTime ValidFrom { get; } + public DateTime ValidTo { get; } + } + + public abstract class TokenHandler + { + public static readonly int DefaultTokenLifetimeInMinutes; + + protected TokenHandler() { } + + public virtual int MaximumTokenSizeInBytes { get; set; } + public bool SetDefaultTimesOnTokenCreation { get; set; } + public int TokenLifetimeInMinutes { get; set; } + } + + public delegate bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters); + public delegate bool AudienceValidator(IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters); + public delegate bool TokenReplayValidator(DateTime? expirationTime, string securityToken, TokenValidationParameters validationParameters); + public delegate string IssuerValidator(string issuer, SecurityToken securityToken, TokenValidationParameters validationParameters); + + public class TokenValidationParameters + { + public const int DefaultMaximumTokenSizeInBytes = 256000; + public static readonly string DefaultAuthenticationType; + public static readonly TimeSpan DefaultClockSkew; + public TimeSpan ClockSkew { get; set; } + public bool SaveSigninToken { get; set; } + public bool ValidateIssuer { get; set; } + public bool ValidateAudience { get; set; } + public bool ValidateLifetime { get; set; } + public bool ValidateIssuerSigningKey { get; set; } + public bool ValidateTokenReplay { get; set; } + public bool ValidateActor { get; set; } + public bool RequireSignedTokens { get; set; } + public bool RequireAudience { get; set; } + public bool RequireExpirationTime { get; set; } + + // Delegation + public LifetimeValidator LifetimeValidator { get; set; } + public AudienceValidator AudienceValidator { get; set; } + public TokenReplayValidator TokenReplayValidator { get; set; } + public IssuerValidator IssuerValidator { get; set; } + + /* + public TokenValidationParameters() { } + public SignatureValidator SignatureValidator { get; set; } + public SecurityKey TokenDecryptionKey { get; set; } + public TokenDecryptionKeyResolver TokenDecryptionKeyResolver { get; set; } + public IEnumerable TokenDecryptionKeys { get; set; } + public TokenReader TokenReader { get; set; } + public ITokenReplayCache TokenReplayCache { get; set; } + public Func RoleClaimTypeRetriever { get; set; } + public string ValidAudience { get; set; } + public IEnumerable ValidAudiences { get; set; } + public string ValidIssuer { get; set; } + public IEnumerable ValidIssuers { get; set; } + public TokenValidationParameters ActorValidationParameters { get; set; } + public AudienceValidator AudienceValidator { get; set; } + public string AuthenticationType { get; set; } + public CryptoProviderFactory CryptoProviderFactory { get; set; } + public IssuerSigningKeyValidator IssuerSigningKeyValidator { get; set; } + public SecurityKey IssuerSigningKey { get; set; } + public IEnumerable IssuerSigningKeys { get; set; } + public IssuerValidator IssuerValidator { get; set; } + public string NameClaimType { get; set; } + public string RoleClaimType { get; set; } + public Func NameClaimTypeRetriever { get; set; } + public IDictionary PropertyBag { get; set; } + public IssuerSigningKeyResolver IssuerSigningKeyResolver { get; set; } + public IEnumerable ValidTypes { get; set; } + public virtual TokenValidationParameters Clone(); + public virtual string CreateClaimsIdentity(SecurityToken securityToken, string issuer); + */ + } + +} + +namespace Microsoft.IdentityModel.JsonWebTokens +{ + public class JsonWebTokenHandler : Microsoft.IdentityModel.Tokens.TokenHandler + { + public virtual TokenValidationResult ValidateToken(string token, Microsoft.IdentityModel.Tokens.TokenValidationParameters validationParameters) + { + return new TokenValidationResult() { IsValid = true, Exception = null, Issuer = "test" }; + } + } + + public class TokenValidationResult + { + public TokenValidationResult() { } + + public Exception Exception { get; set; } + public string Issuer { get; set; } + public bool IsValid { get; set; } + public Microsoft.IdentityModel.Tokens.SecurityToken SecurityToken { get; set; } + public string ClaimsIdentity { get; set; } + } + + +} diff --git a/csharp/test/security/Serialization/DefiningDatasetRelatedType.expected b/csharp/test/security/Serialization/DefiningDatasetRelatedType.expected new file mode 100644 index 00000000..923d680e --- /dev/null +++ b/csharp/test/security/Serialization/DefiningDatasetRelatedType.expected @@ -0,0 +1,2 @@ +| test0.cs:11:18:11:43 | DerivesFromDeprecatedType1 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | +| test0.cs:57:18:57:38 | AttributeSerializer01 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | diff --git a/csharp/test/security/Serialization/DefiningDatasetRelatedType.qlref b/csharp/test/security/Serialization/DefiningDatasetRelatedType.qlref new file mode 100644 index 00000000..7283db95 --- /dev/null +++ b/csharp/test/security/Serialization/DefiningDatasetRelatedType.qlref @@ -0,0 +1 @@ +experimental/Security Features/Serialization/DefiningDatasetRelatedType.ql \ No newline at end of file diff --git a/csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected b/csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected new file mode 100644 index 00000000..03518e43 --- /dev/null +++ b/csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.expected @@ -0,0 +1,2 @@ +| test0.cs:13:24:13:32 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:11:18:11:43 | DerivesFromDeprecatedType1 | DerivesFromDeprecatedType1 | test0.cs:13:24:13:32 | MyDataSet | MyDataSet | +| test0.cs:59:25:59:33 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:57:18:57:38 | AttributeSerializer01 | AttributeSerializer01 | test0.cs:59:25:59:33 | MyDataSet | MyDataSet | diff --git a/csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref b/csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref new file mode 100644 index 00000000..8a8632c6 --- /dev/null +++ b/csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref @@ -0,0 +1 @@ +experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql \ No newline at end of file diff --git a/csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.expected b/csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.expected new file mode 100644 index 00000000..421cae01 --- /dev/null +++ b/csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.expected @@ -0,0 +1,2 @@ +| test0.cs:93:49:93:63 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:93:49:93:63 | typeof(...) | typeof(...) | +| test0.cs:94:49:94:77 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:94:49:94:77 | typeof(...) | typeof(...) | diff --git a/csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.qlref b/csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.qlref new file mode 100644 index 00000000..1593497c --- /dev/null +++ b/csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.qlref @@ -0,0 +1 @@ +experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.ql \ No newline at end of file diff --git a/csharp/test/security/Serialization/XmlDeserializationWithDataSet.expected b/csharp/test/security/Serialization/XmlDeserializationWithDataSet.expected new file mode 100644 index 00000000..be451487 --- /dev/null +++ b/csharp/test/security/Serialization/XmlDeserializationWithDataSet.expected @@ -0,0 +1 @@ +| test0.cs:86:17:86:46 | call to method ReadXmlSchema | Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | diff --git a/csharp/test/security/Serialization/XmlDeserializationWithDataSet.qlref b/csharp/test/security/Serialization/XmlDeserializationWithDataSet.qlref new file mode 100644 index 00000000..8054e46f --- /dev/null +++ b/csharp/test/security/Serialization/XmlDeserializationWithDataSet.qlref @@ -0,0 +1 @@ +experimental/Security Features/Serialization/XmlDeserializationWithDataSet.ql \ No newline at end of file diff --git a/csharp/test/security/Serialization/options b/csharp/test/security/Serialization/options new file mode 100644 index 00000000..670ea383 --- /dev/null +++ b/csharp/test/security/Serialization/options @@ -0,0 +1 @@ +semmle-extractor-options: /r:System.Data.Common.dll /r:System.Xml.XmlSerializer.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Collections.dll /r:System.Private.Xml.dll /r:System.Private.DataContractSerialization.dll /r:System.Runtime.Extensions.dll /r:System.ComponentModel.TypeConverter.dll /r:System.Xml.ReaderWriter.dll /r:System.IO.FileSystem.dll diff --git a/csharp/test/security/Serialization/test0.cs b/csharp/test/security/Serialization/test0.cs new file mode 100644 index 00000000..d2b2e772 --- /dev/null +++ b/csharp/test/security/Serialization/test0.cs @@ -0,0 +1,99 @@ +using System; +using System.Data; +using System.IO; +using System.Xml.Serialization; +using System.Runtime.Serialization; +using System.Xml; +using System.Collections.Generic; + +namespace DataSetSerializationTest +{ + public class DerivesFromDeprecatedType1 : XmlSerializer // warning:DefiningDatasetRelatedType.ql + { + public DataSet MyDataSet { get; set; } // bug:DefiningPotentiallyUnsafeXmlSerializer.ql + + public DerivesFromDeprecatedType1() + { + } + } + + /* + * TODO: I cannot use DataContract on a QL unit test + * + [DataContract(Name = "Customer", Namespace = "http://www.contoso.com")] + public class PatternDataContractSerializer : XmlObjectSerializer + { + [DataMember()] + public DataSet MyDataSet { get; set; } + [DataMember()] + public DataTable MyDataTable { get; set; } + + PatternDataContractSerializer() { } + private ExtensionDataObject extensionData_Value; + public ExtensionDataObject ExtensionData + { + get + { + return extensionData_Value; + } + set + { + extensionData_Value = value; + } + } + + public override void WriteObject(System.IO.Stream stream, object graph) { } + public override void WriteObjectContent(System.Xml.XmlDictionaryWriter writer, object graph) { } + public override bool IsStartObject(System.Xml.XmlDictionaryReader reader) { return false; } + public override void WriteStartObject(System.Xml.XmlDictionaryWriter writer, object graph) { } + public override void WriteEndObject(System.Xml.XmlWriter writer) { } + public override void WriteEndObject(XmlDictionaryWriter writer) { } + public override object ReadObject(System.IO.Stream stream) { return null; } + public override object ReadObject(XmlDictionaryReader reader, bool b) { return null; } + } + */ + + [Serializable()] + public class AttributeSerializer01 // warning:DefiningDatasetRelatedType.ql + { + private DataSet MyDataSet; // bug:DefiningPotentiallyUnsafeXmlSerializer.ql + + AttributeSerializer01() + { + } + } + + class Program + { + static string GetSerializedDataSet(DataSet dataSet) + { + DataTable dataTable = new DataTable("MyTable"); + dataTable.Columns.Add("FirstName", typeof(string)); + dataTable.Columns.Add("LastName", typeof(string)); + dataTable.Columns.Add("Age", typeof(int)); + + StringWriter writer = new StringWriter(); + dataSet.WriteXml(writer, XmlWriteMode.DiffGram); + return writer.ToString(); + } + + static void datatable_readxmlschema_01(string fileName) + { + using (FileStream fs = File.OpenRead(fileName)) + { + DataTable newTable = new DataTable(); + System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(fs); + newTable.ReadXmlSchema(reader); //bug:XmlDeserializationWithDataSet.ql + } + } + + static void Main(string[] args) + { + + XmlSerializer x = new XmlSerializer(typeof(DataSet)); // bug:UnsafeTypeUsedDataContractSerializer.ql + XmlSerializer y = new XmlSerializer(typeof(AttributeSerializer01)); //bug:UnsafeTypeUsedDataContractSerializer.ql + + Console.WriteLine("Hello World!"); + } + } +} diff --git a/csharp/test/security/backdoor/DangerousNativeFunctionCall.expected b/csharp/test/security/backdoor/DangerousNativeFunctionCall.expected new file mode 100644 index 00000000..efbdcb3d --- /dev/null +++ b/csharp/test/security/backdoor/DangerousNativeFunctionCall.expected @@ -0,0 +1 @@ +| test.cs:32:9:32:74 | call to method InitiateSystemShutdownExW | Call to an external method 'InitiateSystemShutdownExW'. | diff --git a/csharp/test/security/backdoor/DangerousNativeFunctionCall.qlref b/csharp/test/security/backdoor/DangerousNativeFunctionCall.qlref new file mode 100644 index 00000000..1215c001 --- /dev/null +++ b/csharp/test/security/backdoor/DangerousNativeFunctionCall.qlref @@ -0,0 +1 @@ +experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql \ No newline at end of file diff --git a/csharp/test/security/backdoor/PotentialTimeBomb.expected b/csharp/test/security/backdoor/PotentialTimeBomb.expected new file mode 100644 index 00000000..3a2f8691 --- /dev/null +++ b/csharp/test/security/backdoor/PotentialTimeBomb.expected @@ -0,0 +1,23 @@ +nodes +| test.cs:69:18:69:30 | access to local variable lastWriteTime : DateTime | semmle.label | access to local variable lastWriteTime : DateTime | +| test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | semmle.label | call to method GetLastWriteTime : DateTime | +| test.cs:71:13:71:71 | call to method CompareTo | semmle.label | call to method CompareTo | +| test.cs:71:13:71:71 | call to method CompareTo : Int32 | semmle.label | call to method CompareTo : Int32 | +| test.cs:71:13:71:76 | ... >= ... | semmle.label | ... >= ... | +| test.cs:71:36:71:48 | access to local variable lastWriteTime | semmle.label | access to local variable lastWriteTime | +| test.cs:71:36:71:70 | call to method AddHours | semmle.label | call to method AddHours | +subpaths +edges +| test.cs:69:18:69:30 | access to local variable lastWriteTime : DateTime | test.cs:71:36:71:48 | access to local variable lastWriteTime | provenance | | +| test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:69:18:69:30 | access to local variable lastWriteTime : DateTime | provenance | | +| test.cs:71:13:71:71 | call to method CompareTo : Int32 | test.cs:71:13:71:76 | ... >= ... | provenance | | +| test.cs:71:36:71:48 | access to local variable lastWriteTime | test.cs:71:13:71:71 | call to method CompareTo | provenance | | +| test.cs:71:36:71:48 | access to local variable lastWriteTime | test.cs:71:13:71:71 | call to method CompareTo : Int32 | provenance | | +| test.cs:71:36:71:48 | access to local variable lastWriteTime | test.cs:71:36:71:70 | call to method AddHours | provenance | | +| test.cs:71:36:71:70 | call to method AddHours | test.cs:71:13:71:71 | call to method CompareTo | provenance | | +| test.cs:71:36:71:70 | call to method AddHours | test.cs:71:13:71:71 | call to method CompareTo : Int32 | provenance | | +| test.cs:71:36:71:70 | call to method AddHours | test.cs:71:36:71:70 | call to method AddHours | provenance | | +#select +| test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:71 | call to method CompareTo | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file | +| test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:71 | call to method CompareTo : Int32 | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file | +| test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:76 | ... >= ... | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file | diff --git a/csharp/test/security/backdoor/PotentialTimeBomb.qlref b/csharp/test/security/backdoor/PotentialTimeBomb.qlref new file mode 100644 index 00000000..f76817aa --- /dev/null +++ b/csharp/test/security/backdoor/PotentialTimeBomb.qlref @@ -0,0 +1 @@ +experimental/Security Features/backdoor/PotentialTimeBomb.ql \ No newline at end of file diff --git a/csharp/test/security/backdoor/ProcessNameToHashTaintFlow.expected b/csharp/test/security/backdoor/ProcessNameToHashTaintFlow.expected new file mode 100644 index 00000000..e217064d --- /dev/null +++ b/csharp/test/security/backdoor/ProcessNameToHashTaintFlow.expected @@ -0,0 +1,4 @@ +edges +nodes +subpaths +#select diff --git a/csharp/test/security/backdoor/ProcessNameToHashTaintFlow.qlref b/csharp/test/security/backdoor/ProcessNameToHashTaintFlow.qlref new file mode 100644 index 00000000..d1d0d520 --- /dev/null +++ b/csharp/test/security/backdoor/ProcessNameToHashTaintFlow.qlref @@ -0,0 +1 @@ +experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql \ No newline at end of file diff --git a/csharp/test/security/backdoor/test.cs b/csharp/test/security/backdoor/test.cs new file mode 100644 index 00000000..1aecc80a --- /dev/null +++ b/csharp/test/security/backdoor/test.cs @@ -0,0 +1,77 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.IO +{ + public class File + { + public static DateTime GetLastWriteTime(string s) + { + return new DateTime(DateTime.MaxValue.Ticks); + } + } +} + +namespace System.Diagnostics +{ + public class Process + { + public static string GetCurrentProcess() { return "test"; } + } +} + +class External +{ + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool InitiateSystemShutdownExW([In] string lpMachineName, [In] string lpMessage, [In] uint dwTimeout, [MarshalAs(UnmanagedType.Bool)][In] bool bForceAppsClosed, [MarshalAs(UnmanagedType.Bool)][In] bool bRebootAfterShutdown, [In] uint dwReason); + + void TestDangerousNativeFunctionCall() + { + InitiateSystemShutdownExW(null, null, 0U, true, true, 2147745794U); // BUG : DangerousNativeFunctionCall + } + + ulong GetFvnHash(string s) + { + ulong num = 14695981039346656037UL; /* FNV base offset */ + try + { + foreach (byte b in Encoding.UTF8.GetBytes(s)) + { + num ^= (ulong)b; + num *= 1099511628211UL; /* FNV prime */ + } + } + catch + { + } + // regular FVN + return num; + } + + void IndirectTestProcessNameToHashTaintFlow(string s) + { + GetFvnHash(s); // BUG : ProcessNameToHashTaintFlow + } + + void TestProcessNameToHashTaintFlow() + { + GetFvnHash(System.Diagnostics.Process.GetCurrentProcess()); // BUG : ProcessNameToHashTaintFlow + + string proc = System.Diagnostics.Process.GetCurrentProcess(); + + IndirectTestProcessNameToHashTaintFlow(proc); + } + + void TestTimeBomb() + { + DateTime lastWriteTime = System.IO.File.GetLastWriteTime("someFile"); + int num = new Random().Next(288, 336); + if (DateTime.Now.CompareTo(lastWriteTime.AddHours((double)num)) >= 0) // BUG : Potential time bomb, currently not detected + { + // Some code here + } + } + +} \ No newline at end of file From 6a023922220258d44409e22ded8a41cf05cde121 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 29 Oct 2024 14:29:56 +0100 Subject: [PATCH 3/5] C#: Adjust paths in test option files. --- .../security/CWE-1004/CookieHttpOnlyFalseAspNetCore/options | 4 ++-- .../security/CWE-1004/CookieHttpOnlyFalseSystemWeb/options | 4 ++-- .../security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/options | 4 ++-- .../CookieWithoutHttpOnlySystemWeb/ConfigEmpty/options | 4 ++-- .../CookieWithoutHttpOnlySystemWeb/ConfigFalse/options | 4 ++-- .../CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/options | 4 ++-- csharp/test/security/CWE-614/RequireSSLAspNetCore/options | 4 ++-- .../test/security/CWE-614/RequireSSLFalseAspNetCore/options | 4 ++-- csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/options | 4 ++-- .../security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/options | 4 ++-- .../security/CWE-614/RequireSSLSystemWeb/ConfigFalse/options | 4 ++-- .../security/CWE-614/RequireSSLSystemWeb/FormsTrue/options | 4 ++-- .../CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/options | 4 ++-- csharp/test/security/CWE-918/options | 4 ++-- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/options b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/options index ce3f295e..e0b7b651 100644 --- a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/options +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/options b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/options index 9290f65d..706833e1 100644 --- a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/options +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: ${testdir}/../../../../resources/stubs/System.Web.cs +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../codeql/csharp/ql/test/resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/options b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/options index ce3f295e..e0b7b651 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/options +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/options b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/options index 9d05f9bf..7ed41f82 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/options +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/options b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/options index 9d05f9bf..7ed41f82 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/options +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/options b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/options index 9d05f9bf..7ed41f82 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/options +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/options b/csharp/test/security/CWE-614/RequireSSLAspNetCore/options index ce3f295e..e0b7b651 100644 --- a/csharp/test/security/CWE-614/RequireSSLAspNetCore/options +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/options b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/options index ce3f295e..e0b7b651 100644 --- a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/options +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj diff --git a/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/options b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/options index 9290f65d..706833e1 100644 --- a/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/options +++ b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: ${testdir}/../../../../resources/stubs/System.Web.cs +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../codeql/csharp/ql/test/resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/options b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/options index 9d05f9bf..7ed41f82 100644 --- a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/options +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/options b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/options index 9d05f9bf..7ed41f82 100644 --- a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/options +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/options b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/options index 9d05f9bf..7ed41f82 100644 --- a/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/options +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/options b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/options index 9d05f9bf..7ed41f82 100644 --- a/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/options +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: ${testdir}/../../../../../resources/stubs/System.Web.cs +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../../../codeql/csharp/ql/test/resources/stubs/System.Web.cs diff --git a/csharp/test/security/CWE-918/options b/csharp/test/security/CWE-918/options index 09b08bf4..f2aae2e4 100644 --- a/csharp/test/security/CWE-918/options +++ b/csharp/test/security/CWE-918/options @@ -1,3 +1,3 @@ semmle-extractor-options: /nostdlib /noconfig -semmle-extractor-options: --load-sources-from-project:${testdir}/../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj -semmle-extractor-options: ${testdir}/../../resources/stubs/System.Web.cs \ No newline at end of file +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../codeql/csharp/ql/test/resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj +semmle-extractor-options: ${testdir}/../../../../codeql/csharp/ql/test/resources/stubs/System.Web.cs \ No newline at end of file From 9238147e514cdb3a7e7a9432b6f3e20146ea5427 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 29 Oct 2024 15:04:07 +0100 Subject: [PATCH 4/5] C#: Adjust query metadata and library references. --- csharp/src/security/CWE-099/TaintedWebClient.ql | 3 +-- csharp/src/security/CWE-1004/CookieWithoutHttpOnly.ql | 5 ++--- .../Azure/UnsafeUsageOfClientSideEncryptionVersion.ql | 3 +-- csharp/src/security/CWE-614/CookieWithoutSecure.ql | 5 ++--- csharp/src/security/CWE-759/HashWithoutSalt.ql | 3 +-- csharp/src/security/CWE-918/RequestForgery.ql | 3 +-- .../delegated-security-validations-always-return-true.ql | 3 +-- .../JsonWebTokenHandler/security-validation-disabled.ql | 3 +-- .../src/security/Serialization/DefiningDatasetRelatedType.ql | 3 +-- .../Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql | 3 +-- .../Serialization/UnsafeTypeUsedDataContractSerializer.ql | 3 +-- .../security/Serialization/XmlDeserializationWithDataSet.ql | 3 +-- csharp/src/security/backdoor/DangerousNativeFunctionCall.ql | 3 +-- csharp/src/security/backdoor/PotentialTimeBomb.ql | 5 ++--- csharp/src/security/backdoor/ProcessNameToHashTaintFlow.ql | 3 +-- 15 files changed, 18 insertions(+), 33 deletions(-) diff --git a/csharp/src/security/CWE-099/TaintedWebClient.ql b/csharp/src/security/CWE-099/TaintedWebClient.ql index 38d99db6..59920068 100644 --- a/csharp/src/security/CWE-099/TaintedWebClient.ql +++ b/csharp/src/security/CWE-099/TaintedWebClient.ql @@ -5,9 +5,8 @@ * @kind path-problem * @problem.severity error * @precision high - * @id cs/webclient-path-injection + * @id githubsecuritylab/cs/webclient-path-injection * @tags security - * experimental * external/cwe/cwe-099 * external/cwe/cwe-023 * external/cwe/cwe-036 diff --git a/csharp/src/security/CWE-1004/CookieWithoutHttpOnly.ql b/csharp/src/security/CWE-1004/CookieWithoutHttpOnly.ql index 560dcc6d..1195d950 100644 --- a/csharp/src/security/CWE-1004/CookieWithoutHttpOnly.ql +++ b/csharp/src/security/CWE-1004/CookieWithoutHttpOnly.ql @@ -7,9 +7,8 @@ * @kind problem * @problem.severity warning * @precision high - * @id cs/web/cookie-httponly-not-set + * @id githubsecuritylab/cs/web/cookie-httponly-not-set * @tags security - * experimental * external/cwe/cwe-1004 */ @@ -17,7 +16,7 @@ import csharp import semmle.code.asp.WebConfig import semmle.code.csharp.frameworks.system.Web import semmle.code.csharp.frameworks.microsoft.AspNetCore -import experimental.dataflow.flowsources.AuthCookie +import security.dataflow.flowsources.AuthCookie from Expr httpOnlySink where diff --git a/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql b/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql index e112d284..80234acb 100644 --- a/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql +++ b/csharp/src/security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql @@ -4,9 +4,8 @@ * @kind problem * @tags security * cryptography - * experimental * external/cwe/cwe-327 - * @id cs/azure-storage/unsafe-usage-of-client-side-encryption-version + * @id githubsecuritylab/cs/azure-storage/unsafe-usage-of-client-side-encryption-version * @problem.severity error * @precision high */ diff --git a/csharp/src/security/CWE-614/CookieWithoutSecure.ql b/csharp/src/security/CWE-614/CookieWithoutSecure.ql index 417c5e59..2f99d000 100644 --- a/csharp/src/security/CWE-614/CookieWithoutSecure.ql +++ b/csharp/src/security/CWE-614/CookieWithoutSecure.ql @@ -6,9 +6,8 @@ * @kind problem * @problem.severity error * @precision high - * @id cs/web/cookie-secure-not-set + * @id githubsecuritylab/cs/web/cookie-secure-not-set * @tags security - * experimental * external/cwe/cwe-319 * external/cwe/cwe-614 */ @@ -17,7 +16,7 @@ import csharp import semmle.code.asp.WebConfig import semmle.code.csharp.frameworks.system.Web import semmle.code.csharp.frameworks.microsoft.AspNetCore -import experimental.dataflow.flowsources.AuthCookie +import security.dataflow.flowsources.AuthCookie from Expr secureSink where diff --git a/csharp/src/security/CWE-759/HashWithoutSalt.ql b/csharp/src/security/CWE-759/HashWithoutSalt.ql index f9c279e0..ae055acc 100644 --- a/csharp/src/security/CWE-759/HashWithoutSalt.ql +++ b/csharp/src/security/CWE-759/HashWithoutSalt.ql @@ -3,9 +3,8 @@ * @description Hashed passwords without a salt are vulnerable to dictionary attacks. * @kind path-problem * @problem.severity error - * @id cs/hash-without-salt + * @id githubsecuritylab/cs/hash-without-salt * @tags security - * experimental * external/cwe/cwe-759 */ diff --git a/csharp/src/security/CWE-918/RequestForgery.ql b/csharp/src/security/CWE-918/RequestForgery.ql index 9f59da7e..c9dda9ab 100644 --- a/csharp/src/security/CWE-918/RequestForgery.ql +++ b/csharp/src/security/CWE-918/RequestForgery.ql @@ -4,9 +4,8 @@ * @kind path-problem * @problem.severity error * @precision high - * @id cs/request-forgery + * @id githubsecuritylab/cs/request-forgery * @tags security - * experimental * external/cwe/cwe-918 */ diff --git a/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql b/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql index 39aaa809..8cc56f41 100644 --- a/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql +++ b/csharp/src/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql @@ -4,10 +4,9 @@ * Higher precision version checks for exception throws, so less false positives are expected. * @kind problem * @tags security - * experimental * JsonWebTokenHandler * manual-verification-required - * @id cs/json-webtoken-handler/delegated-security-validations-always-return-true + * @id githubsecuritylab/cs/json-webtoken-handler/delegated-security-validations-always-return-true * @problem.severity error * @precision high */ diff --git a/csharp/src/security/JsonWebTokenHandler/security-validation-disabled.ql b/csharp/src/security/JsonWebTokenHandler/security-validation-disabled.ql index 679e6c3b..a01a8553 100644 --- a/csharp/src/security/JsonWebTokenHandler/security-validation-disabled.ql +++ b/csharp/src/security/JsonWebTokenHandler/security-validation-disabled.ql @@ -3,10 +3,9 @@ * @description Check if security sensitive token validations for `JsonWebTokenHandler` are being disabled. * @kind problem * @tags security - * experimental * JsonWebTokenHandler * manual-verification-required - * @id cs/json-webtoken-handler/security-validations-disabled + * @id githubsecuritylab/cs/json-webtoken-handler/security-validations-disabled * @problem.severity error * @precision high */ diff --git a/csharp/src/security/Serialization/DefiningDatasetRelatedType.ql b/csharp/src/security/Serialization/DefiningDatasetRelatedType.ql index 47153f92..381cd67f 100644 --- a/csharp/src/security/Serialization/DefiningDatasetRelatedType.ql +++ b/csharp/src/security/Serialization/DefiningDatasetRelatedType.ql @@ -3,9 +3,8 @@ * @description Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types may lead to the usage of dangerous functionality. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. * @kind problem * @problem.severity warning - * @id cs/dataset-serialization/defining-dataset-related-type + * @id githubsecuritylab/cs/dataset-serialization/defining-dataset-related-type * @tags security - * experimental */ import csharp diff --git a/csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql b/csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql index 0e87f724..d3f97d2b 100644 --- a/csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql +++ b/csharp/src/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql @@ -4,9 +4,8 @@ * @kind problem * @problem.severity error * @precision medium - * @id cs/dataset-serialization/defining-potentially-unsafe-xml-serializer + * @id githubsecuritylab/cs/dataset-serialization/defining-potentially-unsafe-xml-serializer * @tags security - * experimental */ import csharp diff --git a/csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.ql b/csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.ql index 74eea145..aa87c99a 100644 --- a/csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.ql +++ b/csharp/src/security/Serialization/UnsafeTypeUsedDataContractSerializer.ql @@ -4,9 +4,8 @@ * @kind problem * @problem.severity error * @precision medium - * @id cs/dataset-serialization/unsafe-type-used-data-contract-serializer + * @id githubsecuritylab/cs/dataset-serialization/unsafe-type-used-data-contract-serializer * @tags security - * experimental */ import csharp diff --git a/csharp/src/security/Serialization/XmlDeserializationWithDataSet.ql b/csharp/src/security/Serialization/XmlDeserializationWithDataSet.ql index fbcba87b..ad03d9d8 100644 --- a/csharp/src/security/Serialization/XmlDeserializationWithDataSet.ql +++ b/csharp/src/security/Serialization/XmlDeserializationWithDataSet.ql @@ -4,9 +4,8 @@ * @kind problem * @problem.severity error * @precision medium - * @id cs/dataset-serialization/xml-deserialization-with-dataset + * @id githubsecuritylab/cs/dataset-serialization/xml-deserialization-with-dataset * @tags security - * experimental */ import csharp diff --git a/csharp/src/security/backdoor/DangerousNativeFunctionCall.ql b/csharp/src/security/backdoor/DangerousNativeFunctionCall.ql index b0f066ba..44cd8860 100644 --- a/csharp/src/security/backdoor/DangerousNativeFunctionCall.ql +++ b/csharp/src/security/backdoor/DangerousNativeFunctionCall.ql @@ -4,9 +4,8 @@ * @kind problem * @problem.severity warning * @precision low - * @id cs/backdoor/dangerous-native-functions + * @id githubsecuritylab/cs/backdoor/dangerous-native-functions * @tags security - * experimental * solorigate */ diff --git a/csharp/src/security/backdoor/PotentialTimeBomb.ql b/csharp/src/security/backdoor/PotentialTimeBomb.ql index 47b69d3e..0a2536f1 100644 --- a/csharp/src/security/backdoor/PotentialTimeBomb.ql +++ b/csharp/src/security/backdoor/PotentialTimeBomb.ql @@ -2,11 +2,10 @@ * @name Potential Timebomb * @description If there is data flow from a file's last modification date and an offset to a condition statement, this could trigger a "time bomb". * @kind path-problem - * @precision Low + * @precision low * @problem.severity warning - * @id cs/backdoor/potential-time-bomb + * @id githubsecuritylab/cs/backdoor/potential-time-bomb * @tags security - * experimental * solorigate */ diff --git a/csharp/src/security/backdoor/ProcessNameToHashTaintFlow.ql b/csharp/src/security/backdoor/ProcessNameToHashTaintFlow.ql index 2835ac19..94959f6e 100644 --- a/csharp/src/security/backdoor/ProcessNameToHashTaintFlow.ql +++ b/csharp/src/security/backdoor/ProcessNameToHashTaintFlow.ql @@ -3,11 +3,10 @@ * @description Flow from a function retrieving process name to a hash function. * @kind path-problem * @tags security - * experimental * solorigate * @problem.severity warning * @precision medium - * @id cs/backdoor/process-name-to-hash-function + * @id githubsecuritylab/cs/backdoor/process-name-to-hash-function */ import csharp From 94cba02a43b62c7d13063eb4af0504cc85357761 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 4 Nov 2024 10:28:46 +0100 Subject: [PATCH 5/5] C#: Update all qlref files to point at the ql files in the community pack repo. --- .../CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.qlref | 2 +- .../CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.qlref | 2 +- .../UseCookiePolicyCallback/HttpOnly.qlref | 2 +- .../CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.qlref | 2 +- .../CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.qlref | 2 +- .../UseCookiePolicyAlways/HttpOnly.qlref | 2 +- .../UseCookiePolicyCallback/HttpOnly.qlref | 2 +- .../UseCookiePolicyNone/HttpOnly.qlref | 2 +- .../CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.qlref | 2 +- .../CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.qlref | 2 +- .../HttpCookiesTrue/HttpOnly.qlref | 2 +- .../CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.qlref | 2 +- .../RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.qlref | 2 +- .../UseCookiePolicyCallback/RequireSSL.qlref | 2 +- .../RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.qlref | 2 +- .../RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.qlref | 2 +- .../CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.qlref | 2 +- .../UseCookiePolicyCallback/RequireSSL.qlref | 2 +- .../security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.qlref | 2 +- .../CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.qlref | 2 +- .../CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.qlref | 2 +- .../CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.qlref | 2 +- .../RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.qlref | 2 +- csharp/test/security/CWE-759/HashWithoutSalt.qlref | 2 +- csharp/test/security/CWE-918/RequestForgery.qlref | 2 +- .../delegated-security-validations-always-return-true.qlref | 2 +- .../JsonWebTokenHandler/security-validation-disabled.qlref | 2 +- .../security/Serialization/DefiningDatasetRelatedType.qlref | 2 +- .../Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref | 2 +- .../Serialization/UnsafeTypeUsedDataContractSerializer.qlref | 2 +- .../security/Serialization/XmlDeserializationWithDataSet.qlref | 2 +- csharp/test/security/backdoor/DangerousNativeFunctionCall.qlref | 2 +- csharp/test/security/backdoor/PotentialTimeBomb.qlref | 2 +- csharp/test/security/backdoor/ProcessNameToHashTaintFlow.qlref | 2 +- 34 files changed, 34 insertions(+), 34 deletions(-) diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/CookieBuilder/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/NoPolicy/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieHttpOnlyFalseSystemWeb/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/NoPolicy/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyAlways/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyCallback/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlyAspNetCore/UseCookiePolicyNone/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigEmpty/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/ConfigFalse/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.qlref b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.qlref index 91ce2260..d3a7f514 100644 --- a/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.qlref +++ b/csharp/test/security/CWE-1004/CookieWithoutHttpOnlySystemWeb/HttpCookiesTrue/HttpOnly.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file +security/CWE-1004/CookieWithoutHttpOnly.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/NoPolicy/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyAlways/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLAspNetCore/UseCookiePolicyNone/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/CookieBuilder/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/NoPolicy/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLFalseAspNetCore/UseCookiePolicyCallback/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLFalseSystemWeb/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigEmpty/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/ConfigFalse/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/FormsTrue/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.qlref b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.qlref index f76146a8..5c0c8afa 100644 --- a/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.qlref +++ b/csharp/test/security/CWE-614/RequireSSLSystemWeb/HttpCookiesTrue/RequireSSL.qlref @@ -1 +1 @@ -experimental/Security Features/CWE-614/CookieWithoutSecure.ql \ No newline at end of file +security/CWE-614/CookieWithoutSecure.ql \ No newline at end of file diff --git a/csharp/test/security/CWE-759/HashWithoutSalt.qlref b/csharp/test/security/CWE-759/HashWithoutSalt.qlref index 6489a340..032c83eb 100644 --- a/csharp/test/security/CWE-759/HashWithoutSalt.qlref +++ b/csharp/test/security/CWE-759/HashWithoutSalt.qlref @@ -1,2 +1,2 @@ -query: experimental/Security Features/CWE-759/HashWithoutSalt.ql +query: security/CWE-759/HashWithoutSalt.ql postprocess: TestUtilities/PrettyPrintModels.ql diff --git a/csharp/test/security/CWE-918/RequestForgery.qlref b/csharp/test/security/CWE-918/RequestForgery.qlref index 3d529ae5..31051491 100644 --- a/csharp/test/security/CWE-918/RequestForgery.qlref +++ b/csharp/test/security/CWE-918/RequestForgery.qlref @@ -1 +1 @@ -experimental/CWE-918/RequestForgery.ql \ No newline at end of file +security/CWE-918/RequestForgery.ql \ No newline at end of file diff --git a/csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref b/csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref index 527ea925..82dd3f42 100644 --- a/csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref +++ b/csharp/test/security/JsonWebTokenHandler/delegated-security-validations-always-return-true.qlref @@ -1 +1 @@ -experimental/Security Features/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql \ No newline at end of file +security/JsonWebTokenHandler/delegated-security-validations-always-return-true.ql \ No newline at end of file diff --git a/csharp/test/security/JsonWebTokenHandler/security-validation-disabled.qlref b/csharp/test/security/JsonWebTokenHandler/security-validation-disabled.qlref index ee07957f..1db68e48 100644 --- a/csharp/test/security/JsonWebTokenHandler/security-validation-disabled.qlref +++ b/csharp/test/security/JsonWebTokenHandler/security-validation-disabled.qlref @@ -1 +1 @@ -experimental/Security Features/JsonWebTokenHandler/security-validation-disabled.ql \ No newline at end of file +security/JsonWebTokenHandler/security-validation-disabled.ql \ No newline at end of file diff --git a/csharp/test/security/Serialization/DefiningDatasetRelatedType.qlref b/csharp/test/security/Serialization/DefiningDatasetRelatedType.qlref index 7283db95..aaea4577 100644 --- a/csharp/test/security/Serialization/DefiningDatasetRelatedType.qlref +++ b/csharp/test/security/Serialization/DefiningDatasetRelatedType.qlref @@ -1 +1 @@ -experimental/Security Features/Serialization/DefiningDatasetRelatedType.ql \ No newline at end of file +security/Serialization/DefiningDatasetRelatedType.ql \ No newline at end of file diff --git a/csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref b/csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref index 8a8632c6..75bef77d 100644 --- a/csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref +++ b/csharp/test/security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.qlref @@ -1 +1 @@ -experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql \ No newline at end of file +security/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql \ No newline at end of file diff --git a/csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.qlref b/csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.qlref index 1593497c..9322ab86 100644 --- a/csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.qlref +++ b/csharp/test/security/Serialization/UnsafeTypeUsedDataContractSerializer.qlref @@ -1 +1 @@ -experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.ql \ No newline at end of file +security/Serialization/UnsafeTypeUsedDataContractSerializer.ql \ No newline at end of file diff --git a/csharp/test/security/Serialization/XmlDeserializationWithDataSet.qlref b/csharp/test/security/Serialization/XmlDeserializationWithDataSet.qlref index 8054e46f..85e8043a 100644 --- a/csharp/test/security/Serialization/XmlDeserializationWithDataSet.qlref +++ b/csharp/test/security/Serialization/XmlDeserializationWithDataSet.qlref @@ -1 +1 @@ -experimental/Security Features/Serialization/XmlDeserializationWithDataSet.ql \ No newline at end of file +security/Serialization/XmlDeserializationWithDataSet.ql \ No newline at end of file diff --git a/csharp/test/security/backdoor/DangerousNativeFunctionCall.qlref b/csharp/test/security/backdoor/DangerousNativeFunctionCall.qlref index 1215c001..40ba1a5d 100644 --- a/csharp/test/security/backdoor/DangerousNativeFunctionCall.qlref +++ b/csharp/test/security/backdoor/DangerousNativeFunctionCall.qlref @@ -1 +1 @@ -experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql \ No newline at end of file +security/backdoor/DangerousNativeFunctionCall.ql \ No newline at end of file diff --git a/csharp/test/security/backdoor/PotentialTimeBomb.qlref b/csharp/test/security/backdoor/PotentialTimeBomb.qlref index f76817aa..b0fbe16a 100644 --- a/csharp/test/security/backdoor/PotentialTimeBomb.qlref +++ b/csharp/test/security/backdoor/PotentialTimeBomb.qlref @@ -1 +1 @@ -experimental/Security Features/backdoor/PotentialTimeBomb.ql \ No newline at end of file +security/backdoor/PotentialTimeBomb.ql \ No newline at end of file diff --git a/csharp/test/security/backdoor/ProcessNameToHashTaintFlow.qlref b/csharp/test/security/backdoor/ProcessNameToHashTaintFlow.qlref index d1d0d520..636c46fc 100644 --- a/csharp/test/security/backdoor/ProcessNameToHashTaintFlow.qlref +++ b/csharp/test/security/backdoor/ProcessNameToHashTaintFlow.qlref @@ -1 +1 @@ -experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql \ No newline at end of file +security/backdoor/ProcessNameToHashTaintFlow.ql \ No newline at end of file