Merge pull request #5587 from smowton/smowton/admin/promote-ssrf-query

Promote SSRF query from experimental
This commit is contained in:
Chris Smowton
2021-06-17 13:02:33 +01:00
committed by GitHub
61 changed files with 2471 additions and 771 deletions

View File

@@ -0,0 +1,4 @@
lgtm,codescanning
* The query "Server-side request forgery (SSRF)" (`java/ssrf`) has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @porcupineyhairs](https://github.com/github/codeql/pull/3454).
* Models for `URI` and `HttpRequest` in the `java.net` package have been improved. This may lead to more results from any query where these types' methods are relevant.
* Models for Apache HttpComponents' `RequestLine` and `BasicRequestLine` types. This may lead to more results from any query where these types' methods are relevant.

View File

@@ -5,22 +5,24 @@
<overview>
<p>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.
<p>Directly incorporating user input into an 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.
</p>
</overview>
<recommendation>
<p>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.</p>
<p>To guard against SSRF attacks, you should avoid putting user-provided input
directly into a request URL. Instead, maintain a list of authorized
URLs on the server; then choose from that list based on the input provided.
Alternatively, ensure requests constructed from user input are limited to
a particular host or more restrictive URL prefix.</p>
</recommendation>
<example>
<p>The following example shows an HTTP request parameter being used directly in a forming a
<p>The following example shows an HTTP request parameter being used directly to form 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.
</p>

View File

@@ -0,0 +1,20 @@
/**
* @name Server-side request forgery
* @description Making web requests based on unvalidated user-input
* may cause the server to communicate with malicious servers.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/ssrf
* @tags security
* external/cwe/cwe-918
*/
import java
import semmle.code.java.security.RequestForgeryConfig
import DataFlow::PathGraph
from DataFlow::PathNode source, DataFlow::PathNode sink, RequestForgeryConfiguration conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Potential server-side request forgery due to $@.",
source.getNode(), "a user-provided value"

View File

@@ -194,15 +194,6 @@ predicate urlOpen(DataFlow::Node node1, DataFlow::Node node2) {
)
}
/** Constructor of `BasicRequestLine` */
predicate basicRequestLine(DataFlow::Node node1, DataFlow::Node node2) {
exists(ConstructorCall mcc |
mcc.getConstructedType().hasQualifiedName("org.apache.http.message", "BasicRequestLine") and
mcc.getArgument(1) = node1.asExpr() and // `BasicRequestLine(String method, String uri, ProtocolVersion version)
node2.asExpr() = mcc
)
}
class BasicAuthFlowConfig extends TaintTracking::Configuration {
BasicAuthFlowConfig() { this = "InsecureBasicAuth::BasicAuthFlowConfig" }
@@ -236,7 +227,6 @@ class BasicAuthFlowConfig extends TaintTracking::Configuration {
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
apacheHttpRequest(node1, node2) or
createURI(node1, node2) or
basicRequestLine(node1, node2) or
createURL(node1, node2) or
urlOpen(node1, node2)
}

View File

@@ -1,33 +0,0 @@
/**
* @name Server Side Request Forgery (SSRF)
* @description Making web requests based on unvalidated user-input
* may cause server to communicate with malicious servers.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/ssrf
* @tags security
* external/cwe/cwe-918
*/
import java
import semmle.code.java.dataflow.FlowSources
import RequestForgery
import DataFlow::PathGraph
class RequestForgeryConfiguration extends TaintTracking::Configuration {
RequestForgeryConfiguration() { this = "Server Side Request Forgery" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgerySink }
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
requestForgeryStep(pred, succ)
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, RequestForgeryConfiguration conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Potential server side request forgery due to $@.",
source.getNode(), "a user-provided value"

View File

@@ -1,192 +0,0 @@
import java
import semmle.code.java.frameworks.Networking
import semmle.code.java.frameworks.ApacheHttp
import semmle.code.java.frameworks.spring.Spring
import semmle.code.java.frameworks.JaxWS
import semmle.code.java.frameworks.javase.Http
import semmle.code.java.dataflow.DataFlow
predicate requestForgeryStep(DataFlow::Node pred, DataFlow::Node succ) {
// propagate to a URI when its host is assigned to
exists(UriCreation c | c.getHostArg() = pred.asExpr() | succ.asExpr() = c)
or
// propagate to a URL when its host is assigned to
exists(UrlConstructorCall c | c.getHostArg() = pred.asExpr() | succ.asExpr() = c)
or
// propagate to a RequestEntity when its url is assigned to
exists(MethodAccess m |
m.getMethod().getDeclaringType() instanceof SpringRequestEntity and
(
m.getMethod().hasName(["get", "post", "head", "delete", "options", "patch", "put"]) and
m.getArgument(0) = pred.asExpr() and
m = succ.asExpr()
or
m.getMethod().hasName("method") and
m.getArgument(1) = pred.asExpr() and
m = succ.asExpr()
)
)
or
// propagate from a `RequestEntity<>$BodyBuilder` to a `RequestEntity`
// when the builder is tainted
exists(MethodAccess m, RefType t |
m.getMethod().getDeclaringType() = t and
t.hasQualifiedName("org.springframework.http", "RequestEntity<>$BodyBuilder") and
m.getMethod().hasName("body") and
m.getQualifier() = pred.asExpr() and
m = succ.asExpr()
)
}
/** A data flow sink for request forgery vulnerabilities. */
abstract class RequestForgerySink extends DataFlow::Node { }
/**
* An argument to an url `openConnection` or `openStream` call
* taken as a sink for request forgery vulnerabilities.
*/
private class UrlOpen extends RequestForgerySink {
UrlOpen() {
exists(MethodAccess ma |
ma.getMethod() instanceof UrlOpenConnectionMethod or
ma.getMethod() instanceof UrlOpenStreamMethod
|
this.asExpr() = ma.getQualifier()
)
}
}
/**
* An argument to an Apache `setURI` call taken as a
* sink for request forgery vulnerabilities.
*/
private class ApacheSetUri extends RequestForgerySink {
ApacheSetUri() {
exists(MethodAccess ma |
ma.getReceiverType() instanceof ApacheHttpRequest and
ma.getMethod().hasName("setURI")
|
this.asExpr() = ma.getArgument(0)
)
}
}
/**
* An argument to any Apache Request Instantiation call taken as a
* sink for request forgery vulnerabilities.
*/
private class ApacheHttpRequestInstantiation extends RequestForgerySink {
ApacheHttpRequestInstantiation() {
exists(ClassInstanceExpr c | c.getConstructedType() instanceof ApacheHttpRequest |
this.asExpr() = c.getArgument(0)
)
}
}
/**
* An argument to a Apache RequestBuilder method call taken as a
* sink for request forgery vulnerabilities.
*/
private class ApacheHttpRequestBuilderArgument extends RequestForgerySink {
ApacheHttpRequestBuilderArgument() {
exists(MethodAccess ma |
ma.getReceiverType() instanceof TypeApacheHttpRequestBuilder and
ma.getMethod().hasName(["setURI", "get", "post", "put", "optons", "head", "delete"])
|
this.asExpr() = ma.getArgument(0)
)
}
}
/**
* An argument to any Java.net.http.request Instantiation call taken as a
* sink for request forgery vulnerabilities.
*/
private class HttpRequestNewBuilder extends RequestForgerySink {
HttpRequestNewBuilder() {
exists(MethodAccess call |
call.getCallee().hasName("newBuilder") and
call.getMethod().getDeclaringType().getName() = "HttpRequest"
|
this.asExpr() = call.getArgument(0)
)
}
}
/**
* An argument to an Http Builder `uri` call taken as a
* sink for request forgery vulnerabilities.
*/
private class HttpBuilderUriArgument extends RequestForgerySink {
HttpBuilderUriArgument() {
exists(MethodAccess ma | ma.getMethod() instanceof HttpBuilderUri |
this.asExpr() = ma.getArgument(0)
)
}
}
/**
* An argument to a Spring Rest Template method call taken as a
* sink for request forgery vulnerabilities.
*/
private class SpringRestTemplateArgument extends RequestForgerySink {
SpringRestTemplateArgument() {
exists(MethodAccess ma |
this.asExpr() = ma.getMethod().(SpringRestTemplateUrlMethods).getUrlArgument(ma)
)
}
}
/**
* An argument to `javax.ws.rs.Client`s `target` method call taken as a
* sink for request forgery vulnerabilities.
*/
private class JaxRsClientTarget extends RequestForgerySink {
JaxRsClientTarget() {
exists(MethodAccess ma |
ma.getMethod().getDeclaringType() instanceof JaxRsClient and
ma.getMethod().hasName("target")
|
this.asExpr() = ma.getArgument(0)
)
}
}
/**
* An argument to `org.springframework.http.RequestEntity`s constructor call
* which is an URI taken as a sink for request forgery vulnerabilities.
*/
private class RequestEntityUriArg extends RequestForgerySink {
RequestEntityUriArg() {
exists(ClassInstanceExpr e, Argument a |
e.getConstructedType() instanceof SpringRequestEntity and
e.getAnArgument() = a and
a.getType() instanceof TypeUri and
this.asExpr() = a
)
}
}
/**
* A class representing all Spring Rest Template methods
* which take an URL as an argument.
*/
private class SpringRestTemplateUrlMethods extends Method {
SpringRestTemplateUrlMethods() {
this.getDeclaringType() instanceof SpringRestTemplate and
this.hasName([
"doExecute", "postForEntity", "postForLocation", "postForObject", "put", "exchange",
"execute", "getForEntity", "getForObject", "patchForObject"
])
}
/**
* Gets the argument which corresponds to a URL argument
* passed as a `java.net.URL` object or as a string or the like
*/
Argument getUrlArgument(MethodAccess ma) {
// doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
// ResponseExtractor<T> responseExtractor)
result = ma.getArgument(0)
}
}

View File

@@ -175,6 +175,19 @@ class FormattingCall extends Call {
)
}
/** Gets the `i`th argument to be formatted. The index `i` is one-based. */
Expr getArgumentToBeFormatted(int i) {
i >= 1 and
if this.hasExplicitVarargsArray()
then
result =
this.getArgument(1 + this.getFormatStringIndex())
.(ArrayCreationExpr)
.getInit()
.getInit(i - 1)
else result = this.getArgument(this.getFormatStringIndex() + i)
}
/** Holds if the varargs argument is given as an explicit array. */
private predicate hasExplicitVarargsArray() {
this.getNumArgument() = this.getFormatStringIndex() + 2 and
@@ -353,6 +366,11 @@ class FormatString extends string {
* is not referred by any format specifier.
*/
/*abstract*/ int getASkippedFmtSpecIndex() { none() }
/**
* Gets an offset (zero-based) in this format string where argument `argNo` (1-based) will be interpolated, if any.
*/
int getAnArgUsageOffset(int argNo) { none() }
}
private class PrintfFormatString extends FormatString {
@@ -425,6 +443,22 @@ private class PrintfFormatString extends FormatString {
result > count(int i | fmtSpecRefersToSequentialIndex(i)) and
not result = fmtSpecRefersToSpecificIndex(_)
}
private int getFmtSpecRank(int specOffset) {
rank[result](int i | this.fmtSpecIsRef(i)) = specOffset
}
override int getAnArgUsageOffset(int argNo) {
argNo = fmtSpecRefersToSpecificIndex(result)
or
result = rank[argNo](int i | fmtSpecRefersToSequentialIndex(i))
or
fmtSpecRefersToPrevious(result) and
exists(int previousOffset |
getFmtSpecRank(previousOffset) = getFmtSpecRank(result) - 1 and
previousOffset = getAnArgUsageOffset(argNo)
)
}
}
private class LoggerFormatString extends FormatString {
@@ -449,4 +483,6 @@ private class LoggerFormatString extends FormatString {
}
override int getMaxFmtSpecIndex() { result = count(int i | fmtPlaceholder(i)) }
override int getAnArgUsageOffset(int argNo) { result = rank[argNo](int i | fmtPlaceholder(i)) }
}

View File

@@ -82,6 +82,8 @@ private module Frameworks {
private import semmle.code.java.frameworks.guava.Guava
private import semmle.code.java.frameworks.jackson.JacksonSerializability
private import semmle.code.java.frameworks.JaxWS
private import semmle.code.java.frameworks.spring.SpringHttp
private import semmle.code.java.frameworks.spring.SpringWebClient
private import semmle.code.java.security.ResponseSplitting
private import semmle.code.java.security.InformationLeak
private import semmle.code.java.security.XSS
@@ -209,6 +211,8 @@ private predicate sinkModelCsv(string row) {
// Open URL
"java.net;URL;false;openConnection;;;Argument[-1];open-url",
"java.net;URL;false;openStream;;;Argument[-1];open-url",
"java.net.http;HttpRequest;false;newBuilder;;;Argument[0];open-url",
"java.net.http;HttpRequest$Builder;false;uri;;;Argument[0];open-url",
// Create file
"java.io;FileOutputStream;false;FileOutputStream;;;Argument[0];create-file",
"java.io;RandomAccessFile;false;RandomAccessFile;;;Argument[0];create-file",
@@ -248,6 +252,8 @@ private predicate summaryModelCsv(string row) {
"javax.xml.transform.stream;StreamSource;false;getInputStream;;;Argument[-1];ReturnValue;taint",
"java.nio;ByteBuffer;false;get;;;Argument[-1];ReturnValue;taint",
"java.net;URI;false;toURL;;;Argument[-1];ReturnValue;taint",
"java.net;URI;false;toString;;;Argument[-1];ReturnValue;taint",
"java.net;URI;false;toAsciiString;;;Argument[-1];ReturnValue;taint",
"java.io;File;false;toURI;;;Argument[-1];ReturnValue;taint",
"java.io;File;false;toPath;;;Argument[-1];ReturnValue;taint",
"java.nio.file;Path;false;toFile;;;Argument[-1];ReturnValue;taint",

View File

@@ -92,6 +92,39 @@ private class ApacheHttpXssSink extends SinkModelCsv {
}
}
private class ApacheHttpOpenUrlSink extends SinkModelCsv {
override predicate row(string row) {
row =
[
"org.apache.http;HttpRequest;true;setURI;;;Argument[0];open-url",
"org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(RequestLine);;Argument[0];open-url",
"org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(String,String);;Argument[1];open-url",
"org.apache.http.message;BasicHttpRequest;false;BasicHttpRequest;(String,String,ProtocolVersion);;Argument[1];open-url",
"org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(RequestLine);;Argument[0];open-url",
"org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(String,String);;Argument[1];open-url",
"org.apache.http.message;BasicHttpEntityEnclosingRequest;false;BasicHttpEntityEnclosingRequest;(String,String,ProtocolVersion);;Argument[1];open-url",
"org.apache.http.client.methods;HttpGet;false;HttpGet;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpHead;false;HttpHead;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpPut;false;HttpPut;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpPost;false;HttpPost;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpDelete;false;HttpDelete;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpOptions;false;HttpOptions;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpTrace;false;HttpTrace;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpPatch;false;HttpPatch;;;Argument[0];open-url",
"org.apache.http.client.methods;HttpRequestBase;true;setURI;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;setUri;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;get;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;post;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;put;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;options;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;head;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;delete;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;trace;;;Argument[0];open-url",
"org.apache.http.client.methods;RequestBuilder;false;patch;;;Argument[0];open-url"
]
}
}
private class ApacheHttpFlowStep extends SummaryModelCsv {
override predicate row(string row) {
row =
@@ -228,7 +261,10 @@ private class ApacheHttpFlowStep extends SummaryModelCsv {
"org.apache.hc.core5.util;CharArrayBuffer;true;toString;();;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;substring;(int,int);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;subSequence;(int,int);;Argument[-1];ReturnValue;taint",
"org.apache.hc.core5.util;CharArrayBuffer;true;substringTrimmed;(int,int);;Argument[-1];ReturnValue;taint"
"org.apache.hc.core5.util;CharArrayBuffer;true;substringTrimmed;(int,int);;Argument[-1];ReturnValue;taint",
"org.apache.http.message;BasicRequestLine;false;BasicRequestLine;;;Argument[1];Argument[-1];taint",
"org.apache.http;RequestLine;true;getUri;;;Argument[-1];ReturnValue;taint",
"org.apache.http;RequestLine;true;toString;;;Argument[-1];ReturnValue;taint"
]
}
}

View File

@@ -786,3 +786,13 @@ private class UriBuilderModel extends SummaryModelCsv {
]
}
}
private class JaxRsUrlOpenSink extends SinkModelCsv {
override predicate row(string row) {
row =
[
"javax.ws.rs.client;Client;true;target;;;Argument[0];open-url",
"jakarta.ws.rs.client;Client;true;target;;;Argument[0];open-url"
]
}
}

View File

@@ -4,6 +4,7 @@
*/
import java
private import semmle.code.java.dataflow.ExternalFlow
/** The class `org.springframework.http.HttpEntity` or an instantiation of it. */
class SpringHttpEntity extends Class {
@@ -38,3 +39,25 @@ class SpringResponseEntityBodyBuilder extends Interface {
class SpringHttpHeaders extends Class {
SpringHttpHeaders() { this.hasQualifiedName("org.springframework.http", "HttpHeaders") }
}
private class UrlOpenSink extends SinkModelCsv {
override predicate row(string row) {
row =
[
"org.springframework.http;RequestEntity;false;get;;;Argument[0];open-url",
"org.springframework.http;RequestEntity;false;post;;;Argument[0];open-url",
"org.springframework.http;RequestEntity;false;head;;;Argument[0];open-url",
"org.springframework.http;RequestEntity;false;delete;;;Argument[0];open-url",
"org.springframework.http;RequestEntity;false;options;;;Argument[0];open-url",
"org.springframework.http;RequestEntity;false;patch;;;Argument[0];open-url",
"org.springframework.http;RequestEntity;false;put;;;Argument[0];open-url",
"org.springframework.http;RequestEntity;false;method;;;Argument[1];open-url",
"org.springframework.http;RequestEntity;false;RequestEntity;(HttpMethod,URI);;Argument[1];open-url",
"org.springframework.http;RequestEntity;false;RequestEntity;(MultiValueMap,HttpMethod,URI);;Argument[2];open-url",
"org.springframework.http;RequestEntity;false;RequestEntity;(Object,HttpMethod,URI);;Argument[2];open-url",
"org.springframework.http;RequestEntity;false;RequestEntity;(Object,HttpMethod,URI,Type);;Argument[2];open-url",
"org.springframework.http;RequestEntity;false;RequestEntity;(Object,MultiValueMap,HttpMethod,URI);;Argument[3];open-url",
"org.springframework.http;RequestEntity;false;RequestEntity;(Object,MultiValueMap,HttpMethod,URI,Type);;Argument[3];open-url"
]
}
}

View File

@@ -4,6 +4,7 @@
import java
import SpringHttp
private import semmle.code.java.dataflow.ExternalFlow
/** The class `org.springframework.web.client.RestTemplate`. */
class SpringRestTemplate extends Class {
@@ -27,3 +28,24 @@ class SpringWebClient extends Interface {
this.hasQualifiedName("org.springframework.web.reactive.function.client", "WebClient")
}
}
private class UrlOpenSink extends SinkModelCsv {
override predicate row(string row) {
row =
[
"org.springframework.web.client;RestTemplate;false;delete;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;doExecute;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;exchange;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;execute;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;getForEntity;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;getForObject;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;headForHeaders;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;optionsForAllow;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;patchForObject;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;postForEntity;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;postForLocation;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;postForObject;;;Argument[0];open-url",
"org.springframework.web.client;RestTemplate;false;put;;;Argument[0];open-url"
]
}
}

View File

@@ -0,0 +1,213 @@
/** Provides classes to reason about server-side request forgery (SSRF) attacks. */
import java
import semmle.code.java.frameworks.Networking
import semmle.code.java.frameworks.ApacheHttp
import semmle.code.java.frameworks.spring.Spring
import semmle.code.java.frameworks.JaxWS
import semmle.code.java.frameworks.javase.Http
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.StringFormat
private import semmle.code.java.dataflow.ExternalFlow
/**
* A unit class for adding additional taint steps that are specific to server-side request forgery (SSRF) attacks.
*
* Extend this class to add additional taint steps to the SSRF query.
*/
class RequestForgeryAdditionalTaintStep extends Unit {
/**
* Holds if the step from `pred` to `succ` should be considered a taint
* step for server-side request forgery.
*/
abstract predicate propagatesTaint(DataFlow::Node pred, DataFlow::Node succ);
}
private class DefaultRequestForgeryAdditionalTaintStep extends RequestForgeryAdditionalTaintStep {
override predicate propagatesTaint(DataFlow::Node pred, DataFlow::Node succ) {
// propagate to a URI when its host is assigned to
exists(UriCreation c | c.getHostArg() = pred.asExpr() | succ.asExpr() = c)
or
// propagate to a URL when its host is assigned to
exists(UrlConstructorCall c | c.getHostArg() = pred.asExpr() | succ.asExpr() = c)
}
}
/** A data flow sink for server-side request forgery (SSRF) vulnerabilities. */
abstract class RequestForgerySink extends DataFlow::Node { }
private class UrlOpenSinkAsRequestForgerySink extends RequestForgerySink {
UrlOpenSinkAsRequestForgerySink() { sinkNode(this, "open-url") }
}
/** A sanitizer for request forgery vulnerabilities. */
abstract class RequestForgerySanitizer extends DataFlow::Node { }
private class PrimitiveSanitizer extends RequestForgerySanitizer {
PrimitiveSanitizer() {
this.getType() instanceof PrimitiveType or
this.getType() instanceof BoxedType or
this.getType() instanceof NumberType
}
}
private class HostnameSanitizingConstantPrefix extends CompileTimeConstantExpr {
int offset;
HostnameSanitizingConstantPrefix() {
// Matches strings that look like when prepended to untrusted input, they will restrict
// the host or entity addressed: for example, anything containing `?` or `#`, or a slash that
// doesn't appear to be a protocol specifier (e.g. `http://` is not sanitizing), or specifically
// the string "/".
exists(
this.getStringValue()
.regexpFind(".*([?#]|[^?#:/\\\\][/\\\\]).*|[/\\\\][^/\\\\].*|^/$", 0, offset)
)
}
/**
* Gets the offset in this constant string where a sanitizing substring begins.
*/
int getOffset() { result = offset }
}
private Expr getAHostnameSanitizingPrefix() {
result instanceof HostnameSanitizingConstantPrefix
or
result.(AddExpr).getAnOperand() = getAHostnameSanitizingPrefix()
}
private class StringBuilderAppend extends MethodAccess {
StringBuilderAppend() {
this.getMethod().getDeclaringType() instanceof StringBuildingType and
this.getMethod().hasName("append")
}
}
private class StringBuilderConstructorOrAppend extends Call {
StringBuilderConstructorOrAppend() {
this instanceof StringBuilderAppend or
this.(ClassInstanceExpr).getConstructedType() instanceof StringBuildingType
}
}
private Expr getQualifier(Expr e) { result = e.(MethodAccess).getQualifier() }
/**
* An extension of `StringBuilderVar` that also accounts for strings appended in StringBuilder/Buffer's constructor
* and in `append` calls chained onto the constructor call.
*
* The original `StringBuilderVar` doesn't care about these because it is designed to model taint, and
* in taint rules terms these are not needed, as the connection between construction, appends and the
* eventual `toString` is more obvious.
*/
private class StringBuilderVarExt extends StringBuilderVar {
/**
* Returns a first assignment after this StringBuilderVar is first assigned.
*
* For example, for `StringBuilder sbv = new StringBuilder("1").append("2"); sbv.append("3").append("4");`
* this returns the append of `"3"`.
*/
private StringBuilderAppend getAFirstAppendAfterAssignment() {
result = this.getAnAppend() and not result = this.getNextAppend(_)
}
/**
* Gets the next `append` after `prev`, where `prev` is, perhaps after some more `append` or other
* chained calls, assigned to this `StringBuilderVar`.
*/
private StringBuilderAppend getNextAssignmentChainedAppend(StringBuilderConstructorOrAppend prev) {
getQualifier*(result) = this.getAnAssignedValue() and
result.getQualifier() = prev
}
/**
* Get a constructor call or `append` call that contributes a string to this string builder.
*/
StringBuilderConstructorOrAppend getAConstructorOrAppend() {
exists(this.getNextAssignmentChainedAppend(result)) or
result = this.getAnAssignedValue() or
result = this.getAnAppend()
}
/**
* Like `StringBuilderVar.getNextAppend`, except including appends and constructors directly
* assigned to this `StringBuilderVar`.
*/
private StringBuilderAppend getNextAppendIncludingAssignmentChains(
StringBuilderConstructorOrAppend prev
) {
result = getNextAssignmentChainedAppend(prev)
or
prev = this.getAnAssignedValue() and
result = this.getAFirstAppendAfterAssignment()
or
result = this.getNextAppend(prev)
}
/**
* Implements `StringBuilderVarExt.getNextAppendIncludingAssignmentChains+(prev)`.
*/
StringBuilderAppend getSubsequentAppendIncludingAssignmentChains(
StringBuilderConstructorOrAppend prev
) {
result = this.getNextAppendIncludingAssignmentChains(prev) or
result =
this.getSubsequentAppendIncludingAssignmentChains(this.getNextAppendIncludingAssignmentChains(prev))
}
}
/**
* An expression that is sanitized because it is concatenated onto a string that looks like
* a hostname or a URL separator, preventing the appended string from arbitrarily controlling
* the addressed server.
*/
private class HostnameSanitizedExpr extends Expr {
HostnameSanitizedExpr() {
// Sanitize expressions that come after a sanitizing prefix in a tree of string additions:
this =
any(AddExpr add | add.getLeftOperand() = getAHostnameSanitizingPrefix()).getRightOperand()
or
// Sanitize expressions that come after a sanitizing prefix in a sequence of StringBuilder operations:
exists(
StringBuilderConstructorOrAppend appendSanitizingConstant,
StringBuilderAppend subsequentAppend, StringBuilderVarExt v
|
appendSanitizingConstant = v.getAConstructorOrAppend() and
appendSanitizingConstant.getArgument(0) = getAHostnameSanitizingPrefix() and
v.getSubsequentAppendIncludingAssignmentChains(appendSanitizingConstant) = subsequentAppend and
this = subsequentAppend.getArgument(0)
)
or
// Sanitize expressions that come after a sanitizing prefix in the args to a format call:
exists(
FormattingCall formatCall, FormatString formatString, HostnameSanitizingConstantPrefix prefix,
int sanitizedFromOffset, int laterOffset, int sanitizedArg
|
formatString = unique(FormatString fs | fs = formatCall.getAFormatString()) and
(
// A sanitizing argument comes before this:
exists(int argIdx |
formatCall.getArgumentToBeFormatted(argIdx) = prefix and
sanitizedFromOffset = formatString.getAnArgUsageOffset(argIdx)
)
or
// The format string itself sanitizes subsequent arguments:
formatString = prefix.getStringValue() and
sanitizedFromOffset = prefix.getOffset()
) and
laterOffset > sanitizedFromOffset and
laterOffset = formatString.getAnArgUsageOffset(sanitizedArg) and
this = formatCall.getArgumentToBeFormatted(sanitizedArg)
)
}
}
/**
* A value that is the result of prepending a string that prevents any value from controlling the
* host of a URL.
*/
private class HostnameSantizer extends RequestForgerySanitizer {
HostnameSantizer() { this.asExpr() instanceof HostnameSanitizedExpr }
}

View File

@@ -0,0 +1,31 @@
/**
* Provides a taint-tracking configuration characterising request-forgery risks.
*
* Only import this directly from .ql files, to avoid the possibility of polluting the Configuration hierarchy accidentally.
*/
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.RequestForgery
/**
* A taint-tracking configuration characterising request-forgery risks.
*/
class RequestForgeryConfiguration extends TaintTracking::Configuration {
RequestForgeryConfiguration() { this = "Server-Side Request Forgery" }
override predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource and
// Exclude results of remote HTTP requests: fetching something else based on that result
// is no worse than following a redirect returned by the remote server, and typically
// we're requesting a resource via https which we trust to only send us to safe URLs.
not source.asExpr().(MethodAccess).getCallee() instanceof URLConnectionGetInputStreamMethod
}
override predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgerySink }
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
any(RequestForgeryAdditionalTaintStep r).propagatesTaint(pred, succ)
}
override predicate isSanitizer(DataFlow::Node node) { node instanceof RequestForgerySanitizer }
}

View File

@@ -11,7 +11,9 @@ edges
| InsecureBasicAuth.java:62:21:62:26 | uriStr : String | InsecureBasicAuth.java:62:13:62:27 | new URI(...) : URI |
| InsecureBasicAuth.java:78:47:78:52 | "http" : String | InsecureBasicAuth.java:86:3:86:6 | post |
| InsecureBasicAuth.java:93:19:93:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:102:3:102:6 | post |
| InsecureBasicAuth.java:109:19:109:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:119:3:119:6 | post |
| InsecureBasicAuth.java:109:19:109:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:110:58:110:63 | uriStr : String |
| InsecureBasicAuth.java:110:29:110:70 | new BasicRequestLine(...) : BasicRequestLine | InsecureBasicAuth.java:119:3:119:6 | post |
| InsecureBasicAuth.java:110:58:110:63 | uriStr : String | InsecureBasicAuth.java:110:29:110:70 | new BasicRequestLine(...) : BasicRequestLine |
| InsecureBasicAuth.java:126:19:126:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | InsecureBasicAuth.java:130:28:130:67 | (...)... : URLConnection |
| InsecureBasicAuth.java:130:28:130:67 | (...)... : URLConnection | InsecureBasicAuth.java:133:3:133:6 | conn |
| InsecureBasicAuth.java:145:21:145:28 | protocol : String | InsecureBasicAuth.java:146:28:146:67 | (...)... : URLConnection |
@@ -34,6 +36,8 @@ nodes
| InsecureBasicAuth.java:93:19:93:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | semmle.label | "http://www.example.com/rest/getuser.do?uid=abcdx" : String |
| InsecureBasicAuth.java:102:3:102:6 | post | semmle.label | post |
| InsecureBasicAuth.java:109:19:109:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | semmle.label | "http://www.example.com/rest/getuser.do?uid=abcdx" : String |
| InsecureBasicAuth.java:110:29:110:70 | new BasicRequestLine(...) : BasicRequestLine | semmle.label | new BasicRequestLine(...) : BasicRequestLine |
| InsecureBasicAuth.java:110:58:110:63 | uriStr : String | semmle.label | uriStr : String |
| InsecureBasicAuth.java:119:3:119:6 | post | semmle.label | post |
| InsecureBasicAuth.java:126:19:126:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | semmle.label | "http://www.example.com/rest/getuser.do?uid=abcdx" : String |
| InsecureBasicAuth.java:130:28:130:67 | (...)... : URLConnection | semmle.label | (...)... : URLConnection |

View File

@@ -1,77 +0,0 @@
edges
| JaxWsSSRF.java:21:22:21:48 | getParameter(...) : String | JaxWsSSRF.java:22:23:22:25 | url |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:25:31:25:34 | sink : String |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:55:32:55:35 | url1 |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:58:32:58:35 | url1 |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:59:30:59:33 | url1 |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:63:65:63:68 | uri2 |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:64:59:64:61 | uri |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:67:43:67:45 | uri |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:69:29:69:32 | uri2 |
| RequestForgery2.java:25:23:25:35 | new URI(...) : URI | RequestForgery2.java:64:59:64:61 | uri |
| RequestForgery2.java:25:23:25:35 | new URI(...) : URI | RequestForgery2.java:67:43:67:45 | uri |
| RequestForgery2.java:25:31:25:34 | sink : String | RequestForgery2.java:25:23:25:35 | new URI(...) : URI |
| RequestForgery.java:19:23:19:58 | new URI(...) : URI | RequestForgery.java:22:52:22:54 | uri |
| RequestForgery.java:19:23:19:58 | new URI(...) : URI | RequestForgery.java:27:57:27:59 | uri |
| RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:19:23:19:58 | new URI(...) : URI |
| RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:22:52:22:54 | uri |
| RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:27:57:27:59 | uri |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:32:47:32:67 | ... + ... |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:37:43:37:56 | fooResourceUrl |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:41:42:41:55 | fooResourceUrl |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:45:47:45:60 | fooResourceUrl |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:54:59:54:72 | fooResourceUrl |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:58:74:58:96 | new URI(...) |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:58:82:58:95 | fooResourceUrl : String |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:62:57:62:70 | fooResourceUrl |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:66:48:66:61 | fooResourceUrl |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:69:30:69:43 | fooResourceUrl |
| SpringSSRF.java:58:82:58:95 | fooResourceUrl : String | SpringSSRF.java:58:74:58:96 | new URI(...) |
nodes
| JaxWsSSRF.java:21:22:21:48 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| JaxWsSSRF.java:22:23:22:25 | url | semmle.label | url |
| RequestForgery2.java:23:27:23:53 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RequestForgery2.java:25:23:25:35 | new URI(...) : URI | semmle.label | new URI(...) : URI |
| RequestForgery2.java:25:31:25:34 | sink : String | semmle.label | sink : String |
| RequestForgery2.java:55:32:55:35 | url1 | semmle.label | url1 |
| RequestForgery2.java:58:32:58:35 | url1 | semmle.label | url1 |
| RequestForgery2.java:59:30:59:33 | url1 | semmle.label | url1 |
| RequestForgery2.java:63:65:63:68 | uri2 | semmle.label | uri2 |
| RequestForgery2.java:64:59:64:61 | uri | semmle.label | uri |
| RequestForgery2.java:67:43:67:45 | uri | semmle.label | uri |
| RequestForgery2.java:69:29:69:32 | uri2 | semmle.label | uri2 |
| RequestForgery.java:19:23:19:58 | new URI(...) : URI | semmle.label | new URI(...) : URI |
| RequestForgery.java:19:31:19:57 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RequestForgery.java:22:52:22:54 | uri | semmle.label | uri |
| RequestForgery.java:27:57:27:59 | uri | semmle.label | uri |
| SpringSSRF.java:26:33:26:60 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| SpringSSRF.java:32:47:32:67 | ... + ... | semmle.label | ... + ... |
| SpringSSRF.java:37:43:37:56 | fooResourceUrl | semmle.label | fooResourceUrl |
| SpringSSRF.java:41:42:41:55 | fooResourceUrl | semmle.label | fooResourceUrl |
| SpringSSRF.java:45:47:45:60 | fooResourceUrl | semmle.label | fooResourceUrl |
| SpringSSRF.java:54:59:54:72 | fooResourceUrl | semmle.label | fooResourceUrl |
| SpringSSRF.java:58:74:58:96 | new URI(...) | semmle.label | new URI(...) |
| SpringSSRF.java:58:82:58:95 | fooResourceUrl : String | semmle.label | fooResourceUrl : String |
| SpringSSRF.java:62:57:62:70 | fooResourceUrl | semmle.label | fooResourceUrl |
| SpringSSRF.java:66:48:66:61 | fooResourceUrl | semmle.label | fooResourceUrl |
| SpringSSRF.java:69:30:69:43 | fooResourceUrl | semmle.label | fooResourceUrl |
#select
| JaxWsSSRF.java:22:23:22:25 | url | JaxWsSSRF.java:21:22:21:48 | getParameter(...) : String | JaxWsSSRF.java:22:23:22:25 | url | Potential server side request forgery due to $@. | JaxWsSSRF.java:21:22:21:48 | getParameter(...) | a user-provided value |
| RequestForgery2.java:55:32:55:35 | url1 | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:55:32:55:35 | url1 | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
| RequestForgery2.java:58:32:58:35 | url1 | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:58:32:58:35 | url1 | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
| RequestForgery2.java:59:30:59:33 | url1 | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:59:30:59:33 | url1 | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
| RequestForgery2.java:63:65:63:68 | uri2 | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:63:65:63:68 | uri2 | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
| RequestForgery2.java:64:59:64:61 | uri | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:64:59:64:61 | uri | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
| RequestForgery2.java:67:43:67:45 | uri | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:67:43:67:45 | uri | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
| RequestForgery2.java:69:29:69:32 | uri2 | RequestForgery2.java:23:27:23:53 | getParameter(...) : String | RequestForgery2.java:69:29:69:32 | uri2 | Potential server side request forgery due to $@. | RequestForgery2.java:23:27:23:53 | getParameter(...) | a user-provided value |
| RequestForgery.java:22:52:22:54 | uri | RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:22:52:22:54 | uri | Potential server side request forgery due to $@. | RequestForgery.java:19:31:19:57 | getParameter(...) | a user-provided value |
| RequestForgery.java:27:57:27:59 | uri | RequestForgery.java:19:31:19:57 | getParameter(...) : String | RequestForgery.java:27:57:27:59 | uri | Potential server side request forgery due to $@. | RequestForgery.java:19:31:19:57 | getParameter(...) | a user-provided value |
| SpringSSRF.java:32:47:32:67 | ... + ... | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:32:47:32:67 | ... + ... | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
| SpringSSRF.java:37:43:37:56 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:37:43:37:56 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
| SpringSSRF.java:41:42:41:55 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:41:42:41:55 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
| SpringSSRF.java:45:47:45:60 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:45:47:45:60 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
| SpringSSRF.java:54:59:54:72 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:54:59:54:72 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
| SpringSSRF.java:58:74:58:96 | new URI(...) | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:58:74:58:96 | new URI(...) | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
| SpringSSRF.java:62:57:62:70 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:62:57:62:70 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
| SpringSSRF.java:66:48:66:61 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:66:48:66:61 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |
| SpringSSRF.java:69:30:69:43 | fooResourceUrl | SpringSSRF.java:26:33:26:60 | getParameter(...) : String | SpringSSRF.java:69:30:69:43 | fooResourceUrl | Potential server side request forgery due to $@. | SpringSSRF.java:26:33:26:60 | getParameter(...) | a user-provided value |

View File

@@ -1,34 +0,0 @@
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestForgery extends HttpServlet {
private static final String VALID_URI = "http://lgtm.com";
private HttpClient client = HttpClient.newHttpClient();
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
URI uri = new URI(request.getParameter("uri"));
// BAD: a request parameter is incorporated without validation into a Http
// request
HttpRequest r = HttpRequest.newBuilder(uri).build();
client.send(r, null);
// GOOD: the request parameter is validated against a known fixed string
if (VALID_URI.equals(request.getParameter("uri"))) {
HttpRequest r2 = HttpRequest.newBuilder(uri).build();
client.send(r2, null);
}
} catch (Exception e) {
// TODO: handle exception
}
}
}

