-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14873 from Kwstubbs/go-rs-cors
Go: Add Rs Cors Support
- Loading branch information
Showing
10 changed files
with
302 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
category: minorAnalysis | ||
--- | ||
* Added the [rs cors](https://github.com/rs/cors) library to the CorsMisconfiguration.ql query |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
/** | ||
* Provides classes for modeling the `github.com/rs/cors` package. | ||
*/ | ||
|
||
import go | ||
|
||
/** | ||
* An abstract class for modeling the Go CORS handler model origin write. | ||
*/ | ||
abstract class UniversalOriginWrite extends DataFlow::ExprNode { | ||
/** | ||
* Get config variable holding header values | ||
*/ | ||
abstract DataFlow::Node getBase(); | ||
|
||
/** | ||
* Get config variable holding header values | ||
*/ | ||
abstract Variable getConfig(); | ||
} | ||
|
||
/** | ||
* An abstract class for modeling the Go CORS handler model allow all origins write. | ||
*/ | ||
abstract class UniversalAllowAllOriginsWrite extends DataFlow::ExprNode { | ||
/** | ||
* Get config variable holding header values | ||
*/ | ||
abstract DataFlow::Node getBase(); | ||
|
||
/** | ||
* Get config variable holding header values | ||
*/ | ||
abstract Variable getConfig(); | ||
} | ||
|
||
/** | ||
* An abstract class for modeling the Go CORS handler model allow credentials write. | ||
*/ | ||
abstract class UniversalAllowCredentialsWrite extends DataFlow::ExprNode { | ||
/** | ||
* Get config struct holding header values | ||
*/ | ||
abstract DataFlow::Node getBase(); | ||
|
||
/** | ||
* Get config variable holding header values | ||
*/ | ||
abstract Variable getConfig(); | ||
} | ||
|
||
/** | ||
* Provides classes for modeling the `github.com/rs/cors` package. | ||
*/ | ||
module RsCors { | ||
/** Gets the package name `github.com/gin-gonic/gin`. */ | ||
string packagePath() { result = package("github.com/rs/cors", "") } | ||
|
||
/** | ||
* A new function create a new rs Handler | ||
*/ | ||
class New extends Function { | ||
New() { exists(Function f | f.hasQualifiedName(packagePath(), "New") | this = f) } | ||
} | ||
|
||
/** | ||
* A write to the value of Access-Control-Allow-Credentials header | ||
*/ | ||
class AllowCredentialsWrite extends UniversalAllowCredentialsWrite { | ||
DataFlow::Node base; | ||
|
||
AllowCredentialsWrite() { | ||
exists(Field f, Write w | | ||
f.hasQualifiedName(packagePath(), "Options", "AllowCredentials") and | ||
w.writesField(base, f, this) and | ||
this.getType() instanceof BoolType | ||
) | ||
} | ||
|
||
/** | ||
* Get options struct holding header values | ||
*/ | ||
override DataFlow::Node getBase() { result = base } | ||
|
||
/** | ||
* Get options variable holding header values | ||
*/ | ||
override RsOptions getConfig() { | ||
exists(RsOptions gc | | ||
( | ||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() = | ||
base.asInstruction() or | ||
gc.getV().getAUse() = base | ||
) and | ||
result = gc | ||
) | ||
} | ||
} | ||
|
||
/** | ||
* A write to the value of Access-Control-Allow-Origins header | ||
*/ | ||
class AllowOriginsWrite extends UniversalOriginWrite { | ||
DataFlow::Node base; | ||
|
||
AllowOriginsWrite() { | ||
exists(Field f, Write w | | ||
f.hasQualifiedName(packagePath(), "Options", "AllowedOrigins") and | ||
w.writesField(base, f, this) and | ||
this.asExpr() instanceof SliceLit | ||
) | ||
} | ||
|
||
/** | ||
* Get options struct holding header values | ||
*/ | ||
override DataFlow::Node getBase() { result = base } | ||
|
||
/** | ||
* Get options variable holding header values | ||
*/ | ||
override RsOptions getConfig() { | ||
exists(RsOptions gc | | ||
( | ||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() = | ||
base.asInstruction() or | ||
gc.getV().getAUse() = base | ||
) and | ||
result = gc | ||
) | ||
} | ||
} | ||
|
||
/** | ||
* A write to the value of Access-Control-Allow-Origins of value "*", overriding AllowOrigins | ||
*/ | ||
class AllowAllOriginsWrite extends UniversalAllowAllOriginsWrite { | ||
DataFlow::Node base; | ||
|
||
AllowAllOriginsWrite() { | ||
exists(Field f, Write w | | ||
f.hasQualifiedName(packagePath(), "Options", "AllowAllOrigins") and | ||
w.writesField(base, f, this) and | ||
this.getType() instanceof BoolType | ||
) | ||
} | ||
|
||
/** | ||
* Get options struct holding header values | ||
*/ | ||
override DataFlow::Node getBase() { result = base } | ||
|
||
/** | ||
* Get options variable holding header values | ||
*/ | ||
override RsOptions getConfig() { | ||
exists(RsOptions gc | | ||
( | ||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() = | ||
base.asInstruction() or | ||
gc.getV().getAUse() = base | ||
) and | ||
result = gc | ||
) | ||
} | ||
} | ||
|
||
/** | ||
* A variable of type Options that holds the headers to be set. | ||
*/ | ||
class RsOptions extends Variable { | ||
SsaWithFields v; | ||
|
||
RsOptions() { | ||
this = v.getBaseVariable().getSourceVariable() and | ||
exists(Type t | t.hasQualifiedName(packagePath(), "Options") | v.getType() = t) | ||
} | ||
|
||
/** | ||
* Get variable declaration of Options | ||
*/ | ||
SsaWithFields getV() { result = v } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/rs/cors" | ||
) | ||
|
||
func rs_vulnerable() { | ||
c := cors.New(cors.Options{ | ||
AllowedOrigins: []string{"null", "http://foo.com:8080"}, | ||
AllowCredentials: true, | ||
// Enable Debugging for testing, consider disabling in production | ||
Debug: true, | ||
}) | ||
|
||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
w.Header().Set("Content-Type", "application/json") | ||
w.Write([]byte("{\"hello\": \"world\"}")) | ||
}) | ||
|
||
http.ListenAndServe(":8080", c.Handler(handler)) | ||
} | ||
|
||
func rs_safe() { | ||
c := cors.New(cors.Options{ | ||
AllowedOrigins: []string{"http://foo.com:8080"}, | ||
AllowCredentials: true, | ||
// Enable Debugging for testing, consider disabling in production | ||
Debug: true, | ||
}) | ||
|
||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
w.Header().Set("Content-Type", "application/json") | ||
w.Write([]byte("{\"hello\": \"world\"}")) | ||
}) | ||
|
||
http.ListenAndServe(":8080", c.Handler(handler)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.