Skip to content

Commit 3037c79

Browse files
committed
Add changelog
Fix issues Change this
1 parent a4fb0e0 commit 3037c79

11 files changed

+390
-33
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* C#: Added `ccs/web/cors-misconfiguration` queries which looks for CORS misconfigurations with and without credentials.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>
8+
9+
A server can send the
10+
<code>"Access-Control-Allow-Credentials"</code> CORS header to control
11+
when a browser may send user credentials in Cross-Origin HTTP
12+
requests.
13+
14+
</p>
15+
<p>
16+
17+
When the <code>Access-Control-Allow-Credentials</code> header
18+
is <code>"true"</code>, the <code>Access-Control-Allow-Origin</code>
19+
header must have a value different from <code>"*"</code> in order to
20+
make browsers accept the header. Therefore, to allow multiple origins
21+
for Cross-Origin requests with credentials, the server must
22+
dynamically compute the value of the
23+
<code>"Access-Control-Allow-Origin"</code> header. Computing this
24+
header value from information in the request to the server can
25+
therefore potentially allow an attacker to control the origins that
26+
the browser sends credentials to.
27+
28+
</p>
29+
30+
31+
32+
</overview>
33+
34+
<recommendation>
35+
<p>
36+
37+
When the <code>Access-Control-Allow-Credentials</code> header
38+
value is <code>"true"</code>, a dynamic computation of the
39+
<code>Access-Control-Allow-Origin</code> header must involve
40+
sanitization if it relies on user-controlled input.
41+
42+
43+
</p>
44+
<p>
45+
46+
Since the <code>"null"</code> origin is easy to obtain for an
47+
attacker, it is never safe to use <code>"null"</code> as the value of
48+
the <code>Access-Control-Allow-Origin</code> header when the
49+
<code>Access-Control-Allow-Credentials</code> header value is
50+
<code>"true"</code>.
51+
52+
</p>
53+
</recommendation>
54+
55+
<example>
56+
<p>
57+
58+
In the example below, the server allows the browser to send
59+
user credentials in a Cross-Origin request. The request header
60+
<code>origins</code> controls the allowed origins for such a
61+
Cross-Origin request.
62+
63+
</p>
64+
65+
<sample src="examples/CorsBad.cs"/>
66+
67+
<p>
68+
69+
This is not secure, since an attacker can choose the value of
70+
the <code>origin</code> request header to make the browser send
71+
credentials to their own server. The use of a allowlist containing
72+
allowed origins for the Cross-Origin request fixes the issue:
73+
74+
</p>
75+
76+
<sample src="examples/CorsGood.cs"/>
77+
</example>
78+
79+
<references>
80+
<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin">CORS, Access-Control-Allow-Origin</a>.</li>
81+
<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials">CORS, Access-Control-Allow-Credentials</a>.</li>
82+
<li>PortSwigger: <a href="http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html">Exploiting CORS Misconfigurations for Bitcoins and Bounties</a></li>
83+
<li>W3C: <a href="https://w3c.github.io/webappsec-cors-for-developers/#resources">CORS for developers, Advice for Resource Owners</a></li>
84+
</references>
85+
</qhelp>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* @name CORS misconfiguration
3+
* @description Keeping an open CORS policy may result in security issues as third party website may be able to
4+
* access other websites.
5+
* @kind problem
6+
* @problem.severity error
7+
* @security-severity 7.5
8+
* @precision high
9+
* @id cs/web/cors-misconfiguration
10+
* @tags security
11+
* external/cwe/cwe-942
12+
*/
13+
14+
import csharp
15+
private import DataFlow
16+
import semmle.code.csharp.frameworks.system.Web
17+
18+
/**
19+
* Holds if SetIsOriginAllowed always returns true. This sets the Access-Control-Allow-Origin to the requester
20+
*/
21+
private predicate functionAlwaysReturnsTrue(MethodCall mc) {
22+
mc.getTarget()
23+
.hasFullyQualifiedName("Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder",
24+
"SetIsOriginAllowed") and
25+
alwaysReturnsTrue(mc.getArgument(0))
26+
}
27+
28+
/**
29+
* Holds if `c` always returns `true`.
30+
*/
31+
private predicate alwaysReturnsTrue(Callable c) {
32+
forex(ReturnStmt rs | rs.getEnclosingCallable() = c |
33+
rs.getExpr().(BoolLiteral).getBoolValue() = true
34+
)
35+
or
36+
c.getBody().(BoolLiteral).getBoolValue() = true
37+
}
38+
39+
/**
40+
* Holds if the application uses a vulnerable CORS policy.
41+
*/
42+
private predicate hasDangerousOrigins(MethodCall m) {
43+
m.getTarget()
44+
.hasFullyQualifiedName("Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder",
45+
"WithOrigins") and
46+
m.getAnArgument().getValue() = ["null", "*"]
47+
}
48+
49+
/**
50+
* Holds if the application allows an origin using "*" origin.
51+
*/
52+
private predicate allowAnyOrigin(MethodCall m) {
53+
m.getTarget()
54+
.hasFullyQualifiedName("Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder",
55+
"AllowAnyOrigin")
56+
}
57+
58+
/**
59+
* Holds if UseCors is called with the revlevant cors policy
60+
*/
61+
private predicate configIsUsed(MethodCall add_policy) {
62+
exists(MethodCall uc |
63+
uc.getTarget()
64+
.hasFullyQualifiedName("Microsoft.AspNetCore.Builder.CorsMiddlewareExtensions", "UseCors") and
65+
(
66+
uc.getArgument(1).getValue() = add_policy.getArgument(0).getValue() or
67+
localFlow(DataFlow::exprNode(add_policy.getArgument(0)), DataFlow::exprNode(uc.getArgument(1)))
68+
)
69+
)
70+
}
71+
72+
from MethodCall add_policy, MethodCall m
73+
where
74+
(
75+
add_policy
76+
.getTarget()
77+
.hasFullyQualifiedName("Microsoft.AspNetCore.Cors.Infrastructure.CorsOptions", "AddPolicy") and
78+
add_policy.getArgument(1) = m.getParent*() and
79+
configIsUsed(add_policy)
80+
or
81+
add_policy
82+
.getTarget()
83+
.hasFullyQualifiedName("Microsoft.AspNetCore.Cors.Infrastructure.CorsOptions",
84+
"AddDefaultPolicy") and
85+
add_policy.getArgument(0) = m.getParent*()
86+
) and
87+
(hasDangerousOrigins(m) or allowAnyOrigin(m) or functionAlwaysReturnsTrue(m))
88+
select add_policy, "The following CORS policy may be vulnerable to 3rd party websites"
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* @name Credentialed CORS Misconfiguration
3+
* @description Allowing any origin while allowing credentials may result in security issues as third party website may be able to
4+
* access private resources.
5+
* @kind problem
6+
* @problem.severity error
7+
* @security-severity 7.5
8+
* @precision high
9+
* @id cs/web/cors-misconfiguration-credentials
10+
* @tags security
11+
* external/cwe/cwe-942
12+
*/
13+
14+
import csharp
15+
private import DataFlow
16+
import semmle.code.csharp.frameworks.system.Web
17+
18+
/**
19+
* Holds if credentials are allowed
20+
*/
21+
private predicate allowsCredentials(MethodCall credentials) {
22+
credentials
23+
.getTarget()
24+
.hasFullyQualifiedName("Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder",
25+
"AllowCredentials")
26+
}
27+
28+
/**
29+
* Holds if SetIsOriginAllowed always returns true. This sets the Access-Control-Allow-Origin to the requester
30+
*/
31+
private predicate functionAlwaysReturnsTrue(MethodCall mc) {
32+
mc.getTarget()
33+
.hasFullyQualifiedName("Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder",
34+
"SetIsOriginAllowed") and
35+
alwaysReturnsTrue(mc.getArgument(0))
36+
}
37+
38+
/**
39+
* Holds if `c` always returns `true`.
40+
*/
41+
private predicate alwaysReturnsTrue(Callable c) {
42+
forex(ReturnStmt rs | rs.getEnclosingCallable() = c |
43+
rs.getExpr().(BoolLiteral).getBoolValue() = true
44+
)
45+
or
46+
c.getBody().(BoolLiteral).getBoolValue() = true
47+
}
48+
49+
/**
50+
* Holds if UseCors is called with the revlevant cors policy
51+
*/
52+
private predicate configIsUsed(MethodCall add_policy) {
53+
exists(MethodCall uc |
54+
uc.getTarget()
55+
.hasFullyQualifiedName("Microsoft.AspNetCore.Builder.CorsMiddlewareExtensions", "UseCors") and
56+
(
57+
uc.getArgument(1).getValue() = add_policy.getArgument(0).getValue() or
58+
uc.getArgument(1).(VariableAccess).getTarget() =
59+
add_policy.getArgument(0).(VariableAccess).getTarget() or
60+
localFlow(DataFlow::exprNode(add_policy.getArgument(0)), DataFlow::exprNode(uc.getArgument(1)))
61+
)
62+
)
63+
}
64+
65+
from MethodCall add_policy, MethodCall m, MethodCall allowsCredentials
66+
where
67+
(
68+
add_policy
69+
.getTarget()
70+
.hasFullyQualifiedName("Microsoft.AspNetCore.Cors.Infrastructure.CorsOptions", "AddPolicy") and
71+
add_policy.getArgument(1) = m.getParent*() and
72+
configIsUsed(add_policy) and
73+
add_policy.getArgument(1) = allowsCredentials.getParent*()
74+
or
75+
add_policy
76+
.getTarget()
77+
.hasFullyQualifiedName("Microsoft.AspNetCore.Cors.Infrastructure.CorsOptions",
78+
"AddDefaultPolicy") and
79+
add_policy.getArgument(0) = m.getParent*() and
80+
add_policy.getArgument(0) = allowsCredentials.getParent*()
81+
) and
82+
(allowsCredentials(allowsCredentials) and functionAlwaysReturnsTrue(m))
83+
select add_policy,
84+
"The following CORS policy may allow credentialed requests from 3rd party websites"
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using Leaf.Middlewares;
2+
using Microsoft.AspNetCore.Builder;
3+
using Microsoft.AspNetCore.Hosting;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.Hosting;
7+
8+
namespace Leaf
9+
{
10+
public class Startup
11+
{
12+
public Startup(IConfiguration configuration)
13+
{
14+
Configuration = configuration;
15+
}
16+
17+
public IConfiguration Configuration { get; }
18+
19+
// This method gets called by the runtime. Use this method to add services to the container.
20+
public void ConfigureServices(IServiceCollection services)
21+
{
22+
services.AddControllers();
23+
//services.AddTransient<MySqlConnection>(_ => new MySqlConnection(Configuration["ConnectionStrings:Default"]));
24+
services.AddControllersWithViews()
25+
.AddNewtonsoftJson(options =>
26+
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
27+
);
28+
29+
services.AddCors(options => {
30+
options.AddPolicy("AllowPolicy", builder => builder
31+
.WithOrigins("null")
32+
.AllowCredentials()
33+
.AllowAnyMethod()
34+
.AllowAnyHeader());
35+
});
36+
37+
}
38+
39+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
40+
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
41+
{
42+
app.UseRouting();
43+
44+
app.UseCors("AllowPolicy");
45+
46+
app.UseRequestResponseLogging();
47+
48+
if (env.IsDevelopment())
49+
{
50+
app.UseDeveloperExceptionPage();
51+
}
52+
53+
app.UseHttpsRedirection();
54+
55+
app.UseAuthorization();
56+
57+
app.UseEndpoints(endpoints =>
58+
{
59+
endpoints.MapControllers();
60+
});
61+
62+
}
63+
}
64+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using Leaf.Middlewares;
2+
using Microsoft.AspNetCore.Builder;
3+
using Microsoft.AspNetCore.Hosting;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.Hosting;
7+
8+
namespace Leaf
9+
{
10+
public class Startup
11+
{
12+
public Startup(IConfiguration configuration)
13+
{
14+
Configuration = configuration;
15+
}
16+
17+
public IConfiguration Configuration { get; }
18+
19+
// This method gets called by the runtime. Use this method to add services to the container.
20+
public void ConfigureServices(IServiceCollection services)
21+
{
22+
services.AddControllers();
23+
//services.AddTransient<MySqlConnection>(_ => new MySqlConnection(Configuration["ConnectionStrings:Default"]));
24+
services.AddControllersWithViews()
25+
.AddNewtonsoftJson(options =>
26+
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
27+
);
28+
29+
services.AddCors(options => {
30+
options.AddPolicy("AllowPolicy", builder => builder
31+
.WithOrigins("http://example.com")
32+
.AllowCredentials()
33+
.AllowAnyMethod()
34+
.AllowAnyHeader());
35+
});
36+
37+
}
38+
39+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
40+
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
41+
{
42+
app.UseRouting();
43+
44+
app.UseCors("AllowPolicy");
45+
46+
app.UseRequestResponseLogging();
47+
48+
if (env.IsDevelopment())
49+
{
50+
app.UseDeveloperExceptionPage();
51+
}
52+
53+
app.UseHttpsRedirection();
54+
55+
app.UseAuthorization();
56+
57+
app.UseEndpoints(endpoints =>
58+
{
59+
endpoints.MapControllers();
60+
});
61+
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)