View File

@@ -1 +0,0 @@
experimental/Security/CWE/CWE-918/RequestForgery.ql

View File

@@ -1,84 +0,0 @@
import java.io.IOException;
import java.net.URI;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.Proxy.Type;
import java.io.InputStream;
import org.apache.http.client.methods.HttpGet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestForgery2 extends HttpServlet {
private static final String VALID_URI = "http://lgtm.com";
private HttpClient client = HttpClient.newHttpClient();
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String sink = request.getParameter("uri");
// URI(String str)
URI uri = new URI(sink);
// URI(String scheme, String ssp, String fragment)
URI uri2 = new URI("http", sink, "fragement");
// URI(String scheme, String userInfo, String host, int port, String path,
// String query, String fragment)
URI uri3 = new URI("http", "userinfo", "host", 1, "path", "query", "fragment");
// URI(String scheme, String host, String path, String fragment)
URI uri4 = new URI("http", "host", "path", "fragment");
// URI(String scheme, String authority, String path, String query, String
// fragment)
URI uri5 = new URI("http", "authority", "path", "query", "fragment");
URI uri6 = URI.create("http://foo.com/");
// URL(String spec)
URL url1 = new URL(sink);
// URL(String protocol, String host, int port, String file)
URL url2 = new URL("http", "host", 1, "file");
// URL(String protocol, String host, String file)
URL url3 = new URL("http", "host", "file");
// URL(URL context, String spec)
URL url4 = new URL(url3, "http");
// URL(String protocol, String host, int port, String file, URLStreamHandler
// handler)
URL url5 = new URL("http", "host", 1, "file", new Helper2());
// URL(URL context, String spec, URLStreamHandler handler)
URL url6 = new URL(url3, "spec", new Helper2());
URLConnection c1 = url1.openConnection();
SocketAddress sa = new SocketAddress() {
};
URLConnection c2 = url1.openConnection(new Proxy(Type.HTTP, sa));
InputStream c3 = url1.openStream();
// java.net.http
HttpClient client = HttpClient.newHttpClient();
HttpRequest request2 = HttpRequest.newBuilder().uri(uri2).build();
HttpRequest request3 = HttpRequest.newBuilder(uri).build();
// Apache HTTPlib
HttpGet httpGet = new HttpGet(uri);
HttpGet httpGet2 = new HttpGet();
httpGet2.setURI(uri2);
} catch (Exception e) {
// TODO: handle exception
}
}
}
class Helper2 extends URLStreamHandler {
Helper2() {
}
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
}

