mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
237 lines
8.3 KiB
Java
237 lines
8.3 KiB
Java
|
|
|
|
|
|
// Test cases for CWE-089 (SQL injection and Java Persistence query injection)
|
|
// http://cwe.mitre.org/data/definitions/89.html
|
|
package test.cwe089.semmle.tests;
|
|
|
|
import java.io.IOException;
|
|
import java.sql.Connection;
|
|
import java.sql.PreparedStatement;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.sql.Statement;
|
|
|
|
|
|
|
|
|
|
|
|
enum Category {
|
|
FloorWax, Topping, Biscuits
|
|
}
|
|
|
|
abstract class Test {
|
|
public static Connection connection;
|
|
public static int categoryId;
|
|
public static String categoryName;
|
|
public static String tableName;
|
|
|
|
private static void tainted(String[] args) throws IOException, SQLException {
|
|
// BAD: the category might have SQL special characters in it
|
|
{
|
|
String category = args[1];
|
|
Statement statement = connection.createStatement();
|
|
String query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
|
+ category + "' ORDER BY PRICE";
|
|
ResultSet results = statement.executeQuery(query1);
|
|
}
|
|
// BAD: don't use user input when building a prepared call
|
|
{
|
|
String id = args[1];
|
|
String query2 = "{ call get_product_by_id('" + id + "',?,?,?) }";
|
|
PreparedStatement statement = connection.prepareCall(query2);
|
|
ResultSet results = statement.executeQuery();
|
|
}
|
|
// BAD: don't use user input when building a prepared query
|
|
{
|
|
String category = args[1];
|
|
String query3 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
|
+ category + "' ORDER BY PRICE";
|
|
PreparedStatement statement = connection.prepareStatement(query3);
|
|
ResultSet results = statement.executeQuery();
|
|
}
|
|
// BAD: an injection using a StringBuilder instead of string append
|
|
{
|
|
String category = args[1];
|
|
StringBuilder querySb = new StringBuilder();
|
|
querySb.append("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='");
|
|
querySb.append(category);
|
|
querySb.append("' ORDER BY PRICE");
|
|
String querySbToString = querySb.toString();
|
|
Statement statement = connection.createStatement();
|
|
ResultSet results = statement.executeQuery(querySbToString);
|
|
}
|
|
// BAD: executeUpdate
|
|
{
|
|
String item = args[1];
|
|
String price = args[2];
|
|
Statement statement = connection.createStatement();
|
|
String query = "UPDATE PRODUCT SET PRICE='" + price + "' WHERE ITEM='" + item + "'";
|
|
int count = statement.executeUpdate(query);
|
|
}
|
|
// BAD: executeUpdate
|
|
{
|
|
String item = args[1];
|
|
String price = args[2];
|
|
Statement statement = connection.createStatement();
|
|
String query = "UPDATE PRODUCT SET PRICE='" + price + "' WHERE ITEM='" + item + "'";
|
|
long count = statement.executeLargeUpdate(query);
|
|
}
|
|
|
|
// OK: validate the input first
|
|
{
|
|
String category = args[1];
|
|
Validation.checkIdentifier(category);
|
|
Statement statement = connection.createStatement();
|
|
String query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
|
+ category + "' ORDER BY PRICE";
|
|
ResultSet results = statement.executeQuery(query1);
|
|
}
|
|
}
|
|
|
|
private static void unescaped() throws IOException, SQLException {
|
|
// BAD: the category might have SQL special characters in it
|
|
{
|
|
Statement statement = connection.createStatement();
|
|
String queryFromField = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
|
+ categoryName + "' ORDER BY PRICE";
|
|
ResultSet results = statement.executeQuery(queryFromField);
|
|
}
|
|
// BAD: unescaped code using a StringBuilder
|
|
{
|
|
StringBuilder querySb = new StringBuilder();
|
|
querySb.append("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='");
|
|
querySb.append(categoryName);
|
|
querySb.append("' ORDER BY PRICE");
|
|
String querySbToString = querySb.toString();
|
|
Statement statement = connection.createStatement();
|
|
ResultSet results = statement.executeQuery(querySbToString);
|
|
}
|
|
// BAD: a StringBuilder with appends of + operations
|
|
{
|
|
StringBuilder querySb2 = new StringBuilder();
|
|
querySb2.append("SELECT ITEM,PRICE FROM PRODUCT ");
|
|
querySb2.append("WHERE ITEM_CATEGORY='" + categoryName + "' ");
|
|
querySb2.append("ORDER BY PRICE");
|
|
String querySb2ToString = querySb2.toString();
|
|
Statement statement = connection.createStatement();
|
|
ResultSet results = statement.executeQuery(querySb2ToString);
|
|
}
|
|
}
|
|
|
|
private static void good(String[] args) throws IOException, SQLException {
|
|
// GOOD: use a prepared query
|
|
{
|
|
String category = args[1];
|
|
String query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=? ORDER BY PRICE";
|
|
PreparedStatement statement = connection.prepareStatement(query2);
|
|
statement.setString(1, category);
|
|
ResultSet results = statement.executeQuery();
|
|
}
|
|
}
|
|
|
|
private static void controlledStrings() throws IOException, SQLException {
|
|
// GOOD: integers cannot have special characters in them
|
|
{
|
|
Statement statement = connection.createStatement();
|
|
String queryWithInt = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
|
+ categoryId + "' ORDER BY PRICE";
|
|
ResultSet results = statement.executeQuery(queryWithInt);
|
|
}
|
|
|
|
// GOOD: enum names are safe
|
|
{
|
|
Statement statement = connection.createStatement();
|
|
String queryWithEnum = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
|
+ Category.Topping + "' ORDER BY PRICE";
|
|
ResultSet results = statement.executeQuery(queryWithEnum);
|
|
}
|
|
|
|
// GOOD: enum with toString called on it is safe
|
|
{
|
|
Statement statement = connection.createStatement();
|
|
String queryWithEnumToString = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
|
+ Category.Topping.toString() + "' ORDER BY PRICE";
|
|
ResultSet results = statement.executeQuery(queryWithEnumToString);
|
|
}
|
|
|
|
// GOOD: class names are okay
|
|
{
|
|
Statement statement = connection.createStatement();
|
|
String queryWithClassName = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
|
+ Test.class.getName() + "' ORDER BY PRICE";
|
|
ResultSet results = statement.executeQuery(queryWithClassName);
|
|
}
|
|
|
|
// GOOD: class names are okay
|
|
{
|
|
Statement statement = connection.createStatement();
|
|
String queryWithClassSimpleName = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
|
+ Test.class.getSimpleName() + "' ORDER BY PRICE";
|
|
ResultSet results = statement
|
|
.executeQuery(queryWithClassSimpleName);
|
|
}
|
|
// GOOD: certain toString() methods are okay
|
|
{
|
|
Statement statement = connection.createStatement();
|
|
String queryWithDoubleToString = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
|
|
+ Double.toString(categoryId) + "' ORDER BY PRICE";
|
|
ResultSet results = statement.executeQuery(queryWithDoubleToString);
|
|
}
|
|
}
|
|
|
|
private static void tableNames(String[] args) throws IOException, SQLException {
|
|
// GOOD: table names cannot be replaced by a wildcard
|
|
{
|
|
Statement statement = connection.createStatement();
|
|
String queryWithTableName = "SELECT ITEM,PRICE FROM " + tableName
|
|
+ " WHERE ITEM_CATEGORY='Biscuits' ORDER BY PRICE";
|
|
ResultSet results = statement.executeQuery(queryWithTableName);
|
|
}
|
|
{
|
|
Statement statement = connection.createStatement();
|
|
String queryWithTableName2 = "SELECT ITEM,PRICE FROM " + tableName;
|
|
ResultSet results = statement.executeQuery(queryWithTableName2);
|
|
}
|
|
{
|
|
Statement statement = connection.createStatement();
|
|
String queryWithTableName3 = "SELECT ITEM,PRICE" + " FROM " + tableName;
|
|
ResultSet results = statement.executeQuery(queryWithTableName3);
|
|
}
|
|
|
|
// BAD: a table name that is user input
|
|
{
|
|
String userTabName = args[1];
|
|
Statement statement = connection.createStatement();
|
|
String queryWithUserTableName = "SELECT ITEM,PRICE FROM "
|
|
+ userTabName
|
|
+ " WHERE ITEM_CATEGORY='Biscuits' ORDER BY PRICE";
|
|
ResultSet results = statement.executeQuery(queryWithUserTableName);
|
|
}
|
|
}
|
|
|
|
private static void bindingVars(String[] args) throws IOException, SQLException {
|
|
// BAD: the category might have SQL special characters in it
|
|
{
|
|
String category = args[1];
|
|
Statement statement = connection.createStatement();
|
|
String prefix = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='";
|
|
String suffix = "' ORDER BY PRICE";
|
|
switch(prefix) {
|
|
case String prefixAlias when prefix.length() > 10 -> statement.executeQuery(prefixAlias + category + suffix);
|
|
default -> { }
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void main(String[] args) throws IOException, SQLException {
|
|
tainted(args);
|
|
unescaped();
|
|
good(args);
|
|
controlledStrings();
|
|
tableNames(args);
|
|
bindingVars(args);
|
|
}
|
|
}
|
|
|