How to prevent SQL injection when generating DDL dynamically?
Goal: dynamically generate a PreparedStatement immune to SQL injection.
// This is a bad method. SQL injection danger . But it works
private PreparedStatement generateSQLBad(Connection connection, String tableName,
String columnName, String columnType) throws SQLException {
String sql = "create table " + tableName + " (" + columnName + " " + columnType + ")";
PreparedStatement create = connection.prepareStatement(sql);
return create;
}
// I tried this. But it didn't work
private PreparedStatement generateSQLGood(Connection connection, String tableName,
String columnName, String columnType) throws SQLException {
String sql = "create table ? (? ?)";
PreparedStatement create = connection.prepareStatement(sql);
create.setString(1, tableName);
create.setString(2, columnName);
create.setString(3, columnType);
return create;
}
How to dynamically generate PreparedStatement where user could choose tablename, columntype etc. and no danger of SQL injection?
java jdbc sql-injection
|
show 5 more comments
Goal: dynamically generate a PreparedStatement immune to SQL injection.
// This is a bad method. SQL injection danger . But it works
private PreparedStatement generateSQLBad(Connection connection, String tableName,
String columnName, String columnType) throws SQLException {
String sql = "create table " + tableName + " (" + columnName + " " + columnType + ")";
PreparedStatement create = connection.prepareStatement(sql);
return create;
}
// I tried this. But it didn't work
private PreparedStatement generateSQLGood(Connection connection, String tableName,
String columnName, String columnType) throws SQLException {
String sql = "create table ? (? ?)";
PreparedStatement create = connection.prepareStatement(sql);
create.setString(1, tableName);
create.setString(2, columnName);
create.setString(3, columnType);
return create;
}
How to dynamically generate PreparedStatement where user could choose tablename, columntype etc. and no danger of SQL injection?
java jdbc sql-injection
1
There is no safe way to do this.
– Elliott Frisch
Jan 1 at 3:36
THank you so much and Happy New Year. what's second best?
– john
Jan 1 at 3:37
1
The second version won't even work.generateSQLBadwill work, but injection isn't even the biggest problem. You should probably not allow people from the outside to create tables.
– Tim Biegeleisen
Jan 1 at 3:52
1
Why do you think you need this capability in the first place? There must be any number of more viable alternatives; please help us to help you choose one by sharing your motivation with us.
– Kevin Anderson
Jan 1 at 3:54
1
I thought I should fix it. You should. There is still no safe way to do this. I echo the other's though, why are you doing this?
– Elliott Frisch
Jan 1 at 4:12
|
show 5 more comments
Goal: dynamically generate a PreparedStatement immune to SQL injection.
// This is a bad method. SQL injection danger . But it works
private PreparedStatement generateSQLBad(Connection connection, String tableName,
String columnName, String columnType) throws SQLException {
String sql = "create table " + tableName + " (" + columnName + " " + columnType + ")";
PreparedStatement create = connection.prepareStatement(sql);
return create;
}
// I tried this. But it didn't work
private PreparedStatement generateSQLGood(Connection connection, String tableName,
String columnName, String columnType) throws SQLException {
String sql = "create table ? (? ?)";
PreparedStatement create = connection.prepareStatement(sql);
create.setString(1, tableName);
create.setString(2, columnName);
create.setString(3, columnType);
return create;
}
How to dynamically generate PreparedStatement where user could choose tablename, columntype etc. and no danger of SQL injection?
java jdbc sql-injection
Goal: dynamically generate a PreparedStatement immune to SQL injection.
// This is a bad method. SQL injection danger . But it works
private PreparedStatement generateSQLBad(Connection connection, String tableName,
String columnName, String columnType) throws SQLException {
String sql = "create table " + tableName + " (" + columnName + " " + columnType + ")";
PreparedStatement create = connection.prepareStatement(sql);
return create;
}
// I tried this. But it didn't work
private PreparedStatement generateSQLGood(Connection connection, String tableName,
String columnName, String columnType) throws SQLException {
String sql = "create table ? (? ?)";
PreparedStatement create = connection.prepareStatement(sql);
create.setString(1, tableName);
create.setString(2, columnName);
create.setString(3, columnType);
return create;
}
How to dynamically generate PreparedStatement where user could choose tablename, columntype etc. and no danger of SQL injection?
java jdbc sql-injection
java jdbc sql-injection
edited Jan 1 at 10:14
Mark Rotteveel
60.6k1478121
60.6k1478121
asked Jan 1 at 3:32
johnjohn
113321
113321
1
There is no safe way to do this.
– Elliott Frisch
Jan 1 at 3:36
THank you so much and Happy New Year. what's second best?
– john
Jan 1 at 3:37
1
The second version won't even work.generateSQLBadwill work, but injection isn't even the biggest problem. You should probably not allow people from the outside to create tables.
– Tim Biegeleisen
Jan 1 at 3:52
1
Why do you think you need this capability in the first place? There must be any number of more viable alternatives; please help us to help you choose one by sharing your motivation with us.
– Kevin Anderson
Jan 1 at 3:54
1
I thought I should fix it. You should. There is still no safe way to do this. I echo the other's though, why are you doing this?
– Elliott Frisch
Jan 1 at 4:12
|
show 5 more comments
1
There is no safe way to do this.
– Elliott Frisch
Jan 1 at 3:36
THank you so much and Happy New Year. what's second best?
– john
Jan 1 at 3:37
1
The second version won't even work.generateSQLBadwill work, but injection isn't even the biggest problem. You should probably not allow people from the outside to create tables.
– Tim Biegeleisen
Jan 1 at 3:52
1
Why do you think you need this capability in the first place? There must be any number of more viable alternatives; please help us to help you choose one by sharing your motivation with us.
– Kevin Anderson
Jan 1 at 3:54
1
I thought I should fix it. You should. There is still no safe way to do this. I echo the other's though, why are you doing this?
– Elliott Frisch
Jan 1 at 4:12
1
1
There is no safe way to do this.
– Elliott Frisch
Jan 1 at 3:36
There is no safe way to do this.
– Elliott Frisch
Jan 1 at 3:36
THank you so much and Happy New Year. what's second best?
– john
Jan 1 at 3:37
THank you so much and Happy New Year. what's second best?
– john
Jan 1 at 3:37
1
1
The second version won't even work.
generateSQLBad will work, but injection isn't even the biggest problem. You should probably not allow people from the outside to create tables.– Tim Biegeleisen
Jan 1 at 3:52
The second version won't even work.
generateSQLBad will work, but injection isn't even the biggest problem. You should probably not allow people from the outside to create tables.– Tim Biegeleisen
Jan 1 at 3:52
1
1
Why do you think you need this capability in the first place? There must be any number of more viable alternatives; please help us to help you choose one by sharing your motivation with us.
– Kevin Anderson
Jan 1 at 3:54
Why do you think you need this capability in the first place? There must be any number of more viable alternatives; please help us to help you choose one by sharing your motivation with us.
– Kevin Anderson
Jan 1 at 3:54
1
1
I thought I should fix it. You should. There is still no safe way to do this. I echo the other's though, why are you doing this?
– Elliott Frisch
Jan 1 at 4:12
I thought I should fix it. You should. There is still no safe way to do this. I echo the other's though, why are you doing this?
– Elliott Frisch
Jan 1 at 4:12
|
show 5 more comments
1 Answer
1
active
oldest
votes
You can't use ? parameter placeholders for identifiers (table names and column names). Nor can they be used for SQL keywords, like data types. Preparing a query needs to be able to validate the syntax, and validate that your table names and so on are legal. This must be done at prepare time, not at execute time. SQL doesn't allow parameters to contain syntax. They are always treated as scalar values. That's how they protect against SQL injection.
So parameters can only be used in place of scalar literals, like quoted strings or dates, or numeric values.
What to do for dynamic identifiers? As the comments suggest, the best you can do is filter the inputs so they're not going to introduce SQL injection. In a way, dynamic SQL based partially on user input is SQL injection. You just need to allow it in a controlled way.
All SQL implementations allow you to use special characters in your table names if you delimit the identifier. Standard SQL uses double-quotes for delimiters. MySQL uses back-ticks, and Microsoft SQL Server uses square brackets.
The point is that you can make strange-looking table names this way, like table names containing spaces, or punctuation, or international characters, or SQL reserved words.
CREATE TABLE "my table" ( col1 VARCHAR(20) );
CREATE TABLE "order" ( col1 VARCHAR(20) );
See also my answer to https://stackoverflow.com/a/214344/20860
But what if the table name itself contains a literal double-quote character? Then you must escape that character. Either use a double character or a backslash:
CREATE TABLE "Dwayne ""The Rock"" Johnson" ( col1 VARCHAR(20) );
CREATE TABLE "Dwayne "The Rock" Johnson" ( col1 VARCHAR(20) );
You could alternatively design your function to check the dynamic table name for such characters, and either strip them out or throw an exception.
But even if you make the statement safe by carefully filtering the input, this might not satisfy the checkmarx warning. SQL injection testers have no way of analyzing your custom code to be sure it filters input reliably.
You may just have to do your best to make the dynamic SQL safe, knowing that checkmarx will always complain about it. Write comments in your code explaining your safety measures to future developers who read your code.
Also write unit tests to ensure that dangerous inputs result in either safe DDL statements, or else exceptions.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53992860%2fhow-to-prevent-sql-injection-when-generating-ddl-dynamically%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can't use ? parameter placeholders for identifiers (table names and column names). Nor can they be used for SQL keywords, like data types. Preparing a query needs to be able to validate the syntax, and validate that your table names and so on are legal. This must be done at prepare time, not at execute time. SQL doesn't allow parameters to contain syntax. They are always treated as scalar values. That's how they protect against SQL injection.
So parameters can only be used in place of scalar literals, like quoted strings or dates, or numeric values.
What to do for dynamic identifiers? As the comments suggest, the best you can do is filter the inputs so they're not going to introduce SQL injection. In a way, dynamic SQL based partially on user input is SQL injection. You just need to allow it in a controlled way.
All SQL implementations allow you to use special characters in your table names if you delimit the identifier. Standard SQL uses double-quotes for delimiters. MySQL uses back-ticks, and Microsoft SQL Server uses square brackets.
The point is that you can make strange-looking table names this way, like table names containing spaces, or punctuation, or international characters, or SQL reserved words.
CREATE TABLE "my table" ( col1 VARCHAR(20) );
CREATE TABLE "order" ( col1 VARCHAR(20) );
See also my answer to https://stackoverflow.com/a/214344/20860
But what if the table name itself contains a literal double-quote character? Then you must escape that character. Either use a double character or a backslash:
CREATE TABLE "Dwayne ""The Rock"" Johnson" ( col1 VARCHAR(20) );
CREATE TABLE "Dwayne "The Rock" Johnson" ( col1 VARCHAR(20) );
You could alternatively design your function to check the dynamic table name for such characters, and either strip them out or throw an exception.
But even if you make the statement safe by carefully filtering the input, this might not satisfy the checkmarx warning. SQL injection testers have no way of analyzing your custom code to be sure it filters input reliably.
You may just have to do your best to make the dynamic SQL safe, knowing that checkmarx will always complain about it. Write comments in your code explaining your safety measures to future developers who read your code.
Also write unit tests to ensure that dangerous inputs result in either safe DDL statements, or else exceptions.
add a comment |
You can't use ? parameter placeholders for identifiers (table names and column names). Nor can they be used for SQL keywords, like data types. Preparing a query needs to be able to validate the syntax, and validate that your table names and so on are legal. This must be done at prepare time, not at execute time. SQL doesn't allow parameters to contain syntax. They are always treated as scalar values. That's how they protect against SQL injection.
So parameters can only be used in place of scalar literals, like quoted strings or dates, or numeric values.
What to do for dynamic identifiers? As the comments suggest, the best you can do is filter the inputs so they're not going to introduce SQL injection. In a way, dynamic SQL based partially on user input is SQL injection. You just need to allow it in a controlled way.
All SQL implementations allow you to use special characters in your table names if you delimit the identifier. Standard SQL uses double-quotes for delimiters. MySQL uses back-ticks, and Microsoft SQL Server uses square brackets.
The point is that you can make strange-looking table names this way, like table names containing spaces, or punctuation, or international characters, or SQL reserved words.
CREATE TABLE "my table" ( col1 VARCHAR(20) );
CREATE TABLE "order" ( col1 VARCHAR(20) );
See also my answer to https://stackoverflow.com/a/214344/20860
But what if the table name itself contains a literal double-quote character? Then you must escape that character. Either use a double character or a backslash:
CREATE TABLE "Dwayne ""The Rock"" Johnson" ( col1 VARCHAR(20) );
CREATE TABLE "Dwayne "The Rock" Johnson" ( col1 VARCHAR(20) );
You could alternatively design your function to check the dynamic table name for such characters, and either strip them out or throw an exception.
But even if you make the statement safe by carefully filtering the input, this might not satisfy the checkmarx warning. SQL injection testers have no way of analyzing your custom code to be sure it filters input reliably.
You may just have to do your best to make the dynamic SQL safe, knowing that checkmarx will always complain about it. Write comments in your code explaining your safety measures to future developers who read your code.
Also write unit tests to ensure that dangerous inputs result in either safe DDL statements, or else exceptions.
add a comment |
You can't use ? parameter placeholders for identifiers (table names and column names). Nor can they be used for SQL keywords, like data types. Preparing a query needs to be able to validate the syntax, and validate that your table names and so on are legal. This must be done at prepare time, not at execute time. SQL doesn't allow parameters to contain syntax. They are always treated as scalar values. That's how they protect against SQL injection.
So parameters can only be used in place of scalar literals, like quoted strings or dates, or numeric values.
What to do for dynamic identifiers? As the comments suggest, the best you can do is filter the inputs so they're not going to introduce SQL injection. In a way, dynamic SQL based partially on user input is SQL injection. You just need to allow it in a controlled way.
All SQL implementations allow you to use special characters in your table names if you delimit the identifier. Standard SQL uses double-quotes for delimiters. MySQL uses back-ticks, and Microsoft SQL Server uses square brackets.
The point is that you can make strange-looking table names this way, like table names containing spaces, or punctuation, or international characters, or SQL reserved words.
CREATE TABLE "my table" ( col1 VARCHAR(20) );
CREATE TABLE "order" ( col1 VARCHAR(20) );
See also my answer to https://stackoverflow.com/a/214344/20860
But what if the table name itself contains a literal double-quote character? Then you must escape that character. Either use a double character or a backslash:
CREATE TABLE "Dwayne ""The Rock"" Johnson" ( col1 VARCHAR(20) );
CREATE TABLE "Dwayne "The Rock" Johnson" ( col1 VARCHAR(20) );
You could alternatively design your function to check the dynamic table name for such characters, and either strip them out or throw an exception.
But even if you make the statement safe by carefully filtering the input, this might not satisfy the checkmarx warning. SQL injection testers have no way of analyzing your custom code to be sure it filters input reliably.
You may just have to do your best to make the dynamic SQL safe, knowing that checkmarx will always complain about it. Write comments in your code explaining your safety measures to future developers who read your code.
Also write unit tests to ensure that dangerous inputs result in either safe DDL statements, or else exceptions.
You can't use ? parameter placeholders for identifiers (table names and column names). Nor can they be used for SQL keywords, like data types. Preparing a query needs to be able to validate the syntax, and validate that your table names and so on are legal. This must be done at prepare time, not at execute time. SQL doesn't allow parameters to contain syntax. They are always treated as scalar values. That's how they protect against SQL injection.
So parameters can only be used in place of scalar literals, like quoted strings or dates, or numeric values.
What to do for dynamic identifiers? As the comments suggest, the best you can do is filter the inputs so they're not going to introduce SQL injection. In a way, dynamic SQL based partially on user input is SQL injection. You just need to allow it in a controlled way.
All SQL implementations allow you to use special characters in your table names if you delimit the identifier. Standard SQL uses double-quotes for delimiters. MySQL uses back-ticks, and Microsoft SQL Server uses square brackets.
The point is that you can make strange-looking table names this way, like table names containing spaces, or punctuation, or international characters, or SQL reserved words.
CREATE TABLE "my table" ( col1 VARCHAR(20) );
CREATE TABLE "order" ( col1 VARCHAR(20) );
See also my answer to https://stackoverflow.com/a/214344/20860
But what if the table name itself contains a literal double-quote character? Then you must escape that character. Either use a double character or a backslash:
CREATE TABLE "Dwayne ""The Rock"" Johnson" ( col1 VARCHAR(20) );
CREATE TABLE "Dwayne "The Rock" Johnson" ( col1 VARCHAR(20) );
You could alternatively design your function to check the dynamic table name for such characters, and either strip them out or throw an exception.
But even if you make the statement safe by carefully filtering the input, this might not satisfy the checkmarx warning. SQL injection testers have no way of analyzing your custom code to be sure it filters input reliably.
You may just have to do your best to make the dynamic SQL safe, knowing that checkmarx will always complain about it. Write comments in your code explaining your safety measures to future developers who read your code.
Also write unit tests to ensure that dangerous inputs result in either safe DDL statements, or else exceptions.
answered Jan 1 at 19:40
Bill KarwinBill Karwin
378k64516672
378k64516672
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53992860%2fhow-to-prevent-sql-injection-when-generating-ddl-dynamically%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
There is no safe way to do this.
– Elliott Frisch
Jan 1 at 3:36
THank you so much and Happy New Year. what's second best?
– john
Jan 1 at 3:37
1
The second version won't even work.
generateSQLBadwill work, but injection isn't even the biggest problem. You should probably not allow people from the outside to create tables.– Tim Biegeleisen
Jan 1 at 3:52
1
Why do you think you need this capability in the first place? There must be any number of more viable alternatives; please help us to help you choose one by sharing your motivation with us.
– Kevin Anderson
Jan 1 at 3:54
1
I thought I should fix it. You should. There is still no safe way to do this. I echo the other's though, why are you doing this?
– Elliott Frisch
Jan 1 at 4:12