PHP - Add new column with placeholder MS SQL preventing SQL Injection












0














I am working on a PHP application based on MS SQL that, among other things, can add a column to a table, either bit, int or varchar. My current code is similar to this:



$sql = "ALTER TABLE myTable ADD ? ".$type;
$values = array($columnname);
if($type == "varchar")
$sql = $sql."(".$length.")";
$sql = $sql.";";
sqlsrv_query($conn, $sql, $values);


However, I only get back an error that tells me there's an incorrect syntax near '@P1'. I thought about inserting the column name into the string directly, but I'm afraid of SQL injection as it is a text input. I'm not as worried about it for the type and the length as those are a select and a number input.



I am hoping one of you can give me some advice on how to add the column without exposing myself to SQL injection. Thank you in advance!



(As this question has been marked a 'possible duplicate' I'd like to clarify that I'm specifically asking about adding a new column without exposing myself to SQL injection, not just inserting values into a table. I hope I made this clear.)










share|improve this question
























  • Possible duplicate of How can I prevent SQL injection in PHP?
    – Sanu0786
    Nov 23 '18 at 7:17










  • You probably cannot use parameters to specify identifier names (table names, column names, etc).
    – Salman A
    Nov 23 '18 at 7:23












  • @SalmanA Yes, I suspected that as well, but I'm not sure how else to do it without exposing myself to SQL injection.
    – pttg
    Nov 23 '18 at 7:25
















0














I am working on a PHP application based on MS SQL that, among other things, can add a column to a table, either bit, int or varchar. My current code is similar to this:



$sql = "ALTER TABLE myTable ADD ? ".$type;
$values = array($columnname);
if($type == "varchar")
$sql = $sql."(".$length.")";
$sql = $sql.";";
sqlsrv_query($conn, $sql, $values);


However, I only get back an error that tells me there's an incorrect syntax near '@P1'. I thought about inserting the column name into the string directly, but I'm afraid of SQL injection as it is a text input. I'm not as worried about it for the type and the length as those are a select and a number input.



I am hoping one of you can give me some advice on how to add the column without exposing myself to SQL injection. Thank you in advance!



(As this question has been marked a 'possible duplicate' I'd like to clarify that I'm specifically asking about adding a new column without exposing myself to SQL injection, not just inserting values into a table. I hope I made this clear.)










share|improve this question
























  • Possible duplicate of How can I prevent SQL injection in PHP?
    – Sanu0786
    Nov 23 '18 at 7:17










  • You probably cannot use parameters to specify identifier names (table names, column names, etc).
    – Salman A
    Nov 23 '18 at 7:23












  • @SalmanA Yes, I suspected that as well, but I'm not sure how else to do it without exposing myself to SQL injection.
    – pttg
    Nov 23 '18 at 7:25














0












0








0







I am working on a PHP application based on MS SQL that, among other things, can add a column to a table, either bit, int or varchar. My current code is similar to this:



$sql = "ALTER TABLE myTable ADD ? ".$type;
$values = array($columnname);
if($type == "varchar")
$sql = $sql."(".$length.")";
$sql = $sql.";";
sqlsrv_query($conn, $sql, $values);


However, I only get back an error that tells me there's an incorrect syntax near '@P1'. I thought about inserting the column name into the string directly, but I'm afraid of SQL injection as it is a text input. I'm not as worried about it for the type and the length as those are a select and a number input.



I am hoping one of you can give me some advice on how to add the column without exposing myself to SQL injection. Thank you in advance!



(As this question has been marked a 'possible duplicate' I'd like to clarify that I'm specifically asking about adding a new column without exposing myself to SQL injection, not just inserting values into a table. I hope I made this clear.)










share|improve this question















I am working on a PHP application based on MS SQL that, among other things, can add a column to a table, either bit, int or varchar. My current code is similar to this:



$sql = "ALTER TABLE myTable ADD ? ".$type;
$values = array($columnname);
if($type == "varchar")
$sql = $sql."(".$length.")";
$sql = $sql.";";
sqlsrv_query($conn, $sql, $values);


