How to prevent SQL injection when generating DDL dynamically?












1















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?










share|improve this question




















  • 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. 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





    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















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?










share|improve this question




















  • 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. 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





    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








1


1






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?










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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. 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





    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





    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. 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





    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












1 Answer
1






active

oldest

votes


















1














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.






share|improve this answer























    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
    });


    }
    });














    draft saved

    draft discarded


















    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









    1














    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.






    share|improve this answer




























      1














      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.






      share|improve this answer


























        1












        1








        1







        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.






        share|improve this answer













        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jan 1 at 19:40









        Bill KarwinBill Karwin

        378k64516672




        378k64516672
































            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Mossoró

            Error while reading .h5 file using the rhdf5 package in R

            Pushsharp Apns notification error: 'InvalidToken'