New model: SQL injection in MyBatis annotations

This commit is contained in:
haby0
2021-11-28 14:43:57 +08:00
parent 04a3f76a8b
commit db04a0dadf
16 changed files with 549 additions and 114 deletions

View File

@@ -40,3 +40,119 @@ class IbatisConfigurationGetVariablesMethod extends Method {
getNumberOfParameters() = 0
}
}
/**
* An annotation type that identifies Ibatis select.
*/
private class IbatisSelectAnnotationType extends AnnotationType {
IbatisSelectAnnotationType() {
this.hasQualifiedName("org.apache.ibatis.annotations", "Select") or
this.getAnAnnotation().getType() instanceof IbatisSelectAnnotationType
}
}
/**
* An annotation type that identifies Ibatis delete.
*/
private class IbatisDeleteAnnotationType extends AnnotationType {
IbatisDeleteAnnotationType() {
this.hasQualifiedName("org.apache.ibatis.annotations", "Delete") or
this.getAnAnnotation().getType() instanceof IbatisDeleteAnnotationType
}
}
/**
* An annotation type that identifies Ibatis insert.
*/
private class IbatisInsertAnnotationType extends AnnotationType {
IbatisInsertAnnotationType() {
this.hasQualifiedName("org.apache.ibatis.annotations", "Insert") or
this.getAnAnnotation().getType() instanceof IbatisInsertAnnotationType
}
}
/**
* An annotation type that identifies Ibatis update.
*/
private class IbatisUpdateAnnotationType extends AnnotationType {
IbatisUpdateAnnotationType() {
this.hasQualifiedName("org.apache.ibatis.annotations", "Update") or
this.getAnAnnotation().getType() instanceof IbatisUpdateAnnotationType
}
}
/**
* Ibatis sql operation annotation.
*/
abstract class IbatisSqlOperationAnnotation extends Annotation {
abstract string getSqlValue();
}
/**
* A `@org.apache.ibatis.annotations.Select` annotation.
*/
private class IbatisSelectAnnotation extends IbatisSqlOperationAnnotation {
IbatisSelectAnnotation() { this.getType() instanceof IbatisSelectAnnotationType }
string getSelectValue() {
result = this.getValue("value").(CompileTimeConstantExpr).getStringValue() or
result =
this.getValue("value").(ArrayInit).getInit(_).(CompileTimeConstantExpr).getStringValue()
}
override string getSqlValue() { result = getSelectValue() }
}
/**
* A `@org.apache.ibatis.annotations.Delete` annotation.
*/
private class IbatisDeleteAnnotation extends IbatisSqlOperationAnnotation {
IbatisDeleteAnnotation() { this.getType() instanceof IbatisDeleteAnnotationType }
string getDeleteValue() {
result = this.getValue("value").(CompileTimeConstantExpr).getStringValue() or
result =
this.getValue("value").(ArrayInit).getInit(_).(CompileTimeConstantExpr).getStringValue()
}
override string getSqlValue() { result = getDeleteValue() }
}
/**
* A `@org.apache.ibatis.annotations.Insert` annotation.
*/
private class IbatisInsertAnnotation extends IbatisSqlOperationAnnotation {
IbatisInsertAnnotation() { this.getType() instanceof IbatisInsertAnnotationType }
string getInsertValue() {
result = this.getValue("value").(CompileTimeConstantExpr).getStringValue() or
result =
this.getValue("value").(ArrayInit).getInit(_).(CompileTimeConstantExpr).getStringValue()
}
override string getSqlValue() { result = getInsertValue() }
}
/**
* A `@org.apache.ibatis.annotations.Update` annotation.
*/
private class IbatisUpdateAnnotation extends IbatisSqlOperationAnnotation {
IbatisUpdateAnnotation() { this.getType() instanceof IbatisUpdateAnnotationType }
string getUpdateValue() {
result = this.getValue("value").(CompileTimeConstantExpr).getStringValue() or
result =
this.getValue("value").(ArrayInit).getInit(_).(CompileTimeConstantExpr).getStringValue()
}
override string getSqlValue() { result = getUpdateValue() }
}
// Mybatis uses sql operation to annotate the method of interacting with the database.
class MybatisSqlOperationAnnotationMethod extends Method {
MybatisSqlOperationAnnotationMethod() {
exists(IbatisSqlOperationAnnotation isoa |
this.getAnAnnotation() = isoa
)
}
}

View File

@@ -0,0 +1,10 @@
import org.apache.ibatis.annotations.Select;
public interface MyBatisAnnotationSqlInjection {
@Select("select * from test where name = ${name}")
public Test bad1(String name);
@Select("select * from test where name = #{name}")
public Test good1(String name);
}

View File

