我容易受到 SQL 注射吗?
Am I vulnerable to SQL Injection?
我有这个 class 扩展了 class 实现 CustomTaskChange。由于某些 class 属性(如列名和类型)由 XML 文件传递给它,因此我需要进行字符串连接。我确实使用了 PreparedStatement,但我想知道我是否仍然容易受到 SQL 注入的影响,如果是这种情况,我该如何确保它安全?
XML 是一个 Liquibase ChangeSet(我将在下面留下示例)。
XML 文件
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">
<changeSet author="" id="57ba1e10-3e3a-4be1-a7a0-7a9fb9411565">
<customChange class="com.petapilot.migrations.customChanges.MultipleAdd" columnName="testeRegex" columnType="varchar(250)"
regex="saft_[0-9]{4}_[0-9]{1,10}_[0-9]{1,10}_nc_transactions" after="CreditAmount" notNull="true" default="sbc"></customChange>
</changeSet>
</databaseChangeLog>
自定义Class
@Override
public void execute(Database database) throws CustomChangeException {
try {
//check if there are any errors in the changelog file
checkArgumentsNumber();
boolean tablesFound = false;
boolean columnsAdded = false;
String sqlStatement = "ALTER TABLE NAME ADD COLUMN " +this.getColumnName()+" "+this.getColumnType();
if(notNull){
sqlStatement+=" NOT NULL";
}
if(defaultValue!=null){
sqlStatement+=" DEFAULT ?";
}
if (this.after != null) {
sqlStatement += " AFTER " +this.after;
}
System.out.println("The statement is: "+sqlStatement);
//get tables in the database
JdbcConnection connection = (JdbcConnection) database.getConnection();
DatabaseMetaData metadata;
metadata = connection.getMetaData();
String[] types = {"TABLE"};
ResultSet rs = metadata.getTables(connection.getCatalog(), null, "%", types);
//if the user chose to use a regex
if (this.getRegex() != null) {
Pattern pattern = Pattern.compile(this.getRegex());
while (rs.next()) {
String tableName = rs.getString(3);
Matcher matcher = pattern.matcher(tableName);
boolean matches = matcher.matches();
if (matches) {
tablesFound = true;
String addStatement=sqlStatement.replaceAll("NAME",tableName);
PreparedStatement s = connection.prepareStatement(addStatement);
if (!checkColumnsExists(s, tableName)) {
if(this.defaultValue!=null){
s.setString(1,this.defaultValue);
}
System.out.println("REGEX:"+s.toString());
s.executeUpdate();
columnsAdded = true;
}
}
}
}
checkInvalidInfo(tablesFound, columnsAdded, "All the matching tables already had that column");
} catch (InvalidArgumentsNumberException | SQLException | InvalidInfoException | DatabaseException e) {
throw new CustomChangeException("Error enabling trigger: " + e);
}
}
它是否是 SQL 注入漏洞将取决于 XML 文件的来源。
如果程序员正在编写此类文件,那么您就没有 SQL 注入问题。是的,可能 连接危险的东西,但这并不比开发人员将危险的东西直接写入代码的风险更大。
但是,如果 XML 文件来自最终用户,或来自其他服务,或来自允许其他人或服务修改的文件,那么它们应该被视为具有潜在危险,并且您的代码将面临 SQL 注入攻击的风险。
由于所有连接的值实际上都是标识符(列名和数据类型),而不是值,如果您检查它们是否仅由字母数字字符组成,您可能会很安全:
if (!getColumnName().matches("\p{AlNum}+")) {
throw new CustomChangeException(
"Invalid column name: \"" + getColumnName() + "\"");
}
if (!after.matches("\p{AlNum}+")) {
throw new CustomChangeException(
"Invalid 'after' column name: \"" + after + "\"");
}
if (!getColumnType().matches("\p{AlNum}+")) {
throw new CustomChangeException(
"Invalid column type: \"" + getColumnType() + "\"");
}
我有这个 class 扩展了 class 实现 CustomTaskChange。由于某些 class 属性(如列名和类型)由 XML 文件传递给它,因此我需要进行字符串连接。我确实使用了 PreparedStatement,但我想知道我是否仍然容易受到 SQL 注入的影响,如果是这种情况,我该如何确保它安全? XML 是一个 Liquibase ChangeSet(我将在下面留下示例)。
XML 文件
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">
<changeSet author="" id="57ba1e10-3e3a-4be1-a7a0-7a9fb9411565">
<customChange class="com.petapilot.migrations.customChanges.MultipleAdd" columnName="testeRegex" columnType="varchar(250)"
regex="saft_[0-9]{4}_[0-9]{1,10}_[0-9]{1,10}_nc_transactions" after="CreditAmount" notNull="true" default="sbc"></customChange>
</changeSet>
</databaseChangeLog>
自定义Class
@Override
public void execute(Database database) throws CustomChangeException {
try {
//check if there are any errors in the changelog file
checkArgumentsNumber();
boolean tablesFound = false;
boolean columnsAdded = false;
String sqlStatement = "ALTER TABLE NAME ADD COLUMN " +this.getColumnName()+" "+this.getColumnType();
if(notNull){
sqlStatement+=" NOT NULL";
}
if(defaultValue!=null){
sqlStatement+=" DEFAULT ?";
}
if (this.after != null) {
sqlStatement += " AFTER " +this.after;
}
System.out.println("The statement is: "+sqlStatement);
//get tables in the database
JdbcConnection connection = (JdbcConnection) database.getConnection();
DatabaseMetaData metadata;
metadata = connection.getMetaData();
String[] types = {"TABLE"};
ResultSet rs = metadata.getTables(connection.getCatalog(), null, "%", types);
//if the user chose to use a regex
if (this.getRegex() != null) {
Pattern pattern = Pattern.compile(this.getRegex());
while (rs.next()) {
String tableName = rs.getString(3);
Matcher matcher = pattern.matcher(tableName);
boolean matches = matcher.matches();
if (matches) {
tablesFound = true;
String addStatement=sqlStatement.replaceAll("NAME",tableName);
PreparedStatement s = connection.prepareStatement(addStatement);
if (!checkColumnsExists(s, tableName)) {
if(this.defaultValue!=null){
s.setString(1,this.defaultValue);
}
System.out.println("REGEX:"+s.toString());
s.executeUpdate();
columnsAdded = true;
}
}
}
}
checkInvalidInfo(tablesFound, columnsAdded, "All the matching tables already had that column");
} catch (InvalidArgumentsNumberException | SQLException | InvalidInfoException | DatabaseException e) {
throw new CustomChangeException("Error enabling trigger: " + e);
}
}
它是否是 SQL 注入漏洞将取决于 XML 文件的来源。
如果程序员正在编写此类文件,那么您就没有 SQL 注入问题。是的,可能 连接危险的东西,但这并不比开发人员将危险的东西直接写入代码的风险更大。
但是,如果 XML 文件来自最终用户,或来自其他服务,或来自允许其他人或服务修改的文件,那么它们应该被视为具有潜在危险,并且您的代码将面临 SQL 注入攻击的风险。
由于所有连接的值实际上都是标识符(列名和数据类型),而不是值,如果您检查它们是否仅由字母数字字符组成,您可能会很安全:
if (!getColumnName().matches("\p{AlNum}+")) {
throw new CustomChangeException(
"Invalid column name: \"" + getColumnName() + "\"");
}
if (!after.matches("\p{AlNum}+")) {
throw new CustomChangeException(
"Invalid 'after' column name: \"" + after + "\"");
}
if (!getColumnType().matches("\p{AlNum}+")) {
throw new CustomChangeException(
"Invalid column type: \"" + getColumnType() + "\"");
}