View File

@@ -1,72 +0,0 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.Proxy.Type;
import org.apache.http.client.methods.HttpGet;
// import java.net.http.HttpClient;
// import java.net.http.HttpRequest;
public class Sinks {
public static void main(String[] args) throws Exception {
// URI(String str)
URI uri = new URI("uri1");
// URI(String scheme, String ssp, String fragment)
URI uri2 = new URI("http", "ssp", "fragement");
// URI(String scheme, String userInfo, String host, int port, String path,
// String query, String fragment)
URI uri3 = new URI("http", "userinfo", "host", 1, "path", "query", "fragment");
// URI(String scheme, String host, String path, String fragment)
URI uri4 = new URI("http", "host", "path", "fragment");
// URI(String scheme, String authority, String path, String query, String
// fragment)
URI uri5 = new URI("http", "authority", "path", "query", "fragment");
URI uri6 = URI.create("http://foo.com/");
// URL(String spec)
URL url1 = new URL("spec");
// URL(String protocol, String host, int port, String file)
URL url2 = new URL("http", "host", 1, "file");
// URL(String protocol, String host, String file)
URL url3 = new URL("http", "host", "file");
// URL(URL context, String spec)
URL url4 = new URL(url3, "http");
// URL(String protocol, String host, int port, String file, URLStreamHandler
// handler)
URL url5 = new URL("http", "host", 1, "file", new Helper());
// URL(URL context, String spec, URLStreamHandler handler)
URL url6 = new URL(url3, "spec", new Helper());
URLConnection c1 = url1.openConnection();
SocketAddress sa = new SocketAddress() {
};
URLConnection c2 = url1.openConnection(new Proxy(Type.HTTP, sa));
InputStream c3 = url1.openStream();
// java.net.http
// HttpClient client = HttpClient.newHttpClient();
// HttpRequest request2 = HttpRequest.newBuilder().uri(uri2).build();
// HttpRequest request3 = HttpRequest.newBuilder(uri).build();
// Apache HTTPlib
HttpGet httpGet = new HttpGet(uri);
HttpGet httpGet2 = new HttpGet();
httpGet2.setURI(uri2);
}
}
class Helper extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL arg0) throws IOException {
return null;
}
}

