mirror of
https://github.com/github/codeql.git
synced 2025-12-21 03:06:31 +01:00
Modify according to suggestions
This commit is contained in:
@@ -4,23 +4,21 @@
|
||||
"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>
|
||||
<p>MyBatis allows operating the database by annotating a method with the annotations <code>@Select</code>, <code>@Insert</code>, etc. to construct dynamic SQL statements.
|
||||
If the syntax `${param}` is used in those statements, and `param` is a parameter of the annotated method, attackers can exploit this to tamper with the SQL 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.
|
||||
When writing MyBatis mapping statements, try to use the syntax <code>#{xxx}</code>. If the syntax <code>${xxx}</code> must be used, any parameters included in it should be sanitized 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.
|
||||
The following sample shows a bad and a good example of MyBatis annotations usage. The <code>bad1</code> method uses <code>$(name)</code>
|
||||
in the <code>@Select</code> annotation to dynamically build a SQL statement, which causes a SQL injection vulnerability.
|
||||
The <code>good1</code> method uses <code>#{name}</code> in the <code>@Select</code> annotation to to dynamically include the parameter in a SQL statement, which allows the MyBatis framework to handle the sanitization, preventing the vulnerability.
|
||||
</p>
|
||||
<sample src="MyBatisAnnotationSqlInjection.java" />
|
||||
</example>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* @name MyBatis annotation sql injection
|
||||
* @name SQL injection in MyBatis annotation
|
||||
* @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
|
||||
* @id java/mybatis-annotation-sql-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-089
|
||||
*/
|
||||
@@ -14,7 +14,6 @@
|
||||
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 {
|
||||
@@ -32,10 +31,6 @@ private class MyBatisAnnotationSqlInjectionConfiguration extends TaintTracking::
|
||||
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
|
||||
@@ -60,5 +55,5 @@ 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"
|
||||
"MyBatis annotation SQL injection might include code from $@ to $@.", source.getNode(),
|
||||
"this user input", isoa, "this SQL operation"
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes for SQL injection detection in MyBatis annotation.
|
||||
*/
|
||||
|
||||
import java
|
||||
import MyBatisCommonLib
|
||||
import semmle.code.xml.MyBatisMapperXML
|
||||
@@ -7,7 +11,7 @@ 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 |
|
||||
exists(MyBatisSqlOperationAnnotationMethod msoam, MethodAccess ma | ma.getMethod() = msoam |
|
||||
ma.getAnArgument() = this.asExpr()
|
||||
)
|
||||
}
|
||||
@@ -15,7 +19,7 @@ class MyBatisAnnotationMethodCallAnArgument extends DataFlow::Node {
|
||||
|
||||
/** Get the #{...} or ${...} parameters in the Mybatis annotation value. */
|
||||
private string getAnMybatiAnnotationSetValue(IbatisSqlOperationAnnotation isoa) {
|
||||
result = isoa.getSqlValue().trim().regexpFind("(#|\\$)(\\{([^\\}]*\\}))", _, _)
|
||||
result = isoa.getSqlValue().trim().regexpFind("(#|\\$)\\{[^\\}]*\\}", _, _)
|
||||
}
|
||||
|
||||
predicate isMybatisAnnotationSqlInjection(DataFlow::Node node, IbatisSqlOperationAnnotation isoa) {
|
||||
@@ -27,15 +31,15 @@ predicate isMybatisAnnotationSqlInjection(DataFlow::Node node, IbatisSqlOperatio
|
||||
// @Select(select id,name from test where name like '%${value}%')
|
||||
// Test test(String name);
|
||||
// ```
|
||||
exists(MybatisSqlOperationAnnotationMethod msoam, MethodAccess ma, string res |
|
||||
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
|
||||
not ma.getMethod().getAParameter().getAnAnnotation().getType() instanceof TypeParam and
|
||||
res.matches("%${%}") and
|
||||
not res.matches("${" + getAnMybatisConfigurationVariableKey() + "}") and
|
||||
not res = "${" + getAnMybatisConfigurationVariableKey() + "}" and
|
||||
ma.getAnArgument() = node.asExpr()
|
||||
)
|
||||
or
|
||||
@@ -47,11 +51,11 @@ predicate isMybatisAnnotationSqlInjection(DataFlow::Node node, IbatisSqlOperatio
|
||||
// @Select(select id,name from test where name like '%${value}%')
|
||||
// Test test(Map map);
|
||||
// ```
|
||||
exists(MybatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, string res |
|
||||
exists(MyBatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, string res |
|
||||
msoam = ma.getMethod()
|
||||
|
|
||||
msoam.getAnAnnotation() = isoa and
|
||||
not ma.getMethod().getParameter(i).hasAnnotation() and
|
||||
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
|
||||
(
|
||||
ma.getMethod().getParameterType(i) instanceof MapType or
|
||||
ma.getMethod().getParameterType(i) instanceof ListType or
|
||||
@@ -59,7 +63,7 @@ predicate isMybatisAnnotationSqlInjection(DataFlow::Node node, IbatisSqlOperatio
|
||||
) and
|
||||
res = getAnMybatiAnnotationSetValue(isoa) and
|
||||
res.matches("%${%}") and
|
||||
not res.matches("${" + getAnMybatisConfigurationVariableKey() + "}") and
|
||||
not res = "${" + getAnMybatisConfigurationVariableKey() + "}" and
|
||||
ma.getArgument(i) = node.asExpr()
|
||||
)
|
||||
or
|
||||
@@ -71,13 +75,13 @@ predicate isMybatisAnnotationSqlInjection(DataFlow::Node node, IbatisSqlOperatio
|
||||
// @Select(select id,name from test order by ${name,jdbcType=VARCHAR})
|
||||
// void test(Test test);
|
||||
// ```
|
||||
exists(MybatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, Class c |
|
||||
exists(MyBatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, RefType t |
|
||||
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
|
||||
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
|
||||
ma.getMethod().getParameterType(i).getName() = t.getName() and
|
||||
getAnMybatiAnnotationSetValue(isoa).matches("%${" + t.getAField().getName() + "%}") and
|
||||
ma.getArgument(i) = node.asExpr()
|
||||
)
|
||||
or
|
||||
@@ -89,12 +93,10 @@ predicate isMybatisAnnotationSqlInjection(DataFlow::Node node, IbatisSqlOperatio
|
||||
// @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()
|
||||
exists(MyBatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, Annotation annotation |
|
||||
msoam = ma.getMethod() and ma.getMethod().getParameter(i).getAnAnnotation() = annotation
|
||||
|
|
||||
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() +
|
||||
@@ -109,18 +111,18 @@ predicate isMybatisAnnotationSqlInjection(DataFlow::Node node, IbatisSqlOperatio
|
||||
// @Select(select id,name from test order by ${arg0,jdbcType=VARCHAR})
|
||||
// void test(String name);
|
||||
// ```
|
||||
exists(MybatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, string res |
|
||||
exists(MyBatisSqlOperationAnnotationMethod msoam, MethodAccess ma, int i, string res |
|
||||
msoam = ma.getMethod()
|
||||
|
|
||||
msoam.getAnAnnotation() = isoa and
|
||||
not ma.getMethod().getParameter(i).hasAnnotation() and
|
||||
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
|
||||
res = getAnMybatiAnnotationSetValue(isoa) and
|
||||
(
|
||||
res.matches("%${param" + (i + 1) + "%}")
|
||||
or
|
||||
res.matches("%${arg" + i + "%}")
|
||||
) and
|
||||
not res.matches("${" + getAnMybatisConfigurationVariableKey() + "}") and
|
||||
not res = "${" + getAnMybatisConfigurationVariableKey() + "}" and
|
||||
ma.getArgument(i) = node.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides public classes for MyBatis SQL injection detection.
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.frameworks.MyBatis
|
||||
@@ -28,15 +32,10 @@ private class PropertiesFlowConfig extends DataFlow2::Configuration {
|
||||
string getAnMybatisConfigurationVariableKey() {
|
||||
exists(PropertiesFlowConfig conf, DataFlow::Node n |
|
||||
propertiesKey(n, result) and
|
||||
conf.hasFlow(_, n)
|
||||
conf.hasFlowTo(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() {
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
|
||||
<<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.
|
||||
When writing MyBatis mapping statements, try to use the syntax <code>#{xxx}</code>. If the syntax <code>${xxx}</code> must be used, any parameters included in it should be sanitized to prevent SQL injection attacks.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
@@ -18,7 +17,7 @@ such as "${xxx}", you must manually filter to prevent SQL injection attacks.
|
||||
<p>
|
||||
The following examples show the bad situation and the good situation respectively. In <code>bad1</code>
|
||||
and <code>bad2</code> and <code>bad3</code> and <code>bad4</code> and <code >bad5</code>, the program
|
||||
${ xxx} are dynamic SQL statements, these five examples of SQL injection vulnerabilities. In <code>good1</code>,
|
||||
${xxx} are dynamic SQL statements, these five examples of SQL injection vulnerabilities. In <code>good1</code>,
|
||||
the program uses the ${xxx} dynamic feature SQL statement, but there are subtle restrictions on the data,
|
||||
and there is no SQL injection vulnerability.
|
||||
</p>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* @name MyBatis Mapper xml sql injection
|
||||
* @name SQL injection in MyBatis Mapper XML
|
||||
* @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
|
||||
* @id java/mybatis-xml-sql-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-089
|
||||
*/
|
||||
@@ -15,7 +15,6 @@ import java
|
||||
import DataFlow::PathGraph
|
||||
import MyBatisMapperXmlSqlInjectionLib
|
||||
import semmle.code.xml.MyBatisMapperXML
|
||||
import semmle.code.java.security.SanitizerGuard
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
private class MyBatisMapperXmlSqlInjectionConfiguration extends TaintTracking::Configuration {
|
||||
@@ -33,10 +32,6 @@ private class MyBatisMapperXmlSqlInjectionConfiguration extends TaintTracking::C
|
||||
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
|
||||
@@ -61,5 +56,5 @@ where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
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"
|
||||
"MyBatis Mapper XML SQL injection might include code from $@ to $@.", source.getNode(),
|
||||
"this user input", xmle, "this SQL operation"
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provide classes for SQL injection detection in MyBatis Mapper XML.
|
||||
*/
|
||||
|
||||
import java
|
||||
import MyBatisCommonLib
|
||||
import semmle.code.xml.MyBatisMapperXML
|
||||
@@ -17,116 +21,120 @@ class MyBatisMapperMethodCallAnArgument extends DataFlow::Node {
|
||||
|
||||
/** Get the #{...} or ${...} parameters in the Mybatis mapper xml file */
|
||||
private string getAnMybatiXmlSetValue(XMLElement xmle) {
|
||||
result = xmle.getTextValue().trim().regexpFind("(#|\\$)(\\{([^\\}]*\\}))", _, _)
|
||||
result = xmle.getTextValue().trim().regexpFind("(#|\\$)\\{[^\\}]*\\}", _, _)
|
||||
}
|
||||
|
||||
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(
|
||||
MyBatisMapperSqlOperation mbmxe, MyBatisMapperSql mbms, MethodAccess mc, int i,
|
||||
Annotation annotation
|
||||
|
|
||||
mbmxe.getMapperMethod() = mc.getMethod()
|
||||
exists(MyBatisMapperSqlOperation mbmxe, MethodAccess ma, int i, Annotation annotation |
|
||||
mbmxe.getMapperMethod() = ma.getMethod()
|
||||
|
|
||||
(
|
||||
mbmxe.getAChild*() = xmle
|
||||
or
|
||||
mbmxe.getInclude().getRefid() = mbms.getId() and
|
||||
mbms.getAChild*() = xmle
|
||||
exists(MyBatisMapperSql mbms |
|
||||
mbmxe.getInclude().getRefid() = mbms.getId() and
|
||||
mbms.getAChild*() = xmle
|
||||
)
|
||||
) and
|
||||
mc.getMethod().getParameter(i).hasAnnotation() and
|
||||
mc.getMethod().getParameter(i).getAnAnnotation() = annotation and
|
||||
ma.getMethod().getParameter(i).getAnAnnotation() = annotation and
|
||||
annotation.getType() instanceof TypeParam and
|
||||
getAnMybatiXmlSetValue(xmle)
|
||||
.matches("%${" + annotation.getValue("value").(CompileTimeConstantExpr).getStringValue() +
|
||||
"%}") and
|
||||
mc.getArgument(i) = node.asExpr()
|
||||
ma.getArgument(i) = node.asExpr()
|
||||
)
|
||||
or
|
||||
// MyBatis Mapper method Class Field sql injection vulnerabilities.
|
||||
// e.g. MyBatis Mapper method: `void test(Test test);` and MyBatis Mapper XML file:`select id,name from test order by ${name,jdbcType=VARCHAR}`
|
||||
exists(MyBatisMapperSqlOperation mbmxe, MyBatisMapperSql mbms, MethodAccess mc, int i, Class c |
|
||||
mbmxe.getMapperMethod() = mc.getMethod()
|
||||
exists(MyBatisMapperSqlOperation mbmxe, MethodAccess ma, int i, RefType t |
|
||||
mbmxe.getMapperMethod() = ma.getMethod()
|
||||
|
|
||||
(
|
||||
mbmxe.getAChild*() = xmle
|
||||
or
|
||||
mbmxe.getInclude().getRefid() = mbms.getId() and
|
||||
mbms.getAChild*() = xmle
|
||||
exists(MyBatisMapperSql mbms |
|
||||
mbmxe.getInclude().getRefid() = mbms.getId() and
|
||||
mbms.getAChild*() = xmle
|
||||
)
|
||||
) and
|
||||
not mc.getMethod().getParameter(i).hasAnnotation() and
|
||||
mc.getMethod().getParameterType(i).getName() = c.getName() and
|
||||
getAnMybatiXmlSetValue(xmle).matches("%${" + c.getAField().getName() + "%}") and
|
||||
mc.getArgument(i) = node.asExpr()
|
||||
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
|
||||
ma.getMethod().getParameterType(i).getName() = t.getName() and
|
||||
getAnMybatiXmlSetValue(xmle).matches("%${" + t.getAField().getName() + "%}") and
|
||||
ma.getArgument(i) = node.asExpr()
|
||||
)
|
||||
or
|
||||
// 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, MyBatisMapperForeach mbmf, MyBatisMapperSql mbms,
|
||||
MethodAccess mc, int i, string res
|
||||
MyBatisMapperSqlOperation mbmxe, MyBatisMapperForeach mbmf, MethodAccess ma, int i, string res
|
||||
|
|
||||
mbmxe.getMapperMethod() = mc.getMethod()
|
||||
mbmxe.getMapperMethod() = ma.getMethod()
|
||||
|
|
||||
mbmf = xmle and
|
||||
(
|
||||
mbmxe.getAChild*() = xmle
|
||||
or
|
||||
mbmxe.getInclude().getRefid() = mbms.getId() and
|
||||
mbms.getAChild*() = xmle
|
||||
exists(MyBatisMapperSql mbms |
|
||||
mbmxe.getInclude().getRefid() = mbms.getId() and
|
||||
mbms.getAChild*() = xmle
|
||||
)
|
||||
) and
|
||||
not mc.getMethod().getParameter(i).hasAnnotation() and
|
||||
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
|
||||
(
|
||||
mc.getMethod().getParameterType(i) instanceof MapType or
|
||||
mc.getMethod().getParameterType(i) instanceof ListType or
|
||||
mc.getMethod().getParameterType(i) instanceof Array
|
||||
ma.getMethod().getParameterType(i) instanceof MapType or
|
||||
ma.getMethod().getParameterType(i) instanceof ListType or
|
||||
ma.getMethod().getParameterType(i) instanceof Array
|
||||
) and
|
||||
res = getAnMybatiXmlSetValue(xmle) and
|
||||
res.matches("%${%}") and
|
||||
not res.matches("${" + getAnMybatisConfigurationVariableKey() + "}") and
|
||||
mc.getArgument(i) = node.asExpr()
|
||||
not res = "${" + getAnMybatisConfigurationVariableKey() + "}" and
|
||||
ma.getArgument(i) = node.asExpr()
|
||||
)
|
||||
or
|
||||
// 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()
|
||||
exists(MyBatisMapperSqlOperation mbmxe, MethodAccess ma, string res |
|
||||
mbmxe.getMapperMethod() = ma.getMethod()
|
||||
|
|
||||
(
|
||||
mbmxe.getAChild*() = xmle
|
||||
or
|
||||
mbmxe.getInclude().getRefid() = mbms.getId() and
|
||||
mbms.getAChild*() = xmle
|
||||
exists(MyBatisMapperSql mbms |
|
||||
mbmxe.getInclude().getRefid() = mbms.getId() and
|
||||
mbms.getAChild*() = xmle
|
||||
)
|
||||
) and
|
||||
res = getAnMybatiXmlSetValue(xmle) and
|
||||
mc.getMethod().getNumberOfParameters() = 1 and
|
||||
not mc.getMethod().getAParameter().hasAnnotation() and
|
||||
ma.getMethod().getNumberOfParameters() = 1 and
|
||||
not ma.getMethod().getAParameter().getAnAnnotation().getType() instanceof TypeParam and
|
||||
res.matches("%${%}") and
|
||||
not res.matches("${" + getAnMybatisConfigurationVariableKey() + "}") and
|
||||
mc.getAnArgument() = node.asExpr()
|
||||
not res = "${" + getAnMybatisConfigurationVariableKey() + "}" and
|
||||
ma.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()
|
||||
exists(MyBatisMapperSqlOperation mbmxe, MethodAccess ma, int i, string res |
|
||||
mbmxe.getMapperMethod() = ma.getMethod()
|
||||
|
|
||||
(
|
||||
mbmxe.getAChild*() = xmle
|
||||
or
|
||||
mbmxe.getInclude().getRefid() = mbms.getId() and
|
||||
mbms.getAChild*() = xmle
|
||||
exists(MyBatisMapperSql mbms |
|
||||
mbmxe.getInclude().getRefid() = mbms.getId() and
|
||||
mbms.getAChild*() = xmle
|
||||
)
|
||||
) and
|
||||
not mc.getMethod().getParameter(i).hasAnnotation() and
|
||||
not ma.getMethod().getParameter(i).getAnAnnotation().getType() instanceof TypeParam and
|
||||
res = getAnMybatiXmlSetValue(xmle) and
|
||||
(
|
||||
res.matches("%${param" + (i + 1) + "%}")
|
||||
or
|
||||
res.matches("%${arg" + i + "%}")
|
||||
) and
|
||||
mc.getArgument(i) = node.asExpr()
|
||||
not res = "${" + getAnMybatisConfigurationVariableKey() + "}" and
|
||||
ma.getArgument(i) = node.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Provide universal sanitizer guards.
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* An contains method sanitizer guard.
|
||||
*
|
||||
* e.g. `if(test.contains("test")) {...`
|
||||
*/
|
||||
class ContainsSanitizer extends DataFlow::BarrierGuard {
|
||||
ContainsSanitizer() { this.(MethodAccess).getMethod().hasName("contains") }
|
||||
|
||||
override predicate checks(Expr e, boolean branch) {
|
||||
e = this.(MethodAccess).getArgument(0) and branch = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An equals method sanitizer guard.
|
||||
*
|
||||
* e.g. `if("test".equals(test)) {...`
|
||||
*/
|
||||
class EqualsSanitizer extends DataFlow::BarrierGuard {
|
||||
EqualsSanitizer() { this.(MethodAccess).getMethod().hasName("equals") }
|
||||
|
||||
override predicate checks(Expr e, boolean branch) {
|
||||
e = [this.(MethodAccess).getArgument(0), this.(MethodAccess).getQualifier()] and
|
||||
branch = true
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Provides classes for working with MyBatis mapper xml files and their content.
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
@@ -20,12 +24,14 @@ class MyBatisMapperXMLElement extends XMLElement {
|
||||
/**
|
||||
* Gets the value for this element, with leading and trailing whitespace trimmed.
|
||||
*/
|
||||
string getValue() { result = allCharactersString().trim() }
|
||||
string getValue() { result = this.allCharactersString().trim() }
|
||||
|
||||
/**
|
||||
* Gets the reference type bound to MyBatis Mapper XML File.
|
||||
*/
|
||||
RefType getNamespaceRefType() { result.getQualifiedName() = getAttribute("namespace").getValue() }
|
||||
RefType getNamespaceRefType() {
|
||||
result.getQualifiedName() = this.getAttribute("namespace").getValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,8 +43,11 @@ abstract class MyBatisMapperSqlOperation extends MyBatisMapperXMLElement {
|
||||
/**
|
||||
* Gets the `<include>` element in a `MyBatisMapperSqlOperation`.
|
||||
*/
|
||||
MyBatisMapperInclude getInclude() { result = getAChild*() }
|
||||
MyBatisMapperInclude getInclude() { result = this.getAChild*() }
|
||||
|
||||
/**
|
||||
* Gets the method bound to MyBatis Mapper XML File.
|
||||
*/
|
||||
Method getMapperMethod() {
|
||||
result.getName() = this.getId() and
|
||||
result.getDeclaringType() = this.getParent().(MyBatisMapperXMLElement).getNamespaceRefType()
|
||||
@@ -49,72 +58,72 @@ abstract class MyBatisMapperSqlOperation extends MyBatisMapperXMLElement {
|
||||
* A `<insert>` element in a `MyBatisMapperSqlOperation`.
|
||||
*/
|
||||
class MyBatisMapperInsert extends MyBatisMapperSqlOperation {
|
||||
MyBatisMapperInsert() { getName() = "insert" }
|
||||
MyBatisMapperInsert() { this.getName() = "insert" }
|
||||
|
||||
/**
|
||||
* Gets the value of the `id` attribute of this `<insert>`.
|
||||
*/
|
||||
override string getId() { result = getAttribute("id").getValue() }
|
||||
override string getId() { result = this.getAttribute("id").getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `<update>` element in a `MyBatisMapperSqlOperation`.
|
||||
*/
|
||||
class MyBatisMapperUpdate extends MyBatisMapperSqlOperation {
|
||||
MyBatisMapperUpdate() { getName() = "update" }
|
||||
MyBatisMapperUpdate() { this.getName() = "update" }
|
||||
|
||||
/**
|
||||
* Gets the value of the `id` attribute of this `<update>`.
|
||||
*/
|
||||
override string getId() { result = getAttribute("id").getValue() }
|
||||
override string getId() { result = this.getAttribute("id").getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `<delete>` element in a `MyBatisMapperSqlOperation`.
|
||||
*/
|
||||
class MyBatisMapperDelete extends MyBatisMapperSqlOperation {
|
||||
MyBatisMapperDelete() { getName() = "delete" }
|
||||
MyBatisMapperDelete() { this.getName() = "delete" }
|
||||
|
||||
/**
|
||||
* Gets the value of the `id` attribute of this `<delete>`.
|
||||
*/
|
||||
override string getId() { result = getAttribute("id").getValue() }
|
||||
override string getId() { result = this.getAttribute("id").getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `<select>` element in a `MyBatisMapperSqlOperation`.
|
||||
*/
|
||||
class MyBatisMapperSelect extends MyBatisMapperSqlOperation {
|
||||
MyBatisMapperSelect() { getName() = "select" }
|
||||
MyBatisMapperSelect() { this.getName() = "select" }
|
||||
|
||||
/**
|
||||
* Gets the value of the `id` attribute of this `<select>`.
|
||||
*/
|
||||
override string getId() { result = getAttribute("id").getValue() }
|
||||
override string getId() { result = this.getAttribute("id").getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `<select>` element in a `MyBatisMapperXMLElement`.
|
||||
*/
|
||||
class MyBatisMapperSql extends MyBatisMapperXMLElement {
|
||||
MyBatisMapperSql() { getName() = "sql" }
|
||||
MyBatisMapperSql() { this.getName() = "sql" }
|
||||
|
||||
/**
|
||||
* Gets the value of the `id` attribute of this `<sql>`.
|
||||
*/
|
||||
string getId() { result = getAttribute("id").getValue() }
|
||||
string getId() { result = this.getAttribute("id").getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `<include>` element in a `MyBatisMapperXMLElement`.
|
||||
*/
|
||||
class MyBatisMapperInclude extends MyBatisMapperXMLElement {
|
||||
MyBatisMapperInclude() { getName() = "include" }
|
||||
MyBatisMapperInclude() { this.getName() = "include" }
|
||||
|
||||
/**
|
||||
* Gets the value of the `refid` attribute of this `<include>`.
|
||||
*/
|
||||
string getRefid() { result = getAttribute("refid").getValue() }
|
||||
string getRefid() { result = this.getAttribute("refid").getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user