@@ -0,0 +1,34 @@
<!DOCTYPE qhelp PUBLIC
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>MyBatis operates the database by using @Select, @Insert, etc. annotations in the method, and can use the $ character
to construct dynamic SQL statements. Attackers can modify the meaning of statements or execute arbitrary SQL commands.</p>
</overview>
<<recommendation>
<p>
When writing MyBatis mapping statements, try to use the format "#{xxx}". If you have to use parameters
such as "${xxx}", you must manually filter to prevent SQL injection attacks.
</p>
</recommendation>
<example>
<p>
The following examples show the bad situation and the good situation respectively. The <code>bad1</code> method uses <code>$(name)</code>
in the <code>@Select</code> annotation to dynamically splice SQL statements, and there is a SQL injection vulnerability.
The good1 method uses the <code>#{name}</code> method in the <code>@Select</code> annotation to splice SQL statements,
and the MyBatis framework will handle the dangerous characters entered by the user, And did not cause SQL injection vulnerabilities.
</p>
<sample src="MyBatisAnnotationSqlInjection.java" />
</example>
<references>
<li>
Fortify:
<a href="https://vulncat.fortify.com/en/detail?id=desc.config.java.sql_injection_mybatis_mapper">SQL Injection: MyBatis Mapper</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,64 @@
/**
* @name MyBatis annotation sql injection
* @description Constructing a dynamic SQL statement with input that comes from an
* untrusted source could allow an attacker to modify the statement's
* meaning or to execute arbitrary SQL commands.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/sql-injection
* @tags security
* external/cwe/cwe-089
*/
import java
import DataFlow::PathGraph
import MyBatisAnnotationSqlInjectionLib
import semmle.code.java.security.SanitizerGuard
import semmle.code.java.dataflow.FlowSources
private class MyBatisAnnotationSqlInjectionConfiguration extends TaintTracking::Configuration {
MyBatisAnnotationSqlInjectionConfiguration() { this = "MyBatis annotation sql injection" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
sink instanceof MyBatisAnnotationMethodCallAnArgument
}
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or
node.getType() instanceof BoxedType or
node.getType() instanceof NumberType
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof ContainsSanitizer or guard instanceof EqualsSanitizer
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma |
ma.getMethod().getDeclaringType() instanceof MapType and
ma.getMethod().getName() = "get" and
ma.getQualifier() = node1.asExpr() and
ma = node2.asExpr()
)
or
exists(MethodAccess ma |
ma.getMethod().getDeclaringType() instanceof TypeObject and
ma.getMethod().getName() = "toString" and
ma.getQualifier() = node1.asExpr() and
ma = node2.asExpr()
)
}
}
from
MyBatisAnnotationSqlInjectionConfiguration cfg, DataFlow::PathNode source,
DataFlow::PathNode sink, IbatisSqlOperationAnnotation isoa
where
cfg.hasFlowPath(source, sink) and
isMybatisAnnotationSqlInjection(sink.getNode(), isoa)
select sink.getNode(), source, sink,
"MyBatis annotation sql injection might include code from $@ to $@.", source.getNode(),
"this user input", isoa, "this sql operation"

View File

@@ -0,0 +1,126 @@
import java
import MyBatisCommonLib
import semmle.code.xml.MyBatisMapperXML
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.Properties
/** A sink for MyBatis annotation method call an argument. */
class MyBatisAnnotationMethodCallAnArgument extends DataFlow::Node {
MyBatisAnnotationMethodCallAnArgument() {
exists(MybatisSqlOperationAnnotationMethod msoam, MethodAccess ma | ma.getMethod() = msoam |
ma.getAnArgument() = this.asExpr()
)
}
}
/** Get the #{...} or ${...} parameters in the Mybatis annotation value. */
private string getAnMybatiAnnotationSetValue(IbatisSqlOperationAnnotation isoa) {
result = isoa.getSqlValue().trim().regexpFind("(#|\\$)(\\{([^\\}]*\\}))", _, _)
}
predicate isMybatisAnnotationSqlInjection(DataFlow::Node node, IbatisSqlOperationAnnotation isoa) {
// MyBatis uses an annotation method to perform SQL operations. This method has only one parameter and
// the parameter is not annotated with `@Param`. Improper use of this parameter has a SQL injection vulnerability.
// e.g.
//
// ```java
// @Select(select id,name from test where name like '%${value}%')
// Test test(String name);
// ```
exists(MybatisSqlOperationAnnotationMethod msoam, MethodAccess ma, string res |
msoam = ma.getMethod()
|
msoam.getAnAnnotation() = isoa and
res = getAnMybatiAnnotationSetValue(isoa) and
msoam.getNumberOfParameters() = 1 and
not ma.getMethod().getAParameter().hasAnnotation() and
res.matches("%${%}") and
not res.matches("${" + getAnMybatisConfigurationVariableKey() + "}") and
ma.getAnArgument() = node.asExpr()
)
or
// MyBatis uses an annotation method to perform SQL operations. The parameter type of the method parameter
// is Map or List or Array. SQL injection vulnerability caused by improper use of this parameter.
// e.g.
//
// ```java
// @Select(select id,name from test where name like '%${value}%')
// Test test(Map map);
// ```
exists(MybatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, string res |
msoam = ma.getMethod()
|
msoam.getAnAnnotation() = isoa and
not ma.getMethod().getParameter(i).hasAnnotation() and
(
ma.getMethod().getParameterType(i) instanceof MapType or
ma.getMethod().getParameterType(i) instanceof ListType or
ma.getMethod().getParameterType(i) instanceof Array
) and
res = getAnMybatiAnnotationSetValue(isoa) and
res.matches("%${%}") and
not res.matches("${" + getAnMybatisConfigurationVariableKey() + "}") and
ma.getArgument(i) = node.asExpr()
)
or
// MyBatis uses annotation methods to perform SQL operations, and SQL injection vulnerabilities caused by
// improper use of instance class fields.
// e.g.
//
// ```java
// @Select(select id,name from test order by ${name,jdbcType=VARCHAR})
// void test(Test test);
// ```
exists(MybatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, Class c |
msoam = ma.getMethod()
|
msoam.getAnAnnotation() = isoa and
not ma.getMethod().getParameter(i).hasAnnotation() and
ma.getMethod().getParameterType(i).getName() = c.getName() and
getAnMybatiAnnotationSetValue(isoa).matches("%${" + c.getAField().getName() + "%}") and
ma.getArgument(i) = node.asExpr()
)
or
// MyBatis uses annotations to perform SQL operations. The method parameters use `@Param` annotation.
// Due to improper use of this parameter, SQL injection vulnerabilities are caused.
// e.g.
//
// ```java
// @Select(select id,name from test order by ${orderby,jdbcType=VARCHAR})
// void test(@Param("orderby") String name);
// ```
exists(MybatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, Annotation annotation |
msoam = ma.getMethod()
|
msoam.getAnAnnotation() = isoa and
ma.getMethod().getParameter(i).hasAnnotation() and
ma.getMethod().getParameter(i).getAnAnnotation() = annotation and
annotation.getType() instanceof TypeParam and
getAnMybatiAnnotationSetValue(isoa)
.matches("%${" + annotation.getValue("value").(CompileTimeConstantExpr).getStringValue() +
"%}") and
ma.getArgument(i) = node.asExpr()
)
or
// MyBatis Mapper method default parameter sql injection vulnerabilities.the default parameter form of the method is arg[0...n] or param[1...n].
// e.g.
//
// ```java
// @Select(select id,name from test order by ${arg0,jdbcType=VARCHAR})
// void test(String name);
// ```
exists(MybatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, string res |
msoam = ma.getMethod()
|
msoam.getAnAnnotation() = isoa and
not ma.getMethod().getParameter(i).hasAnnotation() and
res = getAnMybatiAnnotationSetValue(isoa) and
(
res.matches("%${param" + (i + 1) + "%}")
or
res.matches("%${arg" + i + "%}")
) and
not res.matches("${" + getAnMybatisConfigurationVariableKey() + "}") and
ma.getArgument(i) = node.asExpr()
)
}

