Merge pull request #68 from adityasharad/go/request-forgery

Add experimental query for request forgery.
This commit is contained in:
Max Schaefer
2020-03-25 09:09:34 +00:00
committed by GitHub
5 changed files with 166 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
/**
* @name Uncontrolled data used in network request
* @description Sending network requests with user-controlled data allows for request forgery attacks.
* @kind path-problem
* @problem.severity error
* @id go/request-forgery
* @tags security
* external/cwe/cwe-918
*/
import go
import RequestForgery::RequestForgery
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node request
where
cfg.hasFlowPath(source, sink) and
request = sink.getNode().(Sink).getARequest()
select request, source, sink, "The $@ of this request depends on $@.", sink.getNode(),
sink.getNode().(Sink).getKind(), source, "a user-provided value"

View File

@@ -0,0 +1,35 @@
/**
* Provides a taint-tracking configuration for reasoning about request forgery
* (SSRF) vulnerabilities.
*/
import go
module RequestForgery {
import RequestForgeryCustomizations::RequestForgery
/**
* A taint-tracking configuration for reasoning about request forgery.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "RequestForgery" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) {
super.isSanitizer(node) or
node instanceof Sanitizer
}
override predicate isSanitizerOut(DataFlow::Node node) {
super.isSanitizerOut(node) or
node instanceof SanitizerEdge
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
super.isSanitizerGuard(guard) or guard instanceof SanitizerGuard
}
}
}

View File

@@ -0,0 +1,57 @@
/**
* Provides classes and predicates used by the request forgery query.
*/
import go
import semmle.go.security.UrlConcatenation
/** Provides classes and predicates for the request forgery query. */
module RequestForgery {
/** A data flow source for request forgery vulnerabilities. */
abstract class Source extends DataFlow::Node { }
/** A data flow sink for request forgery vulnerabilities. */
abstract class Sink extends DataFlow::Node {
/** Gets a request that uses this sink. */
abstract DataFlow::Node getARequest();
/**
* Gets the name of a part of the request that may be tainted by this sink,
* such as the URL or the host.
*/
abstract string getKind();
}
/** A sanitizer for request forgery vulnerabilities. */
abstract class Sanitizer extends DataFlow::Node { }
/** An outgoing sanitizer edge for request forgery vulnerabilities. */
abstract class SanitizerEdge extends DataFlow::Node { }
/**
* A sanitizer guard for request forgery vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A third-party controllable input, considered as a flow source for request forgery.
*/
class UntrustedFlowAsSource extends Source, UntrustedFlowSource { }
/**
* The URL of a URL request, viewed as a sink for request forgery.
*/
private class ClientRequestUrlAsSink extends Sink {
HTTP::ClientRequest request;
ClientRequestUrlAsSink() { this = request.getUrl() }
override DataFlow::Node getARequest() { result = request }
override string getKind() { result = "URL" }
}
private class HostnameSanitizer extends SanitizerEdge {
HostnameSanitizer() { hostnameSanitizingPrefixEdge(this, _) }
}
}

View File

@@ -527,6 +527,43 @@ module HTTP {
ResponseWriter getResponseWriter() { result = self.getResponseWriter() }
}
/** Provides a class for modeling new HTTP client request APIs. */
module ClientRequest {
/**
* A call that performs a request to a URL.
*
* Example: An HTTP POST request is a client request that sends some
* `data` to a `url`, where both the headers and the body of the request
* contribute to the `data`.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `HTTP::ClientRequest` instead.
*/
abstract class Range extends DataFlow::Node {
/**
* Gets the URL of the request.
*/
abstract DataFlow::Node getUrl();
}
}
/**
* A call that performs a request to a URL.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `HTTP::ClientRequest::Range` instead.
*/
class ClientRequest extends DataFlow::Node {
ClientRequest::Range self;
ClientRequest() { this = self }
/**
* Gets the URL of the request.
*/
DataFlow::Node getUrl() { result = self.getUrl() }
}
/** Provides a class for modeling new HTTP redirect APIs. */
module Redirect {
/**

View File

@@ -147,4 +147,21 @@ private module StdlibHttp {
override HTTP::ResponseWriter getResponseWriter() { result.getANode() = this.getArgument(0) }
}
/** A call to a function in the `net/http` package that performs an HTTP request to a URL. */
private class RequestCall extends HTTP::ClientRequest::Range, DataFlow::CallNode {
RequestCall() {
exists(string functionName |
(
this.getTarget().hasQualifiedName("net/http", functionName)
or
this.getTarget().(Method).hasQualifiedName("net/http", "Client", functionName)
) and
(functionName = "Get" or functionName = "Post" or functionName = "PostForm")
)
}
/** Gets the URL of the request. */
override DataFlow::Node getUrl() { result = this.getArgument(0) }
}
}