However, I only get back an error that tells me there's an incorrect syntax near '@P1'. I thought about inserting the column name into the string directly, but I'm afraid of SQL injection as it is a text input. I'm not as worried about it for the type and the length as those are a select and a number input.



I am hoping one of you can give me some advice on how to add the column without exposing myself to SQL injection. Thank you in advance!



(As this question has been marked a 'possible duplicate' I'd like to clarify that I'm specifically asking about adding a new column without exposing myself to SQL injection, not just inserting values into a table. I hope I made this clear.)







php sql sql-server sql-injection






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 '18 at 7:24

























asked Nov 23 '18 at 7:17









pttg

64




64












  • Possible duplicate of How can I prevent SQL injection in PHP?
    – Sanu0786
    Nov 23 '18 at 7:17










  • You probably cannot use parameters to specify identifier names (table names, column names, etc).
    – Salman A
    Nov 23 '18 at 7:23












  • @SalmanA Yes, I suspected that as well, but I'm not sure how else to do it without exposing myself to SQL injection.
    – pttg
    Nov 23 '18 at 7:25


















  • Possible duplicate of How can I prevent SQL injection in PHP?
    – Sanu0786
    Nov 23 '18 at 7:17










  • You probably cannot use parameters to specify identifier names (table names, column names, etc).
    – Salman A
    Nov 23 '18 at 7:23












  • @SalmanA Yes, I suspected that as well, but I'm not sure how else to do it without exposing myself to SQL injection.
    – pttg
    Nov 23 '18 at 7:25
















Possible duplicate of How can I prevent SQL injection in PHP?
– Sanu0786
Nov 23 '18 at 7:17




Possible duplicate of How can I prevent SQL injection in PHP?
– Sanu0786
Nov 23 '18 at 7:17












You probably cannot use parameters to specify identifier names (table names, column names, etc).
– Salman A
Nov 23 '18 at 7:23






You probably cannot use parameters to specify identifier names (table names, column names, etc).
– Salman A
Nov 23 '18 at 7:23














@SalmanA Yes, I suspected that as well, but I'm not sure how else to do it without exposing myself to SQL injection.
– pttg
Nov 23 '18 at 7:25




@SalmanA Yes, I suspected that as well, but I'm not sure how else to do it without exposing myself to SQL injection.
– pttg
Nov 23 '18 at 7:25












1 Answer
1






active

oldest

votes


















1














As comments above have stated, you can use a parameter placeholder only to substitute for a scalar value — that is, where you would otherwise use a single quoted string, quoted date/time, or numeric literal.



Parameters don't work for identifiers like table names or column names, nor SQL keywords, nor SQL expressions, nor lists of values (you would have to use one placeholder for each scalar value in a list).



For cases where you want to make a column name or SQL keywords dynamic as you are trying to do, you will be vulnerable to SQL injection unless you make sure to restrict the dynamic part to unharmful strings.



For example, you can do this with delimiting and escaping.



$columnname = str_replace("]", "]]", $columnname);
$sql = "ALTER TABLE myTable ADD [$columnname] $type";


MS SQL Server uses square brackets to delimit an identifier that may contain special characters. The str_replace() is just in case the column name itself contains square brackets. Read https://sqlsunday.com/2014/09/21/identifiers-in-tsql/ for more explanation.



What about $type? How can we make sure that's safe? The other technique is whitelisting. To make $type safe, you would need to check it against a list of allowed values.



switch ($type) {
case "int":
// OK, nothing to change
break;
case "varchar":
$type = "varchar($length)"
break;
// ...add cases for other allowed types...
default:
die("Unrecognized type: $type");
}


You can either die with an error in the default clause, or you can set $type to a reasonable default. Depends on how you want to handle it.



You might ask, Why so much code? Why can't this be simpler?



Because you require the software to do something that is dynamic. You're trying to make code do the right thing no matter what some user inputs. If you didn't need to support user input, you could make the column name and type fixed, and then it would be simple.






share|improve this answer

















  • 1




    Well stated. And I would add to this for OP - perhaps the issue is the design of a system that allows (encourages?) a user to alter the schema. That ability alone requires permissions that users are not typically given.
    – SMor
    Nov 25 '18 at 13:19











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%2f53442175%2fphp-add-new-column-with-placeholder-ms-sql-preventing-sql-injection%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