View File

@@ -1,73 +0,0 @@
import org.springframework.web.client.RestTemplate;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import java.net.URI;
import org.springframework.http.HttpMethod;
import java.io.IOException;
import java.net.URI;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.Proxy.Type;
import java.io.InputStream;
import org.apache.http.client.methods.HttpGet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SpringSSRF extends HttpServlet {
protected void doGet(HttpServletRequest request2, HttpServletResponse response2)
throws ServletException, IOException {
String fooResourceUrl = request2.getParameter("uri");;
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> request = new HttpEntity<>(new String("bar"));
try {
{
ResponseEntity<String> response =
restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
}
{
ResponseEntity<String> response =
restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, String.class);
}
{
ResponseEntity<String> response =
restTemplate.execute(fooResourceUrl, HttpMethod.POST, null, null, "test");
}
{
ResponseEntity<String> response =
restTemplate.getForEntity(fooResourceUrl, String.class, "test");
}
{
String body = new String("body");
RequestEntity<String> requestEntity =
RequestEntity.post(new URI(fooResourceUrl)).body(body);
ResponseEntity<String> response = restTemplate.exchange(requestEntity, String.class);
}
{
String response = restTemplate.patchForObject(fooResourceUrl, new String("object"),
String.class, "hi");
}
{
ResponseEntity<String> response = restTemplate.postForEntity(new URI(fooResourceUrl),
new String("object"), String.class);
}
{
URI response = restTemplate.postForLocation(fooResourceUrl, new String("object"));
}
{
String response =
restTemplate.postForObject(fooResourceUrl, new String("object"), String.class);
}
{
restTemplate.put(fooResourceUrl, new String("object"));
}
} catch (org.springframework.web.client.RestClientException | java.net.URISyntaxException e) {}
}
}

View File

@@ -1 +0,0 @@
//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../stubs/servlet-api-2.4/

View File

@@ -1,12 +0,0 @@
package javax.ws.rs.client;
public abstract interface Client extends javax.ws.rs.core.Configurable {
public abstract javax.ws.rs.client.WebTarget target(java.lang.String arg0);
public abstract javax.ws.rs.client.WebTarget target(java.net.URI arg0);
public abstract javax.ws.rs.client.WebTarget target(javax.ws.rs.core.UriBuilder arg0);
public abstract javax.ws.rs.client.WebTarget target(javax.ws.rs.core.Link arg0);
}

View File

@@ -1,6 +0,0 @@
package javax.ws.rs.core;
public abstract interface Configurable<C extends javax.ws.rs.core.Configurable> {
public abstract javax.ws.rs.core.Configuration getConfiguration();
}

View File

@@ -1,61 +0,0 @@
package javax.ws.rs.core;
public abstract class Link {
public static final java.lang.String TITLE = "title";
public static final java.lang.String REL = "rel";
public static final java.lang.String TYPE = "type";
public Link() {
}
public abstract java.net.URI getUri();
public abstract javax.ws.rs.core.UriBuilder getUriBuilder();
public abstract java.lang.String getRel();
public abstract java.util.List<java.lang.String> getRels();
public abstract java.lang.String getTitle();
public abstract java.lang.String getType();
public abstract java.util.Map<java.lang.String, java.lang.String> getParams();
public abstract java.lang.String toString();
public static javax.ws.rs.core.Link valueOf(java.lang.String value) {
return null;
}
// public static javax.ws.rs.core.Link.Builder fromUri(java.net.URI uri) {
// return null;
// }
// public static javax.ws.rs.core.Link.Builder fromUri(java.lang.String uri) {
// return null;
// }
// public static javax.ws.rs.core.Link.Builder fromUriBuilder(javax.ws.rs.core.UriBuilder uriBuilder) {
// return null;
// }
// public static javax.ws.rs.core.Link.Builder fromLink(javax.ws.rs.core.Link link) {
// return null;
// }
// public static javax.ws.rs.core.Link.Builder fromPath(java.lang.String path) {
// return null;
// }
// public static javax.ws.rs.core.Link.Builder fromResource(java.lang.Class<?> resource) {
// return null;
// }
// public static javax.ws.rs.core.Link.Builder fromMethod(java.lang.Class<?> resource, java.lang.String method) {
// return null;
// }
}

View File

@@ -1,62 +0,0 @@
// Failed to get sources. Instead, stub sources have been generated by the disassembler.
// Implementation of methods is unavailable.
package javax.ws.rs.core;
public abstract class UriBuilder {
protected UriBuilder() {
}
protected static javax.ws.rs.core.UriBuilder newInstance() {
return null;
}
public static javax.ws.rs.core.UriBuilder fromUri(java.net.URI uri) {
return null;
}
public static javax.ws.rs.core.UriBuilder fromUri(java.lang.String uriTemplate) {
return null;
}
public static javax.ws.rs.core.UriBuilder fromLink(javax.ws.rs.core.Link link) {
return null;
}
public static javax.ws.rs.core.UriBuilder fromPath(java.lang.String path)
throws java.lang.IllegalArgumentException {
return null;
}
public static javax.ws.rs.core.UriBuilder fromResource(java.lang.Class<?> resource) {
return null;
}
public static javax.ws.rs.core.UriBuilder fromMethod(java.lang.Class<?> resource, java.lang.String method) {
return null;
}
public abstract javax.ws.rs.core.UriBuilder clone();
public abstract javax.ws.rs.core.UriBuilder uri(java.net.URI arg0);
public abstract javax.ws.rs.core.UriBuilder uri(java.lang.String arg0);
public abstract java.net.URI buildFromMap(java.util.Map<java.lang.String, ?> arg0);
public abstract java.net.URI buildFromMap(java.util.Map<java.lang.String, ?> arg0, boolean arg1)
throws java.lang.IllegalArgumentException, javax.ws.rs.core.UriBuilderException;
public abstract java.net.URI buildFromEncodedMap(java.util.Map<java.lang.String, ?> arg0)
throws java.lang.IllegalArgumentException, javax.ws.rs.core.UriBuilderException;
public abstract java.net.URI build(java.lang.Object... arg0)
throws java.lang.IllegalArgumentException, javax.ws.rs.core.UriBuilderException;
public abstract java.net.URI build(java.lang.Object[] arg0, boolean arg1)
throws java.lang.IllegalArgumentException, javax.ws.rs.core.UriBuilderException;
public abstract java.net.URI buildFromEncoded(java.lang.Object... arg0)
throws java.lang.IllegalArgumentException, javax.ws.rs.core.UriBuilderException;
}

View File

@@ -1,18 +0,0 @@
package javax.ws.rs.core;
public class UriBuilderException extends java.lang.RuntimeException {
private static final long serialVersionUID = 956255913370721193L;
public UriBuilderException() {
}
public UriBuilderException(java.lang.String msg) {
}
public UriBuilderException(java.lang.String msg, java.lang.Throwable cause) {
}
public UriBuilderException(java.lang.Throwable cause) {
}
}

View File

@@ -0,0 +1,17 @@
public class Test {
public static void test () {
String.format("%s", "", "");
String.format("s", "");
String.format("%2$s %2$s", "", "");
String.format("%2$s %1$s", "", "");
String.format("%2$s %s", "");
String.format("%s%<s", "", "");
String.format("%s%%%%%%%%s%n", "", "");
String.format("%s%%%%%%%%s%n", "");
String.format("%s%%%%%%%s%n", "", "");
String.format("%s%%%%%%%s%n", "");
String.format("%2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s", "", "");
}
}

View File

@@ -0,0 +1,22 @@
| %2$s %1$s | 1 | 5 |
| %2$s %1$s | 2 | 0 |
| %2$s %2$s | 2 | 0 |
| %2$s %2$s | 2 | 5 |
| %2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s | 1 | 11 |
| %2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s | 1 | 16 |
| %2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s | 1 | 20 |
| %2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s | 1 | 23 |
| %2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s | 1 | 27 |
| %2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s | 1 | 38 |
| %2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s | 1 | 43 |
| %2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s | 2 | 0 |
| %2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s | 2 | 31 |
| %2$s %% %n %1$s %<s %s %<s %<s %s %<s %1$s %<s | 2 | 34 |
| %2$s %s | 1 | 5 |
| %2$s %s | 2 | 0 |
| %s | 1 | 0 |
| %s%%%%%%%%s%n | 1 | 0 |
| %s%%%%%%%s%n | 1 | 0 |
| %s%%%%%%%s%n | 2 | 8 |
| %s%<s | 1 | 0 |
| %s%<s | 1 | 2 |

View File

@@ -0,0 +1,6 @@
import java
import semmle.code.java.StringFormat
from FormatString f, int argNo, int offset
where offset = f.getAnArgUsageOffset(argNo)
select f, argNo, offset

View File

@@ -0,0 +1,64 @@
import java.io.IOException;
import java.net.URI;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpTrace;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.message.BasicRequestLine;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ApacheHttpSSRF extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String sink = request.getParameter("uri");
URI uri = new URI(sink);
HttpGet httpGet = new HttpGet(uri); // $ SSRF
HttpGet httpGet2 = new HttpGet();
httpGet2.setURI(uri); // $ SSRF
new HttpHead(uri); // $ SSRF
new HttpPost(uri); // $ SSRF
new HttpPut(uri); // $ SSRF
new HttpDelete(uri); // $ SSRF
new HttpOptions(uri); // $ SSRF
new HttpTrace(uri); // $ SSRF
new HttpPatch(uri); // $ SSRF
new BasicHttpRequest(new BasicRequestLine("GET", uri.toString(), null)); // $ SSRF
new BasicHttpRequest("GET", uri.toString()); // $ SSRF
new BasicHttpRequest("GET", uri.toString(), null); // $ SSRF
new BasicHttpEntityEnclosingRequest(new BasicRequestLine("GET", uri.toString(), null)); // $ SSRF
new BasicHttpEntityEnclosingRequest("GET", uri.toString()); // $ SSRF
new BasicHttpEntityEnclosingRequest("GET", uri.toString(), null); // $ SSRF
RequestBuilder.get(uri); // $ SSRF
RequestBuilder.post(uri); // $ SSRF
RequestBuilder.put(uri); // $ SSRF
RequestBuilder.delete(uri); // $ SSRF
RequestBuilder.options(uri); // $ SSRF
RequestBuilder.head(uri); // $ SSRF
RequestBuilder.trace(uri); // $ SSRF
RequestBuilder.patch(uri); // $ SSRF
RequestBuilder.get("").setUri(uri); // $ SSRF
} catch (Exception e) {
// TODO: handle exception
}
}
}

View File

@@ -0,0 +1,18 @@
import jakarta.ws.rs.client.*;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class JakartaWsSSRF extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Client client = ClientBuilder.newClient();
String url = request.getParameter("url");
client.target(url); // $ SSRF
}
}

View File

@@ -0,0 +1,45 @@
import java.io.IOException;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.Proxy.Type;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class JavaNetHttpSSRF extends HttpServlet {
private static final String VALID_URI = "http://lgtm.com";
private HttpClient client = HttpClient.newHttpClient();
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String sink = request.getParameter("uri");
URI uri = new URI(sink);
URI uri2 = new URI("http", sink, "fragement");
URL url1 = new URL(sink);
URLConnection c1 = url1.openConnection(); // $ SSRF
SocketAddress sa = new SocketAddress() {
};
URLConnection c2 = url1.openConnection(new Proxy(Type.HTTP, sa)); // $ SSRF
InputStream c3 = url1.openStream(); // $ SSRF
// java.net.http
HttpClient client = HttpClient.newHttpClient();
HttpRequest request2 = HttpRequest.newBuilder().uri(uri2).build(); // $ SSRF
HttpRequest request3 = HttpRequest.newBuilder(uri).build(); // $ SSRF
} catch (Exception e) {
// TODO: handle exception
}
}
}

View File

@@ -1,13 +1,6 @@
import javax.ws.rs.client.*;
import java.io.IOException;
import java.net.URI;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.Proxy.Type;
import java.io.InputStream;
import org.apache.http.client.methods.HttpGet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@@ -19,7 +12,7 @@ public class JaxWsSSRF extends HttpServlet {
throws ServletException, IOException {
Client client = ClientBuilder.newClient();
String url = request.getParameter("url");
client.target(url);
client.target(url); // $ SSRF
}
}

View File

@@ -0,0 +1,18 @@
import java
import semmle.code.java.security.RequestForgeryConfig
import TestUtilities.InlineExpectationsTest
class HasFlowTest extends InlineExpectationsTest {
HasFlowTest() { this = "HasFlowTest" }
override string getARelevantTag() { result = "SSRF" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "SSRF" and
exists(RequestForgeryConfiguration conf, DataFlow::Node sink | conf.hasFlowTo(sink) |
sink.getLocation() = location and
element = sink.toString() and
value = ""
)
}
}

View File