View File

@@ -0,0 +1,45 @@
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.MyBatis
import semmle.code.java.frameworks.Properties
private predicate propertiesKey(DataFlow::Node prop, string key) {
exists(MethodAccess m |
m.getMethod() instanceof PropertiesSetPropertyMethod and
key = m.getArgument(0).(CompileTimeConstantExpr).getStringValue() and
prop.asExpr() = m.getQualifier()
)
}
/** A data flow configuration tracing flow from ibatis obtaining the variable configuration object to setting the value of the variable. */
private class PropertiesFlowConfig extends DataFlow2::Configuration {
PropertiesFlowConfig() { this = "PropertiesFlowConfig" }
override predicate isSource(DataFlow::Node src) {
exists(MethodAccess ma | ma.getMethod() instanceof IbatisConfigurationGetVariablesMethod |
src.asExpr() = ma
)
}
override predicate isSink(DataFlow::Node sink) { propertiesKey(sink, _) }
}
/** Get the key value of Mybatis Configuration Variable. */
string getAnMybatisConfigurationVariableKey() {
exists(PropertiesFlowConfig conf, DataFlow::Node n |
propertiesKey(n, result) and
conf.hasFlow(_, n)
)
}
/** The interface `org.apache.ibatis.annotations.Param`. */
class TypeParam extends Interface {
TypeParam() { this.hasQualifiedName("org.apache.ibatis.annotations", "Param") }
}
/** A reference type that extends a parameterization of `java.util.List`. */
class ListType extends RefType {
ListType() {
this.getSourceDeclaration().getASourceSupertype*().hasQualifiedName("java.util", "List")
}
}

View File

@@ -14,6 +14,7 @@
import java
import DataFlow::PathGraph
import MyBatisMapperXmlSqlInjectionLib
import semmle.code.xml.MyBatisMapperXML
import semmle.code.java.security.SanitizerGuard
import semmle.code.java.dataflow.FlowSources
@@ -35,6 +36,22 @@ private class MyBatisMapperXmlSqlInjectionConfiguration extends TaintTracking::C
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof ContainsSanitizer or guard instanceof EqualsSanitizer
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma |
ma.getMethod().getDeclaringType() instanceof MapType and
ma.getMethod().getName() = "get" and
ma.getQualifier() = node1.asExpr() and
ma = node2.asExpr()
)
or
exists(MethodAccess ma |
ma.getMethod().getDeclaringType() instanceof TypeObject and
ma.getMethod().getName() = "toString" and
ma.getQualifier() = node1.asExpr() and
ma = node2.asExpr()
)
}
}
from
@@ -42,7 +59,7 @@ from
XMLElement xmle
where
cfg.hasFlowPath(source, sink) and
isSqlInjection(sink.getNode(), xmle)
isMapperXmlSqlInjection(sink.getNode(), xmle)
select sink.getNode(), source, sink,
"MyBatis Mapper XML sql injection might include code from $@ to $@.", source.getNode(),
"this user input", xmle, "this sql operation"

View File