As comments above have stated, you can use a parameter placeholder only to substitute for a scalar value — that is, where you would otherwise use a single quoted string, quoted date/time, or numeric literal.



Parameters don't work for identifiers like table names or column names, nor SQL keywords, nor SQL expressions, nor lists of values (you would have to use one placeholder for each scalar value in a list).



For cases where you want to make a column name or SQL keywords dynamic as you are trying to do, you will be vulnerable to SQL injection unless you make sure to restrict the dynamic part to unharmful strings.



For example, you can do this with delimiting and escaping.



$columnname = str_replace("]", "]]", $columnname);
$sql = "ALTER TABLE myTable ADD [$columnname] $type";


MS SQL Server uses square brackets to delimit an identifier that may contain special characters. The str_replace() is just in case the column name itself contains square brackets. Read https://sqlsunday.com/2014/09/21/identifiers-in-tsql/ for more explanation.



What about $type? How can we make sure that's safe? The other technique is whitelisting. To make $type safe, you would need to check it against a list of allowed values.



switch ($type) {
case "int":
// OK, nothing to change
break;
case "varchar":
$type = "varchar($length)"
break;
// ...add cases for other allowed types...
default:
die("Unrecognized type: $type");
}


You can either die with an error in the default clause, or you can set $type to a reasonable default. Depends on how you want to handle it.



You might ask, Why so much code? Why can't this be simpler?



Because you require the software to do something that is dynamic. You're trying to make code do the right thing no matter what some user inputs. If you didn't need to support user input, you could make the column name and type fixed, and then it would be simple.






share|improve this answer

















  • 1




    Well stated. And I would add to this for OP - perhaps the issue is the design of a system that allows (encourages?) a user to alter the schema. That ability alone requires permissions that users are not typically given.
    – SMor
    Nov 25 '18 at 13:19
















1














As comments above have stated, you can use a parameter placeholder only to substitute for a scalar value — that is, where you would otherwise use a single quoted string, quoted date/time, or numeric literal.



Parameters don't work for identifiers like table names or column names, nor SQL keywords, nor SQL expressions, nor lists of values (you would have to use one placeholder for each scalar value in a list).



For cases where you want to make a column name or SQL keywords dynamic as you are trying to do, you will be vulnerable to SQL injection unless you make sure to restrict the dynamic part to unharmful strings.



For example, you can do this with delimiting and escaping.



$columnname = str_replace("]", "]]", $columnname);
$sql = "ALTER TABLE myTable ADD [$columnname] $type";


MS SQL Server uses square brackets to delimit an identifier that may contain special characters. The str_replace() is just in case the column name itself contains square brackets. Read https://sqlsunday.com/2014/09/21/identifiers-in-tsql/ for more explanation.



What about $type? How can we make sure that's safe? The other technique is whitelisting. To make $type safe, you would need to check it against a list of allowed values.



switch ($type) {
case "int":
// OK, nothing to change
break;
case "varchar":
$type = "varchar($length)"
break;
// ...add cases for other allowed types...
default:
die("Unrecognized type: $type");
}


You can either die with an error in the default clause, or you can set $type to a reasonable default. Depends on how you want to handle it.



You might ask, Why so much code? Why can't this be simpler?



Because you require the software to do something that is dynamic. You're trying to make code do the right thing no matter what some user inputs. If you didn't need to support user input, you could make the column name and type fixed, and then it would be simple.






share|improve this answer

















  • 1




    Well stated. And I would add to this for OP - perhaps the issue is the design of a system that allows (encourages?) a user to alter the schema. That ability alone requires permissions that users are not typically given.
    – SMor
    Nov 25 '18 at 13:19














1












1








1






As comments above have stated, you can use a parameter placeholder only to substitute for a scalar value — that is, where you would otherwise use a single quoted string, quoted date/time, or numeric literal.



Parameters don't work for identifiers like table names or column names, nor SQL keywords, nor SQL expressions, nor lists of values (you would have to use one placeholder for each scalar value in a list).



