mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #5686 from smowton/haby0/JsonHijacking
Java: JSONP Injection w/cleanups
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/** Json string type data. */
|
||||
abstract class JsonStringSource extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* Convert to String using Gson library. *
|
||||
*
|
||||
* For example, in the method access `Gson.toJson(...)`,
|
||||
* the `Object` type data is converted to the `String` type data.
|
||||
*/
|
||||
private class GsonString extends JsonStringSource {
|
||||
GsonString() {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
m.hasName("toJson") and
|
||||
m.getDeclaringType().getASupertype*().hasQualifiedName("com.google.gson", "Gson") and
|
||||
this.asExpr() = ma
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to String using Fastjson library.
|
||||
*
|
||||
* For example, in the method access `JSON.toJSONString(...)`,
|
||||
* the `Object` type data is converted to the `String` type data.
|
||||
*/
|
||||
private class FastjsonString extends JsonStringSource {
|
||||
FastjsonString() {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
m.hasName("toJSONString") and
|
||||
m.getDeclaringType().getASupertype*().hasQualifiedName("com.alibaba.fastjson", "JSON") and
|
||||
this.asExpr() = ma
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to String using Jackson library.
|
||||
*
|
||||
* For example, in the method access `ObjectMapper.writeValueAsString(...)`,
|
||||
* the `Object` type data is converted to the `String` type data.
|
||||
*/
|
||||
private class JacksonString extends JsonStringSource {
|
||||
JacksonString() {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
m.hasName("writeValueAsString") and
|
||||
m.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.hasQualifiedName("com.fasterxml.jackson.databind", "ObjectMapper") and
|
||||
this.asExpr() = ma
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Controller
|
||||
public class JsonpInjection {
|
||||
|
||||
private static HashMap hashMap = new HashMap();
|
||||
|
||||
static {
|
||||
hashMap.put("username","admin");
|
||||
hashMap.put("password","123456");
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp1")
|
||||
@ResponseBody
|
||||
public String bad1(HttpServletRequest request) {
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
Gson gson = new Gson();
|
||||
String result = gson.toJson(hashMap);
|
||||
resultStr = jsonpCallback + "(" + result + ")";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp2")
|
||||
@ResponseBody
|
||||
public String bad2(HttpServletRequest request) {
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp3")
|
||||
@ResponseBody
|
||||
public String bad3(HttpServletRequest request) {
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
String jsonStr = getJsonStr(hashMap);
|
||||
resultStr = jsonpCallback + "(" + jsonStr + ")";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp4")
|
||||
@ResponseBody
|
||||
public String bad4(HttpServletRequest request) {
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
String restr = JSONObject.toJSONString(hashMap);
|
||||
resultStr = jsonpCallback + "(" + restr + ");";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp5")
|
||||
@ResponseBody
|
||||
public void bad5(HttpServletRequest request,
|
||||
HttpServletResponse response) throws Exception {
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
PrintWriter pw = null;
|
||||
Gson gson = new Gson();
|
||||
String result = gson.toJson(hashMap);
|
||||
String resultStr = null;
|
||||
pw = response.getWriter();
|
||||
resultStr = jsonpCallback + "(" + result + ")";
|
||||
pw.println(resultStr);
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp6")
|
||||
@ResponseBody
|
||||
public void bad6(HttpServletRequest request,
|
||||
HttpServletResponse response) throws Exception {
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
PrintWriter pw = null;
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String result = mapper.writeValueAsString(hashMap);
|
||||
String resultStr = null;
|
||||
pw = response.getWriter();
|
||||
resultStr = jsonpCallback + "(" + result + ")";
|
||||
pw.println(resultStr);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "jsonp7", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public String bad7(HttpServletRequest request) {
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
Gson gson = new Gson();
|
||||
String result = gson.toJson(hashMap);
|
||||
resultStr = jsonpCallback + "(" + result + ")";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "jsonp11")
|
||||
@ResponseBody
|
||||
public String good1(HttpServletRequest request) {
|
||||
JSONObject parameterObj = readToJSONObect(request);
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
String restr = JSONObject.toJSONString(hashMap);
|
||||
resultStr = jsonpCallback + "(" + restr + ");";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "jsonp12")
|
||||
@ResponseBody
|
||||
public String good2(@RequestParam("file") MultipartFile file,HttpServletRequest request) {
|
||||
if(null == file){
|
||||
return "upload file error";
|
||||
}
|
||||
String fileName = file.getOriginalFilename();
|
||||
System.out.println("file operations");
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
String restr = JSONObject.toJSONString(hashMap);
|
||||
resultStr = jsonpCallback + "(" + restr + ");";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
public static JSONObject readToJSONObect(HttpServletRequest request){
|
||||
String jsonText = readPostContent(request);
|
||||
JSONObject jsonObj = JSONObject.parseObject(jsonText, JSONObject.class);
|
||||
return jsonObj;
|
||||
}
|
||||
|
||||
public static String readPostContent(HttpServletRequest request){
|
||||
BufferedReader in= null;
|
||||
String content = null;
|
||||
String line = null;
|
||||
try {
|
||||
in = new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8"));
|
||||
StringBuilder buf = new StringBuilder();
|
||||
while ((line = in.readLine()) != null) {
|
||||
buf.append(line);
|
||||
}
|
||||
content = buf.toString();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String uri = request.getRequestURI();
|
||||
return content;
|
||||
}
|
||||
|
||||
public static String getJsonStr(Object result) {
|
||||
return JSONObject.toJSONString(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>The software uses external input as the function name to wrap JSON data and returns it to the client as a request response.
|
||||
When there is a cross-domain problem, this could lead to information leakage.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Adding <code>Referer</code>/<code>Origin</code> or random <code>token</code> verification processing can effectively prevent the leakage of sensitive information.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>The following examples show the bad case and the good case respectively. Bad cases, such as <code>bad1</code> to <code>bad7</code>,
|
||||
will cause information leakage when there are cross-domain problems. In a good case, for example, in the <code>good1</code>
|
||||
method and the <code>good2</code> method, When these two methods process the request, there must be a request body in the request, which does not meet the conditions of Jsonp injection.</p>
|
||||
|
||||
<sample src="JsonpInjection.java" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
OWASPLondon20161124_JSON_Hijacking_Gareth_Heyes:
|
||||
<a href="https://owasp.org/www-chapter-london/assets/slides/OWASPLondon20161124_JSON_Hijacking_Gareth_Heyes.pdf">JSON hijacking</a>.
|
||||
</li>
|
||||
<li>
|
||||
Practical JSONP Injection:
|
||||
<a href="https://securitycafe.ro/2017/01/18/practical-jsonp-injection">
|
||||
Completely controllable from the URL (GET variable)
|
||||
</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @name JSONP Injection
|
||||
* @description User-controlled callback function names that are not verified are vulnerable
|
||||
* to jsonp injection attacks.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/JSONP-Injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-352
|
||||
*/
|
||||
|
||||
import java
|
||||
import JsonpInjectionLib
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.deadcode.WebEntryPoints
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/** Taint-tracking configuration tracing flow from get method request sources to output jsonp data. */
|
||||
class RequestResponseFlowConfig extends TaintTracking::Configuration {
|
||||
RequestResponseFlowConfig() { this = "RequestResponseFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source instanceof RemoteFlowSource and
|
||||
any(RequestGetMethod m).polyCalls*(source.getEnclosingCallable())
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof XssSink and
|
||||
any(RequestGetMethod m).polyCalls*(sink.getEnclosingCallable())
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(MethodAccess ma |
|
||||
isRequestGetParamMethod(ma) and pred.asExpr() = ma.getQualifier() and succ.asExpr() = ma
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, RequestResponseFlowConfig conf
|
||||
where
|
||||
conf.hasFlowPath(source, sink) and
|
||||
exists(JsonpInjectionFlowConfig jhfc | jhfc.hasFlowTo(sink.getNode()))
|
||||
select sink.getNode(), source, sink, "Jsonp response might include code from $@.", source.getNode(),
|
||||
"this user input"
|
||||
@@ -0,0 +1,118 @@
|
||||
import java
|
||||
import DataFlow
|
||||
import JsonStringLib
|
||||
import semmle.code.java.security.XSS
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.DataFlow3
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.frameworks.spring.SpringController
|
||||
|
||||
/**
|
||||
* A method that is called to handle an HTTP GET request.
|
||||
*/
|
||||
abstract class RequestGetMethod extends Method {
|
||||
RequestGetMethod() {
|
||||
not exists(MethodAccess ma |
|
||||
// Exclude apparent GET handlers that read a request entity, because this likely indicates this is not in fact a GET handler.
|
||||
// This is particularly a problem with Spring handlers, which can sometimes neglect to specify a request method.
|
||||
// Even if it is in fact a GET handler, such a request method will be unusable in the context `<script src="...">`,
|
||||
// which is the typical use-case for JSONP but cannot supply a request body.
|
||||
ma.getMethod() instanceof ServletRequestGetBodyMethod and
|
||||
this.polyCalls*(ma.getEnclosingCallable())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Override method of `doGet` of `Servlet` subclass. */
|
||||
private class ServletGetMethod extends RequestGetMethod {
|
||||
ServletGetMethod() { isServletRequestMethod(this) and this.getName() = "doGet" }
|
||||
}
|
||||
|
||||
/** The method of SpringController class processing `get` request. */
|
||||
abstract class SpringControllerGetMethod extends RequestGetMethod { }
|
||||
|
||||
/** Method using `GetMapping` annotation in SpringController class. */
|
||||
class SpringControllerGetMappingGetMethod extends SpringControllerGetMethod {
|
||||
SpringControllerGetMappingGetMethod() {
|
||||
this.getAnAnnotation()
|
||||
.getType()
|
||||
.hasQualifiedName("org.springframework.web.bind.annotation", "GetMapping")
|
||||
}
|
||||
}
|
||||
|
||||
/** The method that uses the `RequestMapping` annotation in the SpringController class and only handles the get request. */
|
||||
class SpringControllerRequestMappingGetMethod extends SpringControllerGetMethod {
|
||||
SpringControllerRequestMappingGetMethod() {
|
||||
this.getAnAnnotation()
|
||||
.getType()
|
||||
.hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") and
|
||||
(
|
||||
this.getAnAnnotation().getValue("method").(VarAccess).getVariable().getName() = "GET" or
|
||||
this.getAnAnnotation().getValue("method").(ArrayInit).getSize() = 0 //Java code example: @RequestMapping(value = "test")
|
||||
) and
|
||||
not this.getAParamType().getName() = "MultipartFile"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A concatenate expression using `(` and `)` or `);`.
|
||||
*
|
||||
* E.g: `functionName + "(" + json + ")"` or `functionName + "(" + json + ");"`
|
||||
*/
|
||||
class JsonpBuilderExpr extends AddExpr {
|
||||
JsonpBuilderExpr() {
|
||||
getRightOperand().(CompileTimeConstantExpr).getStringValue().regexpMatch("\\);?") and
|
||||
getLeftOperand()
|
||||
.(AddExpr)
|
||||
.getLeftOperand()
|
||||
.(AddExpr)
|
||||
.getRightOperand()
|
||||
.(CompileTimeConstantExpr)
|
||||
.getStringValue() = "("
|
||||
}
|
||||
|
||||
/** Get the jsonp function name of this expression. */
|
||||
Expr getFunctionName() {
|
||||
result = getLeftOperand().(AddExpr).getLeftOperand().(AddExpr).getLeftOperand()
|
||||
}
|
||||
|
||||
/** Get the json data of this expression. */
|
||||
Expr getJsonExpr() { result = getLeftOperand().(AddExpr).getRightOperand() }
|
||||
}
|
||||
|
||||
/** A data flow configuration tracing flow from remote sources to jsonp function name. */
|
||||
class RemoteFlowConfig extends DataFlow2::Configuration {
|
||||
RemoteFlowConfig() { this = "RemoteFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(JsonpBuilderExpr jhe | jhe.getFunctionName() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/** A data flow configuration tracing flow from json data into the argument `json` of JSONP-like string `someFunctionName + "(" + json + ")"`. */
|
||||
class JsonDataFlowConfig extends DataFlow2::Configuration {
|
||||
JsonDataFlowConfig() { this = "JsonDataFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof JsonStringSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(JsonpBuilderExpr jhe | jhe.getJsonExpr() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/** Taint-tracking configuration tracing flow from probable jsonp data with a user-controlled function name to an outgoing HTTP entity. */
|
||||
class JsonpInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
JsonpInjectionFlowConfig() { this = "JsonpInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
exists(JsonpBuilderExpr jhe, JsonDataFlowConfig jdfc, RemoteFlowConfig rfc |
|
||||
jhe = src.asExpr() and
|
||||
jdfc.hasFlowTo(DataFlow::exprNode(jhe.getJsonExpr())) and
|
||||
rfc.hasFlowTo(DataFlow::exprNode(jhe.getFunctionName()))
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Controller
|
||||
public class JsonpController {
|
||||
|
||||
private static HashMap hashMap = new HashMap();
|
||||
|
||||
static {
|
||||
hashMap.put("username","admin");
|
||||
hashMap.put("password","123456");
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp1")
|
||||
@ResponseBody
|
||||
public String bad1(HttpServletRequest request) {
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
Gson gson = new Gson();
|
||||
String result = gson.toJson(hashMap);
|
||||
resultStr = jsonpCallback + "(" + result + ")";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp2")
|
||||
@ResponseBody
|
||||
public String bad2(HttpServletRequest request) {
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
resultStr = jsonpCallback + "(" + JSONObject.toJSONString(hashMap) + ")";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp3")
|
||||
@ResponseBody
|
||||
public String bad3(HttpServletRequest request) {
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
String jsonStr = getJsonStr(hashMap);
|
||||
resultStr = jsonpCallback + "(" + jsonStr + ")";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp4")
|
||||
@ResponseBody
|
||||
public String bad4(HttpServletRequest request) {
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
String restr = JSONObject.toJSONString(hashMap);
|
||||
resultStr = jsonpCallback + "(" + restr + ");";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp5")
|
||||
@ResponseBody
|
||||
public void bad5(HttpServletRequest request,
|
||||
HttpServletResponse response) throws Exception {
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
PrintWriter pw = null;
|
||||
Gson gson = new Gson();
|
||||
String result = gson.toJson(hashMap);
|
||||
String resultStr = null;
|
||||
pw = response.getWriter();
|
||||
resultStr = jsonpCallback + "(" + result + ")";
|
||||
pw.println(resultStr);
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonp6")
|
||||
@ResponseBody
|
||||
public void bad6(HttpServletRequest request,
|
||||
HttpServletResponse response) throws Exception {
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
PrintWriter pw = null;
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String result = mapper.writeValueAsString(hashMap);
|
||||
String resultStr = null;
|
||||
pw = response.getWriter();
|
||||
resultStr = jsonpCallback + "(" + result + ")";
|
||||
pw.println(resultStr);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "jsonp7", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public String bad7(HttpServletRequest request) {
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
Gson gson = new Gson();
|
||||
String result = gson.toJson(hashMap);
|
||||
resultStr = jsonpCallback + "(" + result + ")";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "jsonp11")
|
||||
@ResponseBody
|
||||
public String good1(HttpServletRequest request) {
|
||||
JSONObject parameterObj = readToJSONObect(request);
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
String restr = JSONObject.toJSONString(hashMap);
|
||||
resultStr = jsonpCallback + "(" + restr + ");";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "jsonp12")
|
||||
@ResponseBody
|
||||
public String good2(@RequestParam("file") MultipartFile file,HttpServletRequest request) {
|
||||
if(null == file){
|
||||
return "upload file error";
|
||||
}
|
||||
String fileName = file.getOriginalFilename();
|
||||
System.out.println("file operations");
|
||||
String resultStr = null;
|
||||
String jsonpCallback = request.getParameter("jsonpCallback");
|
||||
String restr = JSONObject.toJSONString(hashMap);
|
||||
resultStr = jsonpCallback + "(" + restr + ");";
|
||||
return resultStr;
|
||||
}
|
||||
|
||||
public static JSONObject readToJSONObect(HttpServletRequest request){
|
||||
String jsonText = readPostContent(request);
|
||||
JSONObject jsonObj = JSONObject.parseObject(jsonText, JSONObject.class);
|
||||
return jsonObj;
|
||||
}
|
||||
|
||||
public static String readPostContent(HttpServletRequest request){
|
||||
BufferedReader in= null;
|
||||
String content = null;
|
||||
String line = null;
|
||||
try {
|
||||
in = new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8"));
|
||||
StringBuilder buf = new StringBuilder();
|
||||
while ((line = in.readLine()) != null) {
|
||||
buf.append(line);
|
||||
}
|
||||
content = buf.toString();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String uri = request.getRequestURI();
|
||||
return content;
|
||||
}
|
||||
|
||||
public static String getJsonStr(Object result) {
|
||||
return JSONObject.toJSONString(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
edges
|
||||
| JsonpController.java:33:32:33:68 | getParameter(...) : String | JsonpController.java:37:16:37:24 | resultStr |
|
||||
| JsonpController.java:36:21:36:54 | ... + ... : String | JsonpController.java:37:16:37:24 | resultStr |
|
||||
| JsonpController.java:44:32:44:68 | getParameter(...) : String | JsonpController.java:46:16:46:24 | resultStr |
|
||||
| JsonpController.java:45:21:45:80 | ... + ... : String | JsonpController.java:46:16:46:24 | resultStr |
|
||||
| JsonpController.java:53:32:53:68 | getParameter(...) : String | JsonpController.java:56:16:56:24 | resultStr |
|
||||
| JsonpController.java:55:21:55:55 | ... + ... : String | JsonpController.java:56:16:56:24 | resultStr |
|
||||
| JsonpController.java:63:32:63:68 | getParameter(...) : String | JsonpController.java:66:16:66:24 | resultStr |
|
||||
| JsonpController.java:65:21:65:54 | ... + ... : String | JsonpController.java:66:16:66:24 | resultStr |
|
||||
| JsonpController.java:73:32:73:68 | getParameter(...) : String | JsonpController.java:80:20:80:28 | resultStr |
|
||||
| JsonpController.java:79:21:79:54 | ... + ... : String | JsonpController.java:80:20:80:28 | resultStr |
|
||||
| JsonpController.java:87:32:87:68 | getParameter(...) : String | JsonpController.java:94:20:94:28 | resultStr |
|
||||
| JsonpController.java:93:21:93:54 | ... + ... : String | JsonpController.java:94:20:94:28 | resultStr |
|
||||
| JsonpController.java:101:32:101:68 | getParameter(...) : String | JsonpController.java:105:16:105:24 | resultStr |
|
||||
| JsonpController.java:104:21:104:54 | ... + ... : String | JsonpController.java:105:16:105:24 | resultStr |
|
||||
| JsonpController.java:115:21:115:54 | ... + ... : String | JsonpController.java:116:16:116:24 | resultStr |
|
||||
| JsonpController.java:130:21:130:54 | ... + ... : String | JsonpController.java:131:16:131:24 | resultStr |
|
||||
nodes
|
||||
| JsonpController.java:33:32:33:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:36:21:36:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:37:16:37:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:37:16:37:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:44:32:44:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:45:21:45:80 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:46:16:46:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:46:16:46:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:53:32:53:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:55:21:55:55 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:56:16:56:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:56:16:56:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:63:32:63:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:65:21:65:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:66:16:66:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:66:16:66:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:73:32:73:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:79:21:79:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:80:20:80:28 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:80:20:80:28 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:87:32:87:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:93:21:93:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:94:20:94:28 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:94:20:94:28 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:101:32:101:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:104:21:104:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:105:16:105:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:105:16:105:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:115:21:115:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:116:16:116:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:130:21:130:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:131:16:131:24 | resultStr | semmle.label | resultStr |
|
||||
#select
|
||||
| JsonpController.java:37:16:37:24 | resultStr | JsonpController.java:33:32:33:68 | getParameter(...) : String | JsonpController.java:37:16:37:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:33:32:33:68 | getParameter(...) | this user input |
|
||||
| JsonpController.java:46:16:46:24 | resultStr | JsonpController.java:44:32:44:68 | getParameter(...) : String | JsonpController.java:46:16:46:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:44:32:44:68 | getParameter(...) | this user input |
|
||||
| JsonpController.java:56:16:56:24 | resultStr | JsonpController.java:53:32:53:68 | getParameter(...) : String | JsonpController.java:56:16:56:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:53:32:53:68 | getParameter(...) | this user input |
|
||||
| JsonpController.java:66:16:66:24 | resultStr | JsonpController.java:63:32:63:68 | getParameter(...) : String | JsonpController.java:66:16:66:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:63:32:63:68 | getParameter(...) | this user input |
|
||||
| JsonpController.java:80:20:80:28 | resultStr | JsonpController.java:73:32:73:68 | getParameter(...) : String | JsonpController.java:80:20:80:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:73:32:73:68 | getParameter(...) | this user input |
|
||||
| JsonpController.java:94:20:94:28 | resultStr | JsonpController.java:87:32:87:68 | getParameter(...) : String | JsonpController.java:94:20:94:28 | resultStr | Jsonp response might include code from $@. | JsonpController.java:87:32:87:68 | getParameter(...) | this user input |
|
||||
| JsonpController.java:105:16:105:24 | resultStr | JsonpController.java:101:32:101:68 | getParameter(...) : String | JsonpController.java:105:16:105:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:101:32:101:68 | getParameter(...) | this user input |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-352/JsonpInjection.ql
|
||||
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-http-4.4.13/:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/fastjson-1.2.74/:${testdir}/../../../../stubs/gson-2.8.6/:${testdir}/../../../../stubs/jackson-databind-2.10/:${testdir}/../../../../stubs/springframework-5.2.3/
|
||||
@@ -26,6 +26,10 @@ import com.alibaba.fastjson.parser.*;
|
||||
import com.alibaba.fastjson.parser.deserializer.ParseProcess;
|
||||
|
||||
public abstract class JSON {
|
||||
public static String toJSONString(Object object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Object parse(String text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
7
java/ql/test/stubs/gson-2.8.6/com/google/gson/Gson.java
Normal file
7
java/ql/test/stubs/gson-2.8.6/com/google/gson/Gson.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package com.google.gson;
|
||||
|
||||
public final class Gson {
|
||||
public String toJson(Object src) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.springframework.core.annotation;
|
||||
|
||||
import java.lang.annotation.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;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
@Documented
|
||||
public @interface AliasFor {
|
||||
@AliasFor("attribute")
|
||||
String value() default "";
|
||||
|
||||
@AliasFor("value")
|
||||
String attribute() default "";
|
||||
|
||||
Class<? extends Annotation> annotation() default Annotation.class;
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
package org.springframework.stereotype;
|
||||
|
||||
import java.lang.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;
|
||||
|
||||
@Target(value=ElementType.TYPE)
|
||||
@Retention(value=RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Component
|
||||
public @interface Controller { }
|
||||
public @interface Controller {
|
||||
String value() default "";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.springframework.web.bind.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;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@RequestMapping(
|
||||
method = {RequestMethod.GET}
|
||||
)
|
||||
public @interface GetMapping {
|
||||
@AliasFor(
|
||||
annotation = RequestMapping.class
|
||||
)
|
||||
String name() default "";
|
||||
|
||||
@AliasFor(
|
||||
annotation = RequestMapping.class
|
||||
)
|
||||
String[] value() default {};
|
||||
|
||||
@AliasFor(
|
||||
annotation = RequestMapping.class
|
||||
)
|
||||
String[] path() default {};
|
||||
|
||||
@AliasFor(
|
||||
annotation = RequestMapping.class
|
||||
)
|
||||
String[] params() default {};
|
||||
|
||||
@AliasFor(
|
||||
annotation = RequestMapping.class
|
||||
)
|
||||
String[] headers() default {};
|
||||
|
||||
@AliasFor(
|
||||
annotation = RequestMapping.class
|
||||
)
|
||||
String[] consumes() default {};
|
||||
|
||||
@AliasFor(
|
||||
annotation = RequestMapping.class
|
||||
)
|
||||
String[] produces() default {};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package org.springframework.web.bind.annotation;
|
||||
|
||||
public @interface Mapping {
|
||||
}
|
||||
@@ -1,11 +1,32 @@
|
||||
package org.springframework.web.bind.annotation;
|
||||
|
||||
import java.lang.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;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
@Target(value={ElementType.METHOD,ElementType.TYPE})
|
||||
@Retention(value=RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Mapping
|
||||
public @interface RequestMapping {
|
||||
String name() default "";
|
||||
|
||||
@AliasFor("path")
|
||||
String[] value() default {};
|
||||
|
||||
@AliasFor("value")
|
||||
String[] path() default {};
|
||||
|
||||
RequestMethod[] method() default {};
|
||||
|
||||
String[] params() default {};
|
||||
|
||||
String[] headers() default {};
|
||||
|
||||
String[] consumes() default {};
|
||||
|
||||
String[] produces() default {};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
package org.springframework.web.bind.annotation;
|
||||
|
||||
import java.lang.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;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
@Target(value=ElementType.PARAMETER)
|
||||
@Retention(value=RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RequestParam { }
|
||||
public @interface RequestParam {
|
||||
@AliasFor("name")
|
||||
String value() default "";
|
||||
|
||||
@AliasFor("value")
|
||||
String name() default "";
|
||||
|
||||
boolean required() default true;
|
||||
|
||||
String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.springframework.web.bind.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;
|
||||
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface ResponseBody {
|
||||
}
|
||||
Reference in New Issue
Block a user