@@ -1,56 +1,16 @@
import java
import MyBatisCommonLib
import semmle.code.xml.MyBatisMapperXML
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.MyBatis
import semmle.code.java.frameworks.Properties
private predicate propertiesKey(DataFlow::Node prop, string key) {
exists(MethodAccess m |
m.getMethod() instanceof PropertiesSetPropertyMethod and
key = m.getArgument(0).(CompileTimeConstantExpr).getStringValue() and
prop.asExpr() = m.getQualifier()
)
}
private class PropertiesFlowConfig extends DataFlow2::Configuration {
PropertiesFlowConfig() { this = "PropertiesFlowConfig" }
override predicate isSource(DataFlow::Node src) {
exists(MethodAccess ma | ma.getMethod() instanceof IbatisConfigurationGetVariablesMethod |
src.asExpr() = ma
)
}
override predicate isSink(DataFlow::Node sink) { propertiesKey(sink, _) }
}
/** Get the key value of Mybatis Configuration Variable. */
private string getAnMybatisConfigurationVariableKey() {
exists(PropertiesFlowConfig conf, DataFlow::Node n |
propertiesKey(n, result) and
conf.hasFlow(_, n)
)
}
/** The interface `org.apache.ibatis.annotations.Param`. */
private class TypeParam extends Interface {
TypeParam() { this.hasQualifiedName("org.apache.ibatis.annotations", "Param") }
}
/** A reference type that extends a parameterization of `java.util.List`. */
private class ListType extends RefType {
ListType() {
this.getSourceDeclaration().getASourceSupertype*().hasQualifiedName("java.util", "List")
}
}
/** A sink for MyBatis Mapper method call an argument. */
class MyBatisMapperMethodCallAnArgument extends DataFlow::Node {
MyBatisMapperMethodCallAnArgument() {
exists(MyBatisMapperSqlOperation mbmxe, MethodAccess mc |
mbmxe.getMapperMethod() = mc.getMethod()
exists(MyBatisMapperSqlOperation mbmxe, MethodAccess ma |
mbmxe.getMapperMethod() = ma.getMethod()
|
mc.getAnArgument() = this.asExpr()
ma.getAnArgument() = this.asExpr()
)
}
}
@@ -60,23 +20,7 @@ private string getAnMybatiXmlSetValue(XMLElement xmle) {
result = xmle.getTextValue().trim().regexpFind("(#|\\$)(\\{([^\\}]*\\}))", _, _)
}
predicate isSqlInjection(DataFlow::Node node, XMLElement xmle) {
// MyBatis Mapper method parameter name sql injection vulnerabilities.
// e.g. MyBatis Mapper method: `void test(String name);` and MyBatis Mapper XML file:`select id,name from test where name like '%${name}%'`
exists(MyBatisMapperSqlOperation mbmxe, MyBatisMapperSql mbms, MethodAccess mc, int i |
mbmxe.getMapperMethod() = mc.getMethod()
|
(
mbmxe.getAChild*() = xmle
or
mbmxe.getInclude().getRefid() = mbms.getId() and
mbms.getAChild*() = xmle
) and
not mc.getMethod().getParameter(i).hasAnnotation() and
getAnMybatiXmlSetValue(xmle).matches("${" + mc.getMethod().getParameter(i).getName() + "%}") and
mc.getArgument(i) = node.asExpr()
)
or
predicate isMapperXmlSqlInjection(DataFlow::Node node, XMLElement xmle) {
// MyBatis Mapper method Param Annotation sql injection vulnerabilities.
// e.g. MyBatis Mapper method: `void test(@Param("orderby") String name);` and MyBatis Mapper XML file:`select id,name from test order by ${orderby,jdbcType=VARCHAR}`
exists(
@@ -120,10 +64,12 @@ predicate isSqlInjection(DataFlow::Node node, XMLElement xmle) {
// The parameter type of MyBatis Mapper method is Map or List or Array, which may cause SQL injection vulnerability.
// e.g. MyBatis Mapper method: `void test(Map<String, String> params);` and MyBatis Mapper XML file:`select id,name from test where name like '%${name}%'`
exists(
MyBatisMapperSqlOperation mbmxe, MyBatisMapperSql mbms, MethodAccess mc, int i, string res
MyBatisMapperSqlOperation mbmxe, MyBatisMapperForeach mbmf, MyBatisMapperSql mbms,
MethodAccess mc, int i, string res
|
mbmxe.getMapperMethod() = mc.getMethod()
|
mbmf = xmle and
(
mbmxe.getAChild*() = xmle
or
@@ -142,7 +88,7 @@ predicate isSqlInjection(DataFlow::Node node, XMLElement xmle) {
mc.getArgument(i) = node.asExpr()
)
or
// MyBatis Mapper method string type sql injection vulnerabilities.
// SQL injection vulnerability where the MyBatis Mapper method has only one parameter and the parameter is not annotated with `@Param`.
// e.g. MyBatis Mapper method: `void test(String name);` and MyBatis Mapper XML file:`select id,name from test where name like '%${value}%'`
exists(MyBatisMapperSqlOperation mbmxe, MyBatisMapperSql mbms, MethodAccess mc, string res |
mbmxe.getMapperMethod() = mc.getMethod()
@@ -154,11 +100,33 @@ predicate isSqlInjection(DataFlow::Node node, XMLElement xmle) {
mbms.getAChild*() = xmle
) and
res = getAnMybatiXmlSetValue(xmle) and
mc.getMethod().getAParamType() instanceof TypeString and
mc.getMethod().getNumberOfParameters() = 1 and
not mc.getMethod().getAParameter().hasAnnotation() and
res.matches("%${%}") and
not res.matches("${" + getAnMybatisConfigurationVariableKey() + "}") and
mc.getAnArgument() = node.asExpr()
)
or
// MyBatis Mapper method default parameter sql injection vulnerabilities.the default parameter form of the method is arg[0...n] or param[1...n].
// e.g. MyBatis Mapper method: `void test(String name);` and MyBatis Mapper XML file:`select id,name from test where name like '%${arg0 or param1}%'`
exists(
MyBatisMapperSqlOperation mbmxe, MyBatisMapperSql mbms, MethodAccess mc, int i, string res
|
mbmxe.getMapperMethod() = mc.getMethod()
|
(
mbmxe.getAChild*() = xmle
or
mbmxe.getInclude().getRefid() = mbms.getId() and
mbms.getAChild*() = xmle
) and
not mc.getMethod().getParameter(i).hasAnnotation() and
res = getAnMybatiXmlSetValue(xmle) and
(
res.matches("%${param" + (i + 1) + "%}")
or
res.matches("%${arg" + i + "%}")
) and
mc.getArgument(i) = node.asExpr()
)
}

View File

@@ -39,7 +39,6 @@ abstract class MyBatisMapperSqlOperation extends MyBatisMapperXMLElement {
*/
MyBatisMapperInclude getInclude() { result = getAChild*() }
Method getMapperMethod() {
result.getName() = this.getId() and
result.getDeclaringType() = this.getParent().(MyBatisMapperXMLElement).getNamespaceRefType()
@@ -117,3 +116,10 @@ class MyBatisMapperInclude extends MyBatisMapperXMLElement {
*/
string getRefid() { result = getAttribute("refid").getValue() }
}
/**
* A `<foreach>` element in a `MyBatisMapperXMLElement`.
*/
class MyBatisMapperForeach extends MyBatisMapperXMLElement {
MyBatisMapperForeach() { getName() = "foreach" }
}

View File

@@ -0,0 +1,16 @@
edges
| MybatisSqlInjection.java:62:19:62:43 | name : String | MybatisSqlInjection.java:63:35:63:38 | name : String |
| MybatisSqlInjection.java:63:35:63:38 | name : String | MybatisSqlInjectionService.java:48:19:48:29 | name : String |
| MybatisSqlInjectionService.java:48:19:48:29 | name : String | MybatisSqlInjectionService.java:50:23:50:26 | name : String |
| MybatisSqlInjectionService.java:50:3:50:9 | hashMap [post update] [<map.value>] : String | MybatisSqlInjectionService.java:51:27:51:33 | hashMap |
| MybatisSqlInjectionService.java:50:23:50:26 | name : String | MybatisSqlInjectionService.java:50:3:50:9 | hashMap [post update] [<map.value>] : String |
nodes
| MybatisSqlInjection.java:62:19:62:43 | name : String | semmle.label | name : String |
| MybatisSqlInjection.java:63:35:63:38 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:48:19:48:29 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:50:3:50:9 | hashMap [post update] [<map.value>] : String | semmle.label | hashMap [post update] [<map.value>] : String |
| MybatisSqlInjectionService.java:50:23:50:26 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:51:27:51:33 | hashMap | semmle.label | hashMap |
subpaths
#select
| MybatisSqlInjectionService.java:51:27:51:33 | hashMap | MybatisSqlInjection.java:62:19:62:43 | name : String | MybatisSqlInjectionService.java:51:27:51:33 | hashMap | MyBatis annotation sql injection might include code from $@ to $@. | MybatisSqlInjection.java:62:19:62:43 | name | this user input | SqlInjectionMapper.java:29:2:29:54 | Select | this sql operation |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-089/MyBatisAnnotationSqlInjection.ql

View File

@@ -1,31 +1,31 @@
edges
| MybatisSqlInjection.java:19:25:19:49 | name : String | MybatisSqlInjection.java:20:55:20:58 | name : String |
| MybatisSqlInjection.java:20:55:20:58 | name : String | MybatisSqlInjectionService.java:12:25:12:35 | name : String |
| MybatisSqlInjection.java:20:55:20:58 | name : String | MybatisSqlInjectionService.java:13:25:13:35 | name : String |
| MybatisSqlInjection.java:25:25:25:49 | name : String | MybatisSqlInjection.java:26:55:26:58 | name : String |
| MybatisSqlInjection.java:26:55:26:58 | name : String | MybatisSqlInjectionService.java:17:25:17:35 | name : String |
| MybatisSqlInjection.java:26:55:26:58 | name : String | MybatisSqlInjectionService.java:18:25:18:35 | name : String |
| MybatisSqlInjection.java:31:25:31:49 | test : Test | MybatisSqlInjection.java:32:55:32:58 | test : Test |
| MybatisSqlInjection.java:32:55:32:58 | test : Test | MybatisSqlInjectionService.java:22:25:22:33 | test : Test |
| MybatisSqlInjection.java:32:55:32:58 | test : Test | MybatisSqlInjectionService.java:23:25:23:33 | test : Test |
| MybatisSqlInjection.java:37:19:37:40 | test : Test | MybatisSqlInjection.java:38:35:38:38 | test : Test |
| MybatisSqlInjection.java:38:35:38:38 | test : Test | MybatisSqlInjectionService.java:27:19:27:27 | test : Test |
| MybatisSqlInjection.java:38:35:38:38 | test : Test | MybatisSqlInjectionService.java:28:19:28:27 | test : Test |
| MybatisSqlInjection.java:42:19:42:40 | test : Test | MybatisSqlInjection.java:43:35:43:38 | test : Test |
| MybatisSqlInjection.java:43:35:43:38 | test : Test | MybatisSqlInjectionService.java:31:19:31:27 | test : Test |
| MybatisSqlInjection.java:43:35:43:38 | test : Test | MybatisSqlInjectionService.java:32:19:32:27 | test : Test |
| MybatisSqlInjection.java:47:19:47:57 | params : Map | MybatisSqlInjection.java:48:35:48:40 | params : Map |
| MybatisSqlInjection.java:48:35:48:40 | params : Map | MybatisSqlInjectionService.java:35:19:35:44 | params : Map |
| MybatisSqlInjection.java:48:35:48:40 | params : Map | MybatisSqlInjectionService.java:36:19:36:44 | params : Map |
| MybatisSqlInjection.java:52:19:52:50 | params : List | MybatisSqlInjection.java:53:35:53:40 | params : List |
| MybatisSqlInjection.java:53:35:53:40 | params : List | MybatisSqlInjectionService.java:39:19:39:37 | params : List |
| MybatisSqlInjection.java:53:35:53:40 | params : List | MybatisSqlInjectionService.java:40:19:40:37 | params : List |
| MybatisSqlInjection.java:57:19:57:46 | params : String[] | MybatisSqlInjection.java:58:35:58:40 | params : String[] |
| MybatisSqlInjection.java:58:35:58:40 | params : String[] | MybatisSqlInjectionService.java:43:19:43:33 | params : String[] |
| MybatisSqlInjection.java:68:26:68:36 | name : String | MybatisSqlInjection.java:69:56:69:59 | name : String |
| MybatisSqlInjection.java:69:56:69:59 | name : String | MybatisSqlInjectionService.java:52:26:52:36 | name : String |
| MybatisSqlInjectionService.java:12:25:12:35 | name : String | MybatisSqlInjectionService.java:13:47:13:50 | name |
| MybatisSqlInjectionService.java:17:25:17:35 | name : String | MybatisSqlInjectionService.java:18:47:18:50 | name |
| MybatisSqlInjectionService.java:22:25:22:33 | test : Test | MybatisSqlInjectionService.java:23:47:23:50 | test |
| MybatisSqlInjectionService.java:27:19:27:27 | test : Test | MybatisSqlInjectionService.java:28:27:28:30 | test |
| MybatisSqlInjectionService.java:31:19:31:27 | test : Test | MybatisSqlInjectionService.java:32:27:32:30 | test |
| MybatisSqlInjectionService.java:35:19:35:44 | params : Map | MybatisSqlInjectionService.java:36:27:36:32 | params |
| MybatisSqlInjectionService.java:39:19:39:37 | params : List | MybatisSqlInjectionService.java:40:27:40:32 | params |
| MybatisSqlInjectionService.java:43:19:43:33 | params : String[] | MybatisSqlInjectionService.java:44:27:44:32 | params |
| MybatisSqlInjectionService.java:52:26:52:36 | name : String | MybatisSqlInjectionService.java:53:48:53:51 | name |
| MybatisSqlInjection.java:58:35:58:40 | params : String[] | MybatisSqlInjectionService.java:44:19:44:33 | params : String[] |
| MybatisSqlInjection.java:73:26:73:36 | name : String | MybatisSqlInjection.java:74:56:74:59 | name : String |
| MybatisSqlInjection.java:74:56:74:59 | name : String | MybatisSqlInjectionService.java:59:26:59:36 | name : String |
| MybatisSqlInjectionService.java:13:25:13:35 | name : String | MybatisSqlInjectionService.java:14:47:14:50 | name |
| MybatisSqlInjectionService.java:18:25:18:35 | name : String | MybatisSqlInjectionService.java:19:47:19:50 | name |
| MybatisSqlInjectionService.java:23:25:23:33 | test : Test | MybatisSqlInjectionService.java:24:47:24:50 | test |
| MybatisSqlInjectionService.java:28:19:28:27 | test : Test | MybatisSqlInjectionService.java:29:27:29:30 | test |
| MybatisSqlInjectionService.java:32:19:32:27 | test : Test | MybatisSqlInjectionService.java:33:27:33:30 | test |
| MybatisSqlInjectionService.java:36:19:36:44 | params : Map | MybatisSqlInjectionService.java:37:27:37:32 | params |
| MybatisSqlInjectionService.java:40:19:40:37 | params : List | MybatisSqlInjectionService.java:41:27:41:32 | params |
| MybatisSqlInjectionService.java:44:19:44:33 | params : String[] | MybatisSqlInjectionService.java:45:27:45:32 | params |
| MybatisSqlInjectionService.java:59:26:59:36 | name : String | MybatisSqlInjectionService.java:60:48:60:51 | name |
nodes
| MybatisSqlInjection.java:19:25:19:49 | name : String | semmle.label | name : String |
| MybatisSqlInjection.java:20:55:20:58 | name : String | semmle.label | name : String |
@@ -43,33 +43,34 @@ nodes
| MybatisSqlInjection.java:53:35:53:40 | params : List | semmle.label | params : List |
| MybatisSqlInjection.java:57:19:57:46 | params : String[] | semmle.label | params : String[] |
| MybatisSqlInjection.java:58:35:58:40 | params : String[] | semmle.label | params : String[] |
| MybatisSqlInjection.java:68:26:68:36 | name : String | semmle.label | name : String |
| MybatisSqlInjection.java:69:56:69:59 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:12:25:12:35 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:13:47:13:50 | name | semmle.label | name |
| MybatisSqlInjectionService.java:17:25:17:35 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:18:47:18:50 | name | semmle.label | name |
| MybatisSqlInjectionService.java:22:25:22:33 | test : Test | semmle.label | test : Test |
| MybatisSqlInjectionService.java:23:47:23:50 | test | semmle.label | test |
| MybatisSqlInjectionService.java:27:19:27:27 | test : Test | semmle.label | test : Test |
| MybatisSqlInjectionService.java:28:27:28:30 | test | semmle.label | test |
| MybatisSqlInjectionService.java:31:19:31:27 | test : Test | semmle.label | test : Test |
| MybatisSqlInjectionService.java:32:27:32:30 | test | semmle.label | test |
| MybatisSqlInjectionService.java:35:19:35:44 | params : Map | semmle.label | params : Map |
| MybatisSqlInjectionService.java:36:27:36:32 | params | semmle.label | params |
| MybatisSqlInjectionService.java:39:19:39:37 | params : List | semmle.label | params : List |
| MybatisSqlInjectionService.java:40:27:40:32 | params | semmle.label | params |
| MybatisSqlInjectionService.java:43:19:43:33 | params : String[] | semmle.label | params : String[] |
| MybatisSqlInjectionService.java:44:27:44:32 | params | semmle.label | params |
| MybatisSqlInjectionService.java:52:26:52:36 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:53:48:53:51 | name | semmle.label | name |
| MybatisSqlInjection.java:73:26:73:36 | name : String | semmle.label | name : String |
| MybatisSqlInjection.java:74:56:74:59 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:13:25:13:35 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:14:47:14:50 | name | semmle.label | name |
| MybatisSqlInjectionService.java:18:25:18:35 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:19:47:19:50 | name | semmle.label | name |
| MybatisSqlInjectionService.java:23:25:23:33 | test : Test | semmle.label | test : Test |
| MybatisSqlInjectionService.java:24:47:24:50 | test | semmle.label | test |
| MybatisSqlInjectionService.java:28:19:28:27 | test : Test | semmle.label | test : Test |
| MybatisSqlInjectionService.java:29:27:29:30 | test | semmle.label | test |
| MybatisSqlInjectionService.java:32:19:32:27 | test : Test | semmle.label | test : Test |
| MybatisSqlInjectionService.java:33:27:33:30 | test | semmle.label | test |
| MybatisSqlInjectionService.java:36:19:36:44 | params : Map | semmle.label | params : Map |
| MybatisSqlInjectionService.java:37:27:37:32 | params | semmle.label | params |
| MybatisSqlInjectionService.java:40:19:40:37 | params : List | semmle.label | params : List |
| MybatisSqlInjectionService.java:41:27:41:32 | params | semmle.label | params |
| MybatisSqlInjectionService.java:44:19:44:33 | params : String[] | semmle.label | params : String[] |
| MybatisSqlInjectionService.java:45:27:45:32 | params | semmle.label | params |
| MybatisSqlInjectionService.java:59:26:59:36 | name : String | semmle.label | name : String |
| MybatisSqlInjectionService.java:60:48:60:51 | name | semmle.label | name |
subpaths
#select
| MybatisSqlInjectionService.java:13:47:13:50 | name | MybatisSqlInjection.java:19:25:19:49 | name : String | MybatisSqlInjectionService.java:13:47:13:50 | name | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:19:25:19:49 | name | this user input | SqlInjectionMapper.xml:23:3:25:12 | select | this sql operation |
| MybatisSqlInjectionService.java:18:47:18:50 | name | MybatisSqlInjection.java:25:25:25:49 | name : String | MybatisSqlInjectionService.java:18:47:18:50 | name | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:25:25:25:49 | name | this user input | SqlInjectionMapper.xml:27:3:29:12 | select | this sql operation |
| MybatisSqlInjectionService.java:23:47:23:50 | test | MybatisSqlInjection.java:31:25:31:49 | test : Test | MybatisSqlInjectionService.java:23:47:23:50 | test | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:31:25:31:49 | test | this user input | SqlInjectionMapper.xml:31:3:33:12 | select | this sql operation |
| MybatisSqlInjectionService.java:28:27:28:30 | test | MybatisSqlInjection.java:37:19:37:40 | test : Test | MybatisSqlInjectionService.java:28:27:28:30 | test | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:37:19:37:40 | test | this user input | SqlInjectionMapper.xml:14:7:16:12 | if | this sql operation |
| MybatisSqlInjectionService.java:32:27:32:30 | test | MybatisSqlInjection.java:42:19:42:40 | test : Test | MybatisSqlInjectionService.java:32:27:32:30 | test | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:42:19:42:40 | test | this user input | SqlInjectionMapper.xml:50:7:52:12 | if | this sql operation |
| MybatisSqlInjectionService.java:32:27:32:30 | test | MybatisSqlInjection.java:42:19:42:40 | test : Test | MybatisSqlInjectionService.java:32:27:32:30 | test | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:42:19:42:40 | test | this user input | SqlInjectionMapper.xml:53:7:55:12 | if | this sql operation |
| MybatisSqlInjectionService.java:36:27:36:32 | params | MybatisSqlInjection.java:47:19:47:57 | params : Map | MybatisSqlInjectionService.java:36:27:36:32 | params | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:47:19:47:57 | params | this user input | SqlInjectionMapper.xml:59:3:61:12 | select | this sql operation |
| MybatisSqlInjectionService.java:40:27:40:32 | params | MybatisSqlInjection.java:52:19:52:50 | params : List | MybatisSqlInjectionService.java:40:27:40:32 | params | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:52:19:52:50 | params | this user input | SqlInjectionMapper.xml:65:5:67:15 | foreach | this sql operation |
| MybatisSqlInjectionService.java:44:27:44:32 | params | MybatisSqlInjection.java:57:19:57:46 | params : String[] | MybatisSqlInjectionService.java:44:27:44:32 | params | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:57:19:57:46 | params | this user input | SqlInjectionMapper.xml:72:5:74:15 | foreach | this sql operation |
| MybatisSqlInjectionService.java:14:47:14:50 | name | MybatisSqlInjection.java:19:25:19:49 | name : String | MybatisSqlInjectionService.java:14:47:14:50 | name | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:19:25:19:49 | name | this user input | SqlInjectionMapper.xml:23:3:25:12 | select | this sql operation |
| MybatisSqlInjectionService.java:19:47:19:50 | name | MybatisSqlInjection.java:25:25:25:49 | name : String | MybatisSqlInjectionService.java:19:47:19:50 | name | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:25:25:25:49 | name | this user input | SqlInjectionMapper.xml:27:3:29:12 | select | this sql operation |
| MybatisSqlInjectionService.java:24:47:24:50 | test | MybatisSqlInjection.java:31:25:31:49 | test : Test | MybatisSqlInjectionService.java:24:47:24:50 | test | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:31:25:31:49 | test | this user input | SqlInjectionMapper.xml:31:3:33:12 | select | this sql operation |
| MybatisSqlInjectionService.java:29:27:29:30 | test | MybatisSqlInjection.java:37:19:37:40 | test : Test | MybatisSqlInjectionService.java:29:27:29:30 | test | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:37:19:37:40 | test | this user input | SqlInjectionMapper.xml:14:7:16:12 | if | this sql operation |
| MybatisSqlInjectionService.java:33:27:33:30 | test | MybatisSqlInjection.java:42:19:42:40 | test : Test | MybatisSqlInjectionService.java:33:27:33:30 | test | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:42:19:42:40 | test | this user input | SqlInjectionMapper.xml:50:7:52:12 | if | this sql operation |
| MybatisSqlInjectionService.java:33:27:33:30 | test | MybatisSqlInjection.java:42:19:42:40 | test : Test | MybatisSqlInjectionService.java:33:27:33:30 | test | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:42:19:42:40 | test | this user input | SqlInjectionMapper.xml:53:7:55:12 | if | this sql operation |
| MybatisSqlInjectionService.java:37:27:37:32 | params | MybatisSqlInjection.java:47:19:47:57 | params : Map | MybatisSqlInjectionService.java:37:27:37:32 | params | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:47:19:47:57 | params | this user input | SqlInjectionMapper.xml:59:3:61:12 | select | this sql operation |
| MybatisSqlInjectionService.java:41:27:41:32 | params | MybatisSqlInjection.java:52:19:52:50 | params : List | MybatisSqlInjectionService.java:41:27:41:32 | params | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:52:19:52:50 | params | this user input | SqlInjectionMapper.xml:65:5:67:15 | foreach | this sql operation |
| MybatisSqlInjectionService.java:45:27:45:32 | params | MybatisSqlInjection.java:57:19:57:46 | params : String[] | MybatisSqlInjectionService.java:45:27:45:32 | params | MyBatis Mapper XML sql injection might include code from $@ to $@. | MybatisSqlInjection.java:57:19:57:46 | params | this user input | SqlInjectionMapper.xml:72:5:74:15 | foreach | this sql operation |

View File

@@ -58,6 +58,11 @@ public class MybatisSqlInjection {
mybatisSqlInjectionService.bad8(params);
}
@GetMapping(value = "msi9")
public void bad9(@RequestParam String name) {
mybatisSqlInjectionService.bad9(name);
}
@GetMapping(value = "good1")
public List<Test> good1(Integer id) {
List<Test> result = mybatisSqlInjectionService.good1(id);

View File

@@ -1,5 +1,6 @@
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -44,6 +45,12 @@ public class MybatisSqlInjectionService {
sqlInjectionMapper.bad8(params);
}
public void bad9(String name) {
HashMap hashMap = new HashMap();
hashMap.put("name", name);
sqlInjectionMapper.bad9(hashMap);
}
public List<Test> good1(Integer id) {
List<Test> result = sqlInjectionMapper.good1(id);
return result;

View File

@@ -1,8 +1,10 @@
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import org.apache.ibatis.annotations.Select;
@Mapper
@Repository
@@ -24,6 +26,9 @@ public interface SqlInjectionMapper {
void bad8(String[] params);
@Select({"select * from test", "where id = ${name}"})
public Test bad9(HashMap<String, Object> map);
List<Test> good1(Integer id);
List<Test> good2(String name);

View File

@@ -0,0 +1,14 @@
package org.apache.ibatis.annotations;
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;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Select {
String[] value();
}