For cases where you want to make a column name or SQL keywords dynamic as you are trying to do, you will be vulnerable to SQL injection unless you make sure to restrict the dynamic part to unharmful strings.



For example, you can do this with delimiting and escaping.



$columnname = str_replace("]", "]]", $columnname);
$sql = "ALTER TABLE myTable ADD [$columnname] $type";


MS SQL Server uses square brackets to delimit an identifier that may contain special characters. The str_replace() is just in case the column name itself contains square brackets. Read https://sqlsunday.com/2014/09/21/identifiers-in-tsql/ for more explanation.



What about $type? How can we make sure that's safe? The other technique is whitelisting. To make $type safe, you would need to check it against a list of allowed values.



switch ($type) {
case "int":
// OK, nothing to change
break;
case "varchar":
$type = "varchar($length)"
break;
// ...add cases for other allowed types...
default:
die("Unrecognized type: $type");
}


You can either die with an error in the default clause, or you can set $type to a reasonable default. Depends on how you want to handle it.



You might ask, Why so much code? Why can't this be simpler?



Because you require the software to do something that is dynamic. You're trying to make code do the right thing no matter what some user inputs. If you didn't need to support user input, you could make the column name and type fixed, and then it would be simple.






share|improve this answer












As comments above have stated, you can use a parameter placeholder only to substitute for a scalar value — that is, where you would otherwise use a single quoted string, quoted date/time, or numeric literal.



Parameters don't work for identifiers like table names or column names, nor SQL keywords, nor SQL expressions, nor lists of values (you would have to use one placeholder for each scalar value in a list).



For cases where you want to make a column name or SQL keywords dynamic as you are trying to do, you will be vulnerable to SQL injection unless you make sure to restrict the dynamic part to unharmful strings.



For example, you can do this with delimiting and escaping.



$columnname = str_replace("]", "]]", $columnname);
$sql = "ALTER TABLE myTable ADD [$columnname] $type";


MS SQL Server uses square brackets to delimit an identifier that may contain special characters. The str_replace() is just in case the column name itself contains square brackets. Read https://sqlsunday.com/2014/09/21/identifiers-in-tsql/ for more explanation.



What about $type? How can we make sure that's safe? The other technique is whitelisting. To make $type safe, you would need to check it against a list of allowed values.



switch ($type) {
case "int":
// OK, nothing to change
break;
case "varchar":
$type = "varchar($length)"
break;
// ...add cases for other allowed types...
default:
die("Unrecognized type: $type");
}


You can either die with an error in the default clause, or you can set $type to a reasonable default. Depends on how you want to handle it.



You might ask, Why so much code? Why can't this be simpler?



Because you require the software to do something that is dynamic. You're trying to make code do the right thing no matter what some user inputs. If you didn't need to support user input, you could make the column name and type fixed, and then it would be simple.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 24 '18 at 17:35









Bill Karwin

372k61510667




372k61510667








  • 1




    Well stated. And I would add to this for OP - perhaps the issue is the design of a system that allows (encourages?) a user to alter the schema. That ability alone requires permissions that users are not typically given.
    – SMor
    Nov 25 '18 at 13:19














  • 1




    Well stated. And I would add to this for OP - perhaps the issue is the design of a system that allows (encourages?) a user to alter the schema. That ability alone requires permissions that users are not typically given.
    – SMor
    Nov 25 '18 at 13:19








1




1




Well stated. And I would add to this for OP - perhaps the issue is the design of a system that allows (encourages?) a user to alter the schema. That ability alone requires permissions that users are not typically given.
– SMor
Nov 25 '18 at 13:19




Well stated. And I would add to this for OP - perhaps the issue is the design of a system that allows (encourages?) a user to alter the schema. That ability alone requires permissions that users are not typically given.
– SMor
Nov 25 '18 at 13:19


















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.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • 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%2f53442175%2fphp-add-new-column-with-placeholder-ms-sql-preventing-sql-injection%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

What visual should I use to simply compare current year value vs last year in Power BI desktop

How to ignore python UserWarning in pytest?

Alexandru Averescu