@@ -0,0 +1,123 @@
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SanitizationTests extends HttpServlet {
private static final String VALID_URI = "http://lgtm.com";
private HttpClient client = HttpClient.newHttpClient();
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
URI uri = new URI(request.getParameter("uri"));
// BAD: a request parameter is incorporated without validation into a Http
// request
HttpRequest r = HttpRequest.newBuilder(uri).build(); // $ SSRF
client.send(r, null);
// GOOD: sanitisation by concatenation with a prefix that prevents targeting an arbitrary host.
// We test a few different ways of sanitisation: via string conctentation (perhaps nested),
// via a stringbuilder (for which we consider appends done in the constructor, chained onto
// the constructor and applied in subsequent statements) and via String.format.
String safeUri3 = "https://example.com/" + request.getParameter("uri3");
HttpRequest r3 = HttpRequest.newBuilder(new URI(safeUri3)).build();
client.send(r3, null);
String safeUri4 = "https://example.com/" + ("someprefix" + request.getParameter("uri4"));
HttpRequest r4 = HttpRequest.newBuilder(new URI(safeUri4)).build();
client.send(r4, null);
StringBuilder safeUri5 = new StringBuilder();
safeUri5.append("https://example.com/").append(request.getParameter("uri5"));
HttpRequest r5 = HttpRequest.newBuilder(new URI(safeUri5.toString())).build();
client.send(r5, null);
StringBuilder safeUri5a = new StringBuilder("https://example.com/");
safeUri5a.append(request.getParameter("uri5a"));
HttpRequest r5a = HttpRequest.newBuilder(new URI(safeUri5a.toString())).build();
client.send(r5a, null);
StringBuilder safeUri5b = (new StringBuilder("https://example.com/")).append("dir/");
safeUri5b.append(request.getParameter("uri5b"));
HttpRequest r5b = HttpRequest.newBuilder(new URI(safeUri5b.toString())).build();
client.send(r5b, null);
StringBuilder safeUri5c = (new StringBuilder("prefix")).append("https://example.com/dir/");
safeUri5c.append(request.getParameter("uri5c"));
HttpRequest r5c = HttpRequest.newBuilder(new URI(safeUri5c.toString())).build();
client.send(r5c, null);
String safeUri6 = String.format("https://example.com/%s", request.getParameter("uri6"));
HttpRequest r6 = HttpRequest.newBuilder(new URI(safeUri6)).build();
client.send(r6, null);
String safeUri7 = String.format("%s/%s", "https://example.com", request.getParameter("uri7"));
HttpRequest r7 = HttpRequest.newBuilder(new URI(safeUri7)).build();
client.send(r7, null);
String safeUri8 = String.format("%s%s", "https://example.com/", request.getParameter("uri8"));
HttpRequest r8 = HttpRequest.newBuilder(new URI(safeUri8)).build();
client.send(r8, null);
String safeUri9 = String.format("http://%s", "myserver.com") + "/" + request.getParameter("uri9");
HttpRequest r9 = HttpRequest.newBuilder(new URI(safeUri9)).build();
client.send(r9, null);
// BAD: cases where a string that would sanitise is used, but occurs in the wrong
// place to sanitise user input:
String unsafeUri3 = request.getParameter("baduri3") + "https://example.com/";
HttpRequest unsafer3 = HttpRequest.newBuilder(new URI(unsafeUri3)).build(); // $ SSRF
client.send(unsafer3, null);
String unsafeUri4 = ("someprefix" + request.getParameter("baduri4")) + "https://example.com/";
HttpRequest unsafer4 = HttpRequest.newBuilder(new URI(unsafeUri4)).build(); // $ SSRF
client.send(unsafer4, null);
StringBuilder unsafeUri5 = new StringBuilder();
unsafeUri5.append(request.getParameter("baduri5")).append("https://example.com/");
HttpRequest unsafer5 = HttpRequest.newBuilder(new URI(unsafeUri5.toString())).build(); // $ SSRF
client.send(unsafer5, null);
StringBuilder unafeUri5a = new StringBuilder(request.getParameter("uri5a"));
unafeUri5a.append("https://example.com/");
HttpRequest unsafer5a = HttpRequest.newBuilder(new URI(unafeUri5a.toString())).build(); // $ SSRF
client.send(unsafer5a, null);
StringBuilder unsafeUri5b = (new StringBuilder(request.getParameter("uri5b"))).append("dir/");
unsafeUri5b.append("https://example.com/");
HttpRequest unsafer5b = HttpRequest.newBuilder(new URI(unsafeUri5b.toString())).build(); // $ SSRF
client.send(unsafer5b, null);
StringBuilder unsafeUri5c = (new StringBuilder("https")).append(request.getParameter("uri5c"));
unsafeUri5c.append("://example.com/dir/");
HttpRequest unsafer5c = HttpRequest.newBuilder(new URI(unsafeUri5c.toString())).build(); // $ SSRF
client.send(unsafer5c, null);
String unsafeUri6 = String.format("%shttps://example.com/", request.getParameter("baduri6"));
HttpRequest unsafer6 = HttpRequest.newBuilder(new URI(unsafeUri6)).build(); // $ SSRF
client.send(unsafer6, null);
String unsafeUri7 = String.format("%s/%s", request.getParameter("baduri7"), "https://example.com");
HttpRequest unsafer7 = HttpRequest.newBuilder(new URI(unsafeUri7)).build(); // $ SSRF
client.send(unsafer7, null);
String unsafeUri8 = String.format("%s%s", request.getParameter("baduri8"), "https://example.com/");
HttpRequest unsafer8 = HttpRequest.newBuilder(new URI(unsafeUri8)).build(); // $ SSRF
client.send(unsafer8, null);
String unsafeUri9 = request.getParameter("baduri9") + "/" + String.format("http://%s", "myserver.com");
HttpRequest unsafer9 = HttpRequest.newBuilder(new URI(unsafeUri9)).build(); // $ SSRF
client.send(unsafer9, null);
} catch (Exception e) {
// TODO: handle exception
}
}
}

View File

@@ -0,0 +1,70 @@
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import java.net.URI;
import org.springframework.http.HttpMethod;
import java.io.IOException;
import java.net.URI;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.Proxy.Type;
import java.io.InputStream;
import org.apache.http.client.methods.HttpGet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SpringSSRF extends HttpServlet {
protected void doGet(HttpServletRequest request2, HttpServletResponse response2)
throws ServletException, IOException {
String fooResourceUrl = request2.getParameter("uri");;
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> request = new HttpEntity<>(new String("bar"));
try {
restTemplate.getForEntity(fooResourceUrl + "/1", String.class); // $ SSRF
restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, String.class); // $ SSRF
restTemplate.execute(fooResourceUrl, HttpMethod.POST, null, null, "test"); // $ SSRF
restTemplate.getForObject(fooResourceUrl, String.class, "test"); // $ SSRF
restTemplate.patchForObject(fooResourceUrl, new String("object"), String.class, "hi"); // $ SSRF
restTemplate.postForEntity(new URI(fooResourceUrl), new String("object"), String.class); // $ SSRF
restTemplate.postForLocation(fooResourceUrl, new String("object")); // $ SSRF
restTemplate.postForObject(fooResourceUrl, new String("object"), String.class); // $ SSRF
restTemplate.put(fooResourceUrl, new String("object")); // $ SSRF
restTemplate.delete(fooResourceUrl); // $ SSRF
restTemplate.headForHeaders(fooResourceUrl); // $ SSRF
restTemplate.optionsForAllow(fooResourceUrl); // $ SSRF
{
String body = new String("body");
URI uri = new URI(fooResourceUrl);
RequestEntity<String> requestEntity =
RequestEntity.post(uri).body(body); // $ SSRF
ResponseEntity<String> response = restTemplate.exchange(requestEntity, String.class);
RequestEntity.get(uri); // $ SSRF
RequestEntity.put(uri); // $ SSRF
RequestEntity.delete(uri); // $ SSRF
RequestEntity.options(uri); // $ SSRF
RequestEntity.patch(uri); // $ SSRF
RequestEntity.head(uri); // $ SSRF
RequestEntity.method(null, uri); // $ SSRF
}
{
URI uri = new URI(fooResourceUrl);
MultiValueMap<String, String> headers = null;
java.lang.reflect.Type type = null;
new RequestEntity<String>(null, uri); // $ SSRF
new RequestEntity<String>(headers, null, uri); // $ SSRF
new RequestEntity<String>("body", null, uri); // $ SSRF
new RequestEntity<String>("body", headers, null, uri); // $ SSRF
new RequestEntity<String>("body", null, uri, type); // $ SSRF
new RequestEntity<String>("body", headers, null, uri, type); // $ SSRF
}
} catch (org.springframework.web.client.RestClientException | java.net.URISyntaxException e) {}
}
}

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/apache-http-4.4.13/:${testdir}/../../../stubs/servlet-api-2.4/

View File

@@ -0,0 +1,45 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation defines behavioral contract enforced at runtime by instances of annotated classes.
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Contract {
ThreadingBehavior threading() default ThreadingBehavior.UNSAFE;
}

View File

@@ -0,0 +1,233 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http;
import java.io.Serializable;
import java.net.InetAddress;
import org.apache.http.annotation.ThreadingBehavior;
import org.apache.http.annotation.Contract;
/**
* Holds all of the variables needed to describe an HTTP connection to a host.
* This includes remote host name, port and scheme.
*
* @since 4.0
*/
@Contract(threading = ThreadingBehavior.IMMUTABLE)
public final class HttpHost implements Cloneable, Serializable {
/** The default scheme is "http". */
public static final String DEFAULT_SCHEME_NAME = "http";
/**
* Creates {@code HttpHost} instance with the given scheme, hostname and port.
*
* @param hostname the hostname (IP or DNS name)
* @param port the port number.
* {@code -1} indicates the scheme default port.
* @param scheme the name of the scheme.
* {@code null} indicates the
* {@link #DEFAULT_SCHEME_NAME default scheme}
*/
public HttpHost(final String hostname, final int port, final String scheme) {
}
/**
* Creates {@code HttpHost} instance with the default scheme and the given hostname and port.
*
* @param hostname the hostname (IP or DNS name)
* @param port the port number.
* {@code -1} indicates the scheme default port.
*/
public HttpHost(final String hostname, final int port) {
}
/**
* Creates {@code HttpHost} instance from string. Text may not contain any blanks.
*
* @since 4.4
*/
public static HttpHost create(final String s) {
return null;
}
/**
* Creates {@code HttpHost} instance with the default scheme and port and the given hostname.
*
* @param hostname the hostname (IP or DNS name)
*/
public HttpHost(final String hostname) {
}
/**
* Creates {@code HttpHost} instance with the given scheme, inet address and port.
*
* @param address the inet address.
* @param port the port number.
* {@code -1} indicates the scheme default port.
* @param scheme the name of the scheme.
* {@code null} indicates the
* {@link #DEFAULT_SCHEME_NAME default scheme}
*
* @since 4.3
*/
public HttpHost(final InetAddress address, final int port, final String scheme) {
}
/**
* Creates a new {@link HttpHost HttpHost}, specifying all values.
* Constructor for HttpHost.
*
* @param address the inet address.
* @param hostname the hostname (IP or DNS name)
* @param port the port number.
* {@code -1} indicates the scheme default port.
* @param scheme the name of the scheme.
* {@code null} indicates the
* {@link #DEFAULT_SCHEME_NAME default scheme}
*
* @since 4.4
*/
public HttpHost(final InetAddress address, final String hostname, final int port, final String scheme) {
}
/**
* Creates {@code HttpHost} instance with the default scheme and the given inet address
* and port.
*
* @param address the inet address.
* @param port the port number.
* {@code -1} indicates the scheme default port.
*
* @since 4.3
*/
public HttpHost(final InetAddress address, final int port) {
}
/**
* Creates {@code HttpHost} instance with the default scheme and port and the given inet
* address.
*
* @param address the inet address.
*
* @since 4.3
*/
public HttpHost(final InetAddress address) {
}
/**
* Copy constructor for {@link HttpHost HttpHost}.
*
* @param httphost the HTTP host to copy details from
*/
public HttpHost (final HttpHost httphost) {
}
/**
* Returns the host name.
*
* @return the host name (IP or DNS name)
*/
public String getHostName() {
return null;
}
/**
* Returns the port.
*
* @return the host port, or {@code -1} if not set
*/
public int getPort() {
return 0;
}
/**
* Returns the scheme name.
*
* @return the scheme name
*/
public String getSchemeName() {
return null;
}
/**
* Returns the inet address if explicitly set by a constructor,
* {@code null} otherwise.
* @return the inet address
*
* @since 4.3
*/
public InetAddress getAddress() {
return null;
}
/**
* Return the host URI, as a string.
*
* @return the host URI
*/
public String toURI() {
return null;
}
/**
* Obtains the host string, without scheme prefix.
*
* @return the host string, for example {@code localhost:8080}
*/
public String toHostString() {
return null;
}
@Override
public String toString() {
return null;
}
@Override
public boolean equals(final Object obj) {
return false;
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return 0;
}
@Override
public Object clone() throws CloneNotSupportedException {
return null;
}
}

View File

@@ -0,0 +1,45 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation defines behavioral contract enforced at runtime by instances of annotated classes.
*/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Contract {
ThreadingBehavior threading() default ThreadingBehavior.UNSAFE;
}

View File

@@ -0,0 +1,63 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.annotation;
/**
Defines types of threading behavior enforced at runtime.
*/
public enum ThreadingBehavior {
/**
* Instances of classes with the given contract are expected to be fully immutable
* and thread-safe.
*/
IMMUTABLE,
/**
* Instances of classes with the given contract are expected to be immutable if their
* dependencies injected at construction time are immutable and are expected to be thread-safe
* if their dependencies are thread-safe.
*/
IMMUTABLE_CONDITIONAL,
/**
* Instances of classes with the given contract are expected to be fully thread-safe.
*/
SAFE,
/**
* Instances of classes with the given contract are expected to be thread-safe if their
* dependencies injected at construction time are thread-safe.
*/
SAFE_CONDITIONAL,
/**
* Instances of classes with the given contract are expected to be non thread-safe.
*/
UNSAFE
}

View File

@@ -0,0 +1,423 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.client.config;
import java.net.InetAddress;
import java.util.Collection;
import org.apache.http.HttpHost;
import org.apache.http.annotation.Contract;
import org.apache.http.annotation.ThreadingBehavior;
/**
* Immutable class encapsulating request configuration items.
* The default setting for stale connection checking changed
* to false, and the feature was deprecated starting with version 4.4.
*/
@Contract(threading = ThreadingBehavior.IMMUTABLE)
public class RequestConfig implements Cloneable {
public static final RequestConfig DEFAULT = null;
/**
* Intended for CDI compatibility
*/
protected RequestConfig() {
}
RequestConfig(
final boolean expectContinueEnabled,
final HttpHost proxy,
final InetAddress localAddress,
final boolean staleConnectionCheckEnabled,
final String cookieSpec,
final boolean redirectsEnabled,
final boolean relativeRedirectsAllowed,
final boolean circularRedirectsAllowed,
final int maxRedirects,
final boolean authenticationEnabled,
final Collection<String> targetPreferredAuthSchemes,
final Collection<String> proxyPreferredAuthSchemes,
final int connectionRequestTimeout,
final int connectTimeout,
final int socketTimeout,
final boolean contentCompressionEnabled,
final boolean normalizeUri) {
}
/**
* Determines whether the 'Expect: 100-Continue' handshake is enabled
* for entity enclosing methods. The purpose of the 'Expect: 100-Continue'
* handshake is to allow a client that is sending a request message with
* a request body to determine if the origin server is willing to
* accept the request (based on the request headers) before the client
* sends the request body.
* <p>
* The use of the 'Expect: 100-continue' handshake can result in
* a noticeable performance improvement for entity enclosing requests
* (such as POST and PUT) that require the target server's
* authentication.
* </p>
* <p>
* 'Expect: 100-continue' handshake should be used with caution, as it
* may cause problems with HTTP servers and proxies that do not support
* HTTP/1.1 protocol.
* </p>
* <p>
* Default: {@code false}
* </p>
*/
public boolean isExpectContinueEnabled() {
return false;
}
/**
* Returns HTTP proxy to be used for request execution.
* <p>
* Default: {@code null}
* </p>
*/
public HttpHost getProxy() {
return null;
}
/**
* Returns local address to be used for request execution.
* <p>
* On machines with multiple network interfaces, this parameter
* can be used to select the network interface from which the
* connection originates.
* </p>
* <p>
* Default: {@code null}
* </p>
*/
public InetAddress getLocalAddress() {
return null;
}
/**
* Determines whether stale connection check is to be used. The stale
* connection check can cause up to 30 millisecond overhead per request and
* should be used only when appropriate. For performance critical
* operations this check should be disabled.
* <p>
* Default: {@code false} since 4.4
* </p>
*
* @deprecated (4.4) Use {@link
* org.apache.http.impl.conn.PoolingHttpClientConnectionManager#getValidateAfterInactivity()}
*/
@Deprecated
public boolean isStaleConnectionCheckEnabled() {
return false;
}
/**
* Determines the name of the cookie specification to be used for HTTP state
* management.
* <p>
* Default: {@code null}
* </p>
*/
public String getCookieSpec() {
return null;
}
/**
* Determines whether redirects should be handled automatically.
* <p>
* Default: {@code true}
* </p>
*/
public boolean isRedirectsEnabled() {
return false;
}
/**
* Determines whether relative redirects should be rejected. HTTP specification
* requires the location value be an absolute URI.
* <p>
* Default: {@code true}
* </p>
*/
public boolean isRelativeRedirectsAllowed() {
return false;
}
/**
* Determines whether circular redirects (redirects to the same location) should
* be allowed. The HTTP spec is not sufficiently clear whether circular redirects
* are permitted, therefore optionally they can be enabled
* <p>
* Default: {@code false}
* </p>
*/
public boolean isCircularRedirectsAllowed() {
return false;
}
/**
* Returns the maximum number of redirects to be followed. The limit on number
* of redirects is intended to prevent infinite loops.
* <p>
* Default: {@code 50}
* </p>
*/
public int getMaxRedirects() {
return 0;
}
/**
* Determines whether authentication should be handled automatically.
* <p>
* Default: {@code true}
* </p>
*/
public boolean isAuthenticationEnabled() {
return false;
}
/**
* Determines the order of preference for supported authentication schemes
* when authenticating with the target host.
* <p>
* Default: {@code null}
* </p>
*/
public Collection<String> getTargetPreferredAuthSchemes() {
return null;
}
/**
* Determines the order of preference for supported authentication schemes
* when authenticating with the proxy host.
* <p>
* Default: {@code null}
* </p>
*/
public Collection<String> getProxyPreferredAuthSchemes() {
return null;
}
/**
* Returns the timeout in milliseconds used when requesting a connection
* from the connection manager.
* <p>
* A timeout value of zero is interpreted as an infinite timeout.
* A negative value is interpreted as undefined (system default if applicable).
* </p>
* <p>
* Default: {@code -1}
* </p>
*/
public int getConnectionRequestTimeout() {
return 0;
}
/**
* Determines the timeout in milliseconds until a connection is established.
* <p>
* A timeout value of zero is interpreted as an infinite timeout.
* A negative value is interpreted as undefined (system default if applicable).
* </p>
* <p>
* Default: {@code -1}
* </p>
*/
public int getConnectTimeout() {
return 0;
}
/**
* Defines the socket timeout ({@code SO_TIMEOUT}) in milliseconds,
* which is the timeout for waiting for data or, put differently,
* a maximum period inactivity between two consecutive data packets).
* <p>
* A timeout value of zero is interpreted as an infinite timeout.
* A negative value is interpreted as undefined (system default if applicable).
* </p>
* <p>
* Default: {@code -1}
* </p>
*/
public int getSocketTimeout() {
return 0;
}
/**
* Determines whether compressed entities should be decompressed automatically.
* <p>
* Default: {@code true}
* </p>
*
* @since 4.4
* @deprecated (4.5) Use {@link #isContentCompressionEnabled()}
*/
@Deprecated
public boolean isDecompressionEnabled() {
return false;
}
/**
* Determines whether the target server is requested to compress content.
* <p>
* Default: {@code true}
* </p>
*
* @since 4.5
*/
public boolean isContentCompressionEnabled() {
return false;
}
/**
* Determines whether client should normalize URIs in requests or not.
* <p>
* Default: {@code true}
* </p>
*
* @since 4.5.8
*/
public boolean isNormalizeUri() {
return false;
}
@Override
protected RequestConfig clone() throws CloneNotSupportedException {
return null;
}
@Override
public String toString() {
return null;
}
public static RequestConfig.Builder custom() {
return null;
}
@SuppressWarnings("deprecation")
public static RequestConfig.Builder copy(final RequestConfig config) {
return null;
}
public static class Builder {
Builder() {
}
public Builder setExpectContinueEnabled(final boolean expectContinueEnabled) {
return null;
}
public Builder setProxy(final HttpHost proxy) {
return null;
}
public Builder setLocalAddress(final InetAddress localAddress) {
return null;
}
/**
* @deprecated (4.4) Use {@link
* org.apache.http.impl.conn.PoolingHttpClientConnectionManager#setValidateAfterInactivity(int)}
*/
@Deprecated
public Builder setStaleConnectionCheckEnabled(final boolean staleConnectionCheckEnabled) {
return null;
}
public Builder setCookieSpec(final String cookieSpec) {
return null;
}
public Builder setRedirectsEnabled(final boolean redirectsEnabled) {
return null;
}
public Builder setRelativeRedirectsAllowed(final boolean relativeRedirectsAllowed) {
return null;
}
public Builder setCircularRedirectsAllowed(final boolean circularRedirectsAllowed) {
return null;
}
public Builder setMaxRedirects(final int maxRedirects) {
return null;
}
public Builder setAuthenticationEnabled(final boolean authenticationEnabled) {
return null;
}
public Builder setTargetPreferredAuthSchemes(final Collection<String> targetPreferredAuthSchemes) {
return null;
}
public Builder setProxyPreferredAuthSchemes(final Collection<String> proxyPreferredAuthSchemes) {
return null;
}
public Builder setConnectionRequestTimeout(final int connectionRequestTimeout) {
return null;
}
public Builder setConnectTimeout(final int connectTimeout) {
return null;
}
public Builder setSocketTimeout(final int socketTimeout) {
return null;
}
/**
* @deprecated (4.5) Set {@link #setContentCompressionEnabled(boolean)} to {@code false} and
* add the {@code Accept-Encoding} request header.
*/
@Deprecated
public Builder setDecompressionEnabled(final boolean decompressionEnabled) {
return null;
}
public Builder setContentCompressionEnabled(final boolean contentCompressionEnabled) {
return null;
}
public Builder setNormalizeUri(final boolean normalizeUri) {
return null;
}
public RequestConfig build() {
return null;
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.client.methods;
import java.net.URI;
/**
* HTTP DELETE method
* <p>
* The HTTP DELETE method is defined in section 9.7 of
* <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
* <blockquote>
* The DELETE method requests that the origin server delete the resource
* identified by the Request-URI. [...] The client cannot
* be guaranteed that the operation has been carried out, even if the
* status code returned from the origin server indicates that the action
* has been completed successfully.
* </blockquote>
*
* @since 4.0
*/
public class HttpDelete extends HttpRequestBase {
public final static String METHOD_NAME = "DELETE";
public HttpDelete() {
}
public HttpDelete(final URI uri) {
}
/**
* @throws IllegalArgumentException if the uri is invalid.
*/
public HttpDelete(final String uri) {
}
@Override
public String getMethod() {
return METHOD_NAME;
}
}

View File

@@ -0,0 +1,72 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.client.methods;
import java.net.URI;
/**
* HTTP HEAD method.
* <p>
* The HTTP HEAD method is defined in section 9.4 of
* <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
* </p>
* <blockquote>
* The HEAD method is identical to GET except that the server MUST NOT
* return a message-body in the response. The metainformation contained
* in the HTTP headers in response to a HEAD request SHOULD be identical
* to the information sent in response to a GET request. This method can
* be used for obtaining metainformation about the entity implied by the
* request without transferring the entity-body itself. This method is
* often used for testing hypertext links for validity, accessibility,
* and recent modification.
* </blockquote>
*
* @since 4.0
*/
public class HttpHead extends HttpRequestBase {
public final static String METHOD_NAME = "HEAD";
public HttpHead() {
}
public HttpHead(final URI uri) {
}
/**
* @throws IllegalArgumentException if the uri is invalid.
*/
public HttpHead(final String uri) {
}
@Override
public String getMethod() {
return METHOD_NAME;
}
}

View File

@@ -0,0 +1,82 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.client.methods;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpResponse;
import org.apache.http.util.Args;
/**
* HTTP OPTIONS method.
* <p>
* The HTTP OPTIONS method is defined in section 9.2 of
* <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
* </p>
* <blockquote>
* The OPTIONS method represents a request for information about the
* communication options available on the request/response chain
* identified by the Request-URI. This method allows the client to
* determine the options and/or requirements associated with a resource,
* or the capabilities of a server, without implying a resource action
* or initiating a resource retrieval.
* </blockquote>
*
* @since 4.0
*/
public class HttpOptions extends HttpRequestBase {
public final static String METHOD_NAME = "OPTIONS";
public HttpOptions() {
}
public HttpOptions(final URI uri) {
}
/**
* @throws IllegalArgumentException if the uri is invalid.
*/
public HttpOptions(final String uri) {
}
@Override
public String getMethod() {
return null;
}
public Set<String> getAllowedMethods(final HttpResponse response) {
return null;
}
}

View File

@@ -0,0 +1,69 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.client.methods;
import java.net.URI;
/**
* HTTP PATCH method.
* <p>
* The HTTP PATCH method is defined in <a
* href="http://tools.ietf.org/html/rfc5789">RF5789</a>:
* </p>
* <blockquote> The PATCH
* method requests that a set of changes described in the request entity be
* applied to the resource identified by the Request- URI. Differs from the PUT
* method in the way the server processes the enclosed entity to modify the
* resource identified by the Request-URI. In a PUT request, the enclosed entity
* origin server, and the client is requesting that the stored version be
* replaced. With PATCH, however, the enclosed entity contains a set of
* instructions describing how a resource currently residing on the origin
* server should be modified to produce a new version.
* </blockquote>
*
* @since 4.2
*/
public class HttpPatch extends HttpEntityEnclosingRequestBase {
public final static String METHOD_NAME = "PATCH";
public HttpPatch() {
}
public HttpPatch(final URI uri) {
}
public HttpPatch(final String uri) {
}
@Override
public String getMethod() {
return null;
}
}

View File

@@ -0,0 +1,71 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.client.methods;
import java.net.URI;
/**
* HTTP TRACE method.
* <p>
* The HTTP TRACE method is defined in section 9.6 of
* <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
* </p>
* <blockquote>
* The TRACE method is used to invoke a remote, application-layer loop-
* back of the request message. The final recipient of the request
* SHOULD reflect the message received back to the client as the
* entity-body of a 200 (OK) response. The final recipient is either the
* origin server or the first proxy or gateway to receive a Max-Forwards
* value of zero (0) in the request (see section 14.31). A TRACE request
* MUST NOT include an entity.
* </blockquote>
*
* @since 4.0
*/
public class HttpTrace extends HttpRequestBase {
public final static String METHOD_NAME = "TRACE";
public HttpTrace() {
}
public HttpTrace(final URI uri) {
}
/**
* @throws IllegalArgumentException if the uri is invalid.
*/
public HttpTrace(final String uri) {
}
@Override
public String getMethod() {
return METHOD_NAME;
}
}

View File

@@ -0,0 +1,85 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.client.methods;
import java.net.URI;
import org.apache.http.HttpRequest;
/**
* Extended version of the {@link HttpRequest} interface that provides
* convenience methods to access request properties such as request URI
* and method type.
*
* @since 4.0
*/
public interface HttpUriRequest extends HttpRequest {
/**
* Returns the HTTP method this request uses, such as {@code GET},
* {@code PUT}, {@code POST}, or other.
*/
String getMethod();
/**
* Returns the URI this request uses, such as
* {@code http://example.org/path/to/file}.
* <p>
* Note that the URI may be absolute URI (as above) or may be a relative URI.
* </p>
* <p>
* Implementations are encouraged to return
* the URI that was initially requested.
* </p>
* <p>
* To find the final URI after any redirects have been processed,
* please see the section entitled
* <a href="http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d4e205">HTTP execution context</a>
* in the
* <a href="http://hc.apache.org/httpcomponents-client-ga/tutorial/html">HttpClient Tutorial</a>
* </p>
*/
URI getURI();
/**
* Aborts execution of the request.
*
* @throws UnsupportedOperationException if the abort operation
* is not supported / cannot be implemented.
*/
void abort() throws UnsupportedOperationException;
/**
* Tests if the request execution has been aborted.
*
* @return {@code true} if the request execution has been aborted,
* {@code false} otherwise.
*/
boolean isAborted();
}

View File

@@ -0,0 +1,369 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.client.methods;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.List;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.config.RequestConfig;
/**
* Builder for {@link HttpUriRequest} instances.
* <p>
* Please note that this class treats parameters differently depending on composition
* of the request: if the request has a content entity explicitly set with
* {@link #setEntity(org.apache.http.HttpEntity)} or it is not an entity enclosing method
* (such as POST or PUT), parameters will be added to the query component of the request URI.
* Otherwise, parameters will be added as a URL encoded {@link UrlEncodedFormEntity entity}.
* </p>
*
* @since 4.3
*/
public class RequestBuilder {
RequestBuilder(final String method) {
}
RequestBuilder(final String method, final URI uri) {
}
RequestBuilder(final String method, final String uri) {
}
RequestBuilder() {
}
public static RequestBuilder create(final String method) {
return null;
}
public static RequestBuilder get() {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder get(final URI uri) {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder get(final String uri) {
return null;
}
public static RequestBuilder head() {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder head(final URI uri) {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder head(final String uri) {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder patch() {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder patch(final URI uri) {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder patch(final String uri) {
return null;
}
public static RequestBuilder post() {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder post(final URI uri) {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder post(final String uri) {
return null;
}
public static RequestBuilder put() {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder put(final URI uri) {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder put(final String uri) {
return null;
}
public static RequestBuilder delete() {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder delete(final URI uri) {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder delete(final String uri) {
return null;
}
public static RequestBuilder trace() {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder trace(final URI uri) {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder trace(final String uri) {
return null;
}
public static RequestBuilder options() {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder options(final URI uri) {
return null;
}
/**
* @since 4.4
*/
public static RequestBuilder options(final String uri) {
return null;
}
public static RequestBuilder copy(final HttpRequest request) {
return null;
}
private RequestBuilder doCopy(final HttpRequest request) {
return null;
}
/**
* @since 4.4
*/
public RequestBuilder setCharset(final Charset charset) {
return null;
}
/**
* @since 4.4
*/
public Charset getCharset() {
return null;
}
public String getMethod() {
return null;
}
public ProtocolVersion getVersion() {
return null;
}
public RequestBuilder setVersion(final ProtocolVersion version) {
return null;
}
public URI getUri() {
return null;
}
public RequestBuilder setUri(final URI uri) {
return null;
}
public RequestBuilder setUri(final String uri) {
return null;
}
public Header getFirstHeader(final String name) {
return null;
}
public Header getLastHeader(final String name) {
return null;
}
public Header[] getHeaders(final String name) {
return null;
}
public RequestBuilder addHeader(final Header header) {
return null;
}
public RequestBuilder addHeader(final String name, final String value) {
return null;
}
public RequestBuilder removeHeader(final Header header) {
return null;
}
public RequestBuilder removeHeaders(final String name) {
return null;
}
public RequestBuilder setHeader(final Header header) {
return null;
}
public RequestBuilder setHeader(final String name, final String value) {
return null;
}
public HttpEntity getEntity() {
return null;
}
public RequestBuilder setEntity(final HttpEntity entity) {
return null;
}
public List<NameValuePair> getParameters() {
return null;
}
public RequestBuilder addParameter(final NameValuePair nvp) {
return null;
}
public RequestBuilder addParameter(final String name, final String value) {
return null;
}
public RequestBuilder addParameters(final NameValuePair... nvps) {
return null;
}
public RequestConfig getConfig() {
return null;
}
public RequestBuilder setConfig(final RequestConfig config) {
return null;
}
public HttpUriRequest build() {
return null;
}
static class InternalRequest extends HttpRequestBase {
InternalRequest(final String method) {
}
@Override
public String getMethod() {
return null;
}
}
static class InternalEntityEclosingRequest extends HttpEntityEnclosingRequestBase {
InternalEntityEclosingRequest(final String method) {
}
@Override
public String getMethod() {
return null;
}
}
@Override
public String toString() {
return null;
}
}

View File

@@ -43,7 +43,7 @@ import org.apache.http.RequestLine;
* @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
*
* @version $Revision: 618017 $
*
*
* @since 4.0
*
* @deprecated Please use {@link java.net.URL#openConnection} instead. Please
@@ -54,15 +54,15 @@ import org.apache.http.RequestLine;
@Deprecated
public class BasicHttpEntityEnclosingRequest extends BasicHttpRequest implements HttpEntityEnclosingRequest {
public BasicHttpEntityEnclosingRequest(final String method, final String uri) {
super(method, uri);
super(null);
}
public BasicHttpEntityEnclosingRequest(final String method, final String uri, final ProtocolVersion ver) {
super(method, uri, ver);
super(null);
}
public BasicHttpEntityEnclosingRequest(final RequestLine requestline) {
super(requestline);
super(null);
}
public HttpEntity getEntity() {

View File

@@ -15,23 +15,23 @@
*/
package javax.ws.rs.client;
// import java.net.URI;
import java.net.URI;
import javax.ws.rs.core.Configurable;
// import javax.ws.rs.core.Link;
// import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.UriBuilder;
// import javax.net.ssl.HostnameVerifier;
// import javax.net.ssl.SSLContext;
public interface Client extends Configurable<Client> {
public void close();
// public WebTarget target(String uri);
public WebTarget target(String uri);
// public WebTarget target(URI uri);
public WebTarget target(URI uri);
// public WebTarget target(UriBuilder uriBuilder);
public WebTarget target(UriBuilder uriBuilder);
// public WebTarget target(Link link);
public WebTarget target(Link link);
// public Invocation.Builder invocation(Link link);

View File

@@ -15,23 +15,23 @@
*/
package jakarta.ws.rs.client;
// import java.net.URI;
import java.net.URI;
// import javax.net.ssl.HostnameVerifier;
// import javax.net.ssl.SSLContext;
import jakarta.ws.rs.core.Configurable;
// import jakarta.ws.rs.core.Link;
// import jakarta.ws.rs.core.UriBuilder;
import jakarta.ws.rs.core.Link;
import jakarta.ws.rs.core.UriBuilder;
public interface Client extends Configurable<Client> {
public void close();
// public WebTarget target(String uri);
public WebTarget target(String uri);
// public WebTarget target(URI uri);
public WebTarget target(URI uri);
// public WebTarget target(UriBuilder uriBuilder);
public WebTarget target(UriBuilder uriBuilder);
// public WebTarget target(Link link);
public WebTarget target(Link link);
// public Invocation.Builder invocation(Link link);

View File

@@ -0,0 +1,19 @@
package jakarta.ws.rs.client;
public abstract class ClientBuilder implements jakarta.ws.rs.core.Configurable {
protected ClientBuilder() {
}
public static jakarta.ws.rs.client.ClientBuilder newBuilder() {
return null;
}
public static jakarta.ws.rs.client.Client newClient() {
return null;
}
public static jakarta.ws.rs.client.Client newClient(jakarta.ws.rs.core.Configuration configuration) {
return null;
}
}

View File

@@ -0,0 +1,4 @@
package jakarta.ws.rs.client;
public abstract interface WebTarget extends jakarta.ws.rs.core.Configurable {
}

View File

@@ -0,0 +1,3 @@
package jakarta.ws.rs.core;
public abstract interface Configuration {}