Thanks for your feedback, Anthony.
I'll take a few of your points in turn.
With regards to the fact that not all SQL queries are directly
parameterizable, this is true. Structural parts of a query, such as table
names, column names and complex conditions are hard to parameterize with
"vanilla" prepared statements, and many developers like to abstract some of
these structural parts of a SQL query into config files, and append
additional conditional constraints into the query at runtime based on user
input.
This feature addresses this head on. So long as the structural parts of the
prepared statement -- that is, table names, database names and column names
-- are not themselves attacker-controlled (I can't think of a valid reason
whey they would be), this feature is happy for developers to concatenate
them into a query string. For example, the following is not detected by the
feature as dangerous, because the query (whilst dynamically constructed) is
the linear concatenation of string literals, and so is a safeconst.
$query = "SELECT * from {$config['tablename']} WHERE id=?";
if(isset($_GET["filterbycolor"]))
$query .= " AND color=?";
do_prepared_statement($query, array("id" => $_GET["id"] "color" =>
$_GET["color"]));
We can even take this to an extreme to prove how flexible this can be.
Here's a function that issues a SQL statement where everything from the
table name and column name, to the structure and form of the condition, as
well as the limit, order and direction of the output are all chosen by the
caller. So long as the structural parts (i.e. the table names, database
names and column names) are safeconsts, the resulting query is a safeconst,
and this feature correctly identifies the resulting query as untainted).
http://phpoops.cloudapp.net/dynamic_pdo.php?viewcode
http://phpoops.cloudapp.net/dynamic_pdo.php
Finally, this feature is off-by-default. This means that that the feature
only helps developers who want to (or are required to) parameterize their
queries. It detects queries where the query cannot be proven "safe", and
then informs the developer that they need to upgrade the query so that the
dynamic parts of the query are parameterized to be in compliance with the
website's PHP.INI settings for this feature.
==
With regard to static analysis, I have a lot of respect for static analysis
tools, but especially in the webapplication world, they lack adoption, and
hence have limited real-world value. In over a decade of security
consulting experience, and with the notable exception of Google and
Microsoft, I've never seen any company that routinely scanned their website
with static analysis tools more complex than "grep".
As well as poor adoption, static analysis tools quickly run into
intractible problems doing analysis over unbound-loops, indirect function
calls or eval statements, and can get confused when looking at files out of
context (e.g. scanning included files). Runtime analysis, on the other
hand, always runs, has zero startup cost, negligble runtime cost and
guarrantees to check every codepath that is actually taken; regardless of
how it was reached.
For this reason, I think static analysis is the wrong tool for this job.
==
With regard to SQL parameterization not always being safe, the case you are
citing is due to a security defect in the way PHP emulates SQL
parameterization for old versions of MySQL that don't support
parameterization. In this particular case, PHP "emulates" the
parametization by escaping the parameters, and -- since escaping is a
dangerous way to build SQL query statements -- this goes horribly wrong and
leads to a SQL injection. But to be clear: this is a defect in PHP's
/emulation/ of prepared statements when real prepared statements are not
available, not a problem of prepared statements themselves.
Where parameterized queries are available at the database layer, and PHP is
not defectively emulating them, they are (by definition) immune from SQL
injection. Parameterized queries are not flattened to a string using
escaping. They are sent to the database in parameterized form, and are
replaced at AST-construction stage in the database itself. This means they
are immune from weird bugs like character-set differences between
application and SQL-server: so long as the query is untainted, the attacker
cannot affect the structure of the AST using only parameter values, and
hence can never SQL-inject the database.
To quote Wikipedia's article on prepared statements (
https://en.wikipedia.org/wiki/Prepared_statement):
>> Prepared statements are resilient against SQL injection, because
parameter values, which are transmitted later
>> using a different protocol, need not be correctly escaped. If the
original statement template is not derived
>> from external input, SQL injection cannot occur.
To quote the W3C (http://www.w3schools.com/sql/sql_injection.asp)
>> The only proven way to protect a web site from SQL injection attacks, is
to use SQL parameters.
To quote security consortium OWASP (
https://www.owasp.org/index.php/Query_Parameterization_Cheat_Sheet)
>> SQL injection is best prevented through the use of parameterized queries..
And to quote one of Microsoft's security engineers on the SQL team,
specifically addressing PHP (
http://blogs.msdn.com/b/brian_swan/archive/2010/03/04/what_2700_s-the-right-way-to-avoid-sql-injection-in-php-scripts_3f00_.aspx
):
*>> The most common suggestion I’ve seen for preventing SQL injection
involves trying to remove or escape any possible SQL code from user input
before concatenating it with the SQL code to be executed. There are several
PHP functions (and functions in PHP extensions) that can be used to do
this, but all of them are potentially vulnerable. If you concatenate user
input with SQL code that will be executed in the database, you run the risk
of a SQL injection attack no matter how much parsing and escaping of the
input you do. How can you be 100% sure that you’ve thought of all
possibilities that a creative hacker might think of? How can you be sure
that you’ve taken the appropriate measures to mitigate an attack? How can
you be sure that the functions you are using to remove or escape dangerous
user input aren’t buggy?*
*>> The right way to prevent SQL injection is by using parameterized
queries. This means defining the SQL code that is to be executed with
placeholders for parameter values, programmatically adding the parameter
values, then executing the query. Doing this allows the server to create an
execution plan for the query, which prevents any "injected" SQL from being
executed. An example will help in explaining this. Let’s use the same
script, but I’ll define the SQL query with parameter placeholders.*
You are of course welcome to disagree with the overwhelming body of
security advice that parameterized queries are the correct, secure way to
prevent SQL injection. In that case, you only need to not enable this
feature. This feature is off-by-default, and only attempts to help secure
webapplications and webdevelopers who do (or are required, for example by
PCI compliance standards) to adopt this security-best-practice to ensure
that they do so systematically across their entire website.
==
With regard to SQL extensions that don't ship with PHP, it is true that
this doesn't add security to builtin functions that don't ship with PHP or
its various extensions. Extensions that ship entirely independently to PHP
are free to copy the two-line edit to their codebase to also take advantage
of the feature. If they choose not to, that is their prerogative. In the
meantime, securing MySQLi, Postgres and PDO seems to me to be a good place
to start.
==
With regard to training, I 100% agree that developer security training in
general is pretty bad, but especially so for PHP. For example, none of the
pages on SQL builtins (like this one
http://php.net/manual/en/function.mysql-query.php) mention SQL injection,
why it is bad, and how to prevent it.
By way of contrast, see Microsoft's Database.SqlQuery documentation (
https://msdn.microsoft.com/en-us/library/system.data.entity.database.sqlquery(v=vs.113).aspx)
which states:
>> Creates a raw SQL query that will return elements of the given type. The
type can be any type that has properties that match the names of the
columns returned from the query, or can be a simple primitive type. The
type does not have to be an entity type. The results of this query are
never tracked by the context even if the type of object returned is an
entity type. Use the SqlQuery method to return entities that are tracked by
the context. *As with any API that accepts SQL it is important to
parameterize any user input to protect against a SQL injection attack. You
can include parameter place holders in the SQL query string and then supply
parameter values as additional arguments*. Any parameter values you supply
will automatically be converted to a DbParameter.
context.Database.SqlQuery(typeof(Post), "SELECT * FROM dbo.Posts WHERE
Author = @p0", userSuppliedAuthor); Alternatively, you can also construct a
DbParameter and supply it to SqlQuery. This allows you to use named
parameters in the SQL query string. context.Database.SqlQuery(typeof(Post),
"SELECT * FROM dbo.Posts WHERE Author = @author", new
SqlParameter("@author", userSuppliedAuthor)); (emphasis added).
This feature helps address some of this technical debt. This feature gives
website owners (who may be nontechnical, or technical but with limited
oversight of their large workforce) a tool to prevent unsafe SQL-queries
being written in the first place. If one of their developers then writes
(or exposes) a query that could be tainted with attacker data -- even if
the user data isn't an injection attack in progress -- PHP blocks the query
and provides the developer with a link that can tell them about SQL
injection, why their query was blocked and how they can restructure their
query so that it's not vulnerable to SQL injection any more. By doing this
/as the developer writes code/, rather than via some static analysis tool
or security audit weeks or months later, developers will quickly discover
that writing parameterized queries is the only way to dynamically interact
with a database when the feature is enabled.
Hope that clears some of this up,
Matt
On 5 August 2015 at 21:53, Anthony Ferrara <ircmaxell@gmail.com> wrote:
> Matt,
>
> > To be clear: this feature does not track taint through escape functions,
> > regular expression filters, ctype_filters and the like by design.
> Security
> > best-practice and more than a decade of security consulting experience
> show
> > that developers who rely on filters and escaping rarely manage to do so
> > competently and systematically enough to prevent SQL-injection on
> > non-trivial websites. Rather, this feature recognizes that SQL-injection
> is
> > already a solved problem. It is uncontroversial and overwhelmingly
> accepted
> > security best-practice to ensure that every dynamic SQL query is executed
> > via a prepared statement rather than via string-escaping.
>
> Except that not every part of a query is preparable. And many
> non-trivial complexity websites use these portions of queries
> extensively.
>
> Hence a blanket **programming language level** blocking of it is not
> really going to fly.
>
> > This feature works best for big websites that are following (or in the
> > process of migrating their code to follow) this security-best-practice,
> as
> > it allows them to systematically verify during development that the query
> > string to every SQL statement is guaranteed untainted by attackers.
>
> Actually, this allows them to verify at runtime. Not during
> development (codepaths that aren't hit at devtime can still cause
> problems at runtime).
>
> If this is your goal, I'd suggest doing static analysis to prove (or
> not) it. I have a working proof-of-concept of one here:
> https://github.com/ircmaxell/php-security-scanner
>
> > In terms of whether this RFC is too coupled with SQL extensions, I am
> > sensitive to these concerns, but I don't think they apply for three broad
> > reasons:
> >
> > Firstly, the taint logic tracks "safeconstness" (i.e. whether a
> zend_string
> > is a string literal or linear concatenation of string literals), and
> > by-design does not attempt to interact with escaping functions because
> (as
> > your example clearly shows), escaping functions only /sometimes/ prevent
> > injections, whereas parameterized queries /always/ stop injections.
>
> No they don't. They only stop injections when used correctly. For
> example (an edge case, but an important one):
>
> http://stackoverflow.com/questions/134099/are-pdo-prepared-statements-sufficient-to-prevent-sql-injection/12202218#12202218
>
> And that doesn't even touch on the DB backends that don't support PS.
> And it doesn't even touch on the fact that not every dynamic part of a
> query is preparable.
>
> > reason the taint feature can be trivially applied to any builltin
> function
> > where one parameter is structural and should be constant. It could be
> > deployed without modification to prevent injection into regular
> expression
> > queries for example to prevent denial-of-service, or to prove that the
> > parameter to shell_exec is constant.
> >
> > Secondly, this feature applies globally to all SQL extensions, not just
> > mysqli. This feature encompasses protection of mysqli, PDO and Postgres..
> In
> > future, I would like to build this feature out to include some of the
> other
> > categories of injection later, but given that SQL-injections remain the
> > single most commonly exploited vulnerability in PHP applications, I think
> > starting with them is probably best. Tackling SQL-injection in PHP is a
> big
> > enough task as it is, and is a good place to start.
> >
> > Thirdly, although SQL extensions are extensions, this is a technicality,
> in
> > much the same way that Zend Core is not supposed to be coupled to PHP. In
> > reality, /most/ non-trivial PHP websites use one SQL extension or
> another to
> > interact with a database, and despite parameterized queries existing for
> > over a decade, huge numbers of PHP websites remain vulnerable to them --
> > with a devastating impact on the company and their users when the
> > vulnerability is exploited.
>
> Except that there are a number of DB extensions that don't ship with
> PHP. And those that aren't shipped at all (they are custom propriatary
> extensions). And those that aren't really SQL, but use similar
> semantics (MongoDB).
>
> > Understanding SQL injections is hard for many junior developers to
> > understand, and hard for companies to apply systematically. The impact of
> > them getting it wrong can be catastrophic to companies and is a major
> threat
> > to users' online privacy when their data gets compromised. I think having
> > PHP give developers a hand to write code that is unambiguously safe from
> > hackers would be a good for whole PHP community.
>
> It's hard, because tutorials make it hard. It's hard because we show
> concatenation as the right way of doing things, and then tell them
> it's wrong. It's hard, because we suck at teaching.
>
> Kent Beck had an awesome passage in his book Test-Driven-Development
> By Example. I'll paraphrase here, but he said that every engineer he
> worked with found testing difficult. However, his daughter found it
> easy and never even thought about it. It was because she was taught
> TDD from the ground up. She was taught that you don't write code and
> then test, you just test & write code. So she never had time to learn
> bad practices because she just learned how to do it right.
>
> And prepared statements are precisely like that. How many other
> programming languages have such major problems with SQLi? Most do not.
> Don't get me wrong, it exists in other languages (most definitely).
> But Parameterized Queries are a big focus in other languages.
>
> Our beginner tutorials all teach concatenation. Then escaping. Then
> PS. You want to fix the problem, fix it with education. Tainting can
> be a safeguard, but it's not a solution.
>
> My $0.02
>
> Anthony
>
I'll take a few of your points in turn.
With regards to the fact that not all SQL queries are directly
parameterizable, this is true. Structural parts of a query, such as table
names, column names and complex conditions are hard to parameterize with
"vanilla" prepared statements, and many developers like to abstract some of
these structural parts of a SQL query into config files, and append
additional conditional constraints into the query at runtime based on user
input.
This feature addresses this head on. So long as the structural parts of the
prepared statement -- that is, table names, database names and column names
-- are not themselves attacker-controlled (I can't think of a valid reason
whey they would be), this feature is happy for developers to concatenate
them into a query string. For example, the following is not detected by the
feature as dangerous, because the query (whilst dynamically constructed) is
the linear concatenation of string literals, and so is a safeconst.
$query = "SELECT * from {$config['tablename']} WHERE id=?";
if(isset($_GET["filterbycolor"]))
$query .= " AND color=?";
do_prepared_statement($query, array("id" => $_GET["id"] "color" =>
$_GET["color"]));
We can even take this to an extreme to prove how flexible this can be.
Here's a function that issues a SQL statement where everything from the
table name and column name, to the structure and form of the condition, as
well as the limit, order and direction of the output are all chosen by the
caller. So long as the structural parts (i.e. the table names, database
names and column names) are safeconsts, the resulting query is a safeconst,
and this feature correctly identifies the resulting query as untainted).
http://phpoops.cloudapp.net/dynamic_pdo.php?viewcode
http://phpoops.cloudapp.net/dynamic_pdo.php
Finally, this feature is off-by-default. This means that that the feature
only helps developers who want to (or are required to) parameterize their
queries. It detects queries where the query cannot be proven "safe", and
then informs the developer that they need to upgrade the query so that the
dynamic parts of the query are parameterized to be in compliance with the
website's PHP.INI settings for this feature.
==
With regard to static analysis, I have a lot of respect for static analysis
tools, but especially in the webapplication world, they lack adoption, and
hence have limited real-world value. In over a decade of security
consulting experience, and with the notable exception of Google and
Microsoft, I've never seen any company that routinely scanned their website
with static analysis tools more complex than "grep".
As well as poor adoption, static analysis tools quickly run into
intractible problems doing analysis over unbound-loops, indirect function
calls or eval statements, and can get confused when looking at files out of
context (e.g. scanning included files). Runtime analysis, on the other
hand, always runs, has zero startup cost, negligble runtime cost and
guarrantees to check every codepath that is actually taken; regardless of
how it was reached.
For this reason, I think static analysis is the wrong tool for this job.
==
With regard to SQL parameterization not always being safe, the case you are
citing is due to a security defect in the way PHP emulates SQL
parameterization for old versions of MySQL that don't support
parameterization. In this particular case, PHP "emulates" the
parametization by escaping the parameters, and -- since escaping is a
dangerous way to build SQL query statements -- this goes horribly wrong and
leads to a SQL injection. But to be clear: this is a defect in PHP's
/emulation/ of prepared statements when real prepared statements are not
available, not a problem of prepared statements themselves.
Where parameterized queries are available at the database layer, and PHP is
not defectively emulating them, they are (by definition) immune from SQL
injection. Parameterized queries are not flattened to a string using
escaping. They are sent to the database in parameterized form, and are
replaced at AST-construction stage in the database itself. This means they
are immune from weird bugs like character-set differences between
application and SQL-server: so long as the query is untainted, the attacker
cannot affect the structure of the AST using only parameter values, and
hence can never SQL-inject the database.
To quote Wikipedia's article on prepared statements (
https://en.wikipedia.org/wiki/Prepared_statement):
>> Prepared statements are resilient against SQL injection, because
parameter values, which are transmitted later
>> using a different protocol, need not be correctly escaped. If the
original statement template is not derived
>> from external input, SQL injection cannot occur.
To quote the W3C (http://www.w3schools.com/sql/sql_injection.asp)
>> The only proven way to protect a web site from SQL injection attacks, is
to use SQL parameters.
To quote security consortium OWASP (
https://www.owasp.org/index.php/Query_Parameterization_Cheat_Sheet)
>> SQL injection is best prevented through the use of parameterized queries..
And to quote one of Microsoft's security engineers on the SQL team,
specifically addressing PHP (
http://blogs.msdn.com/b/brian_swan/archive/2010/03/04/what_2700_s-the-right-way-to-avoid-sql-injection-in-php-scripts_3f00_.aspx
):
*>> The most common suggestion I’ve seen for preventing SQL injection
involves trying to remove or escape any possible SQL code from user input
before concatenating it with the SQL code to be executed. There are several
PHP functions (and functions in PHP extensions) that can be used to do
this, but all of them are potentially vulnerable. If you concatenate user
input with SQL code that will be executed in the database, you run the risk
of a SQL injection attack no matter how much parsing and escaping of the
input you do. How can you be 100% sure that you’ve thought of all
possibilities that a creative hacker might think of? How can you be sure
that you’ve taken the appropriate measures to mitigate an attack? How can
you be sure that the functions you are using to remove or escape dangerous
user input aren’t buggy?*
*>> The right way to prevent SQL injection is by using parameterized
queries. This means defining the SQL code that is to be executed with
placeholders for parameter values, programmatically adding the parameter
values, then executing the query. Doing this allows the server to create an
execution plan for the query, which prevents any "injected" SQL from being
executed. An example will help in explaining this. Let’s use the same
script, but I’ll define the SQL query with parameter placeholders.*
You are of course welcome to disagree with the overwhelming body of
security advice that parameterized queries are the correct, secure way to
prevent SQL injection. In that case, you only need to not enable this
feature. This feature is off-by-default, and only attempts to help secure
webapplications and webdevelopers who do (or are required, for example by
PCI compliance standards) to adopt this security-best-practice to ensure
that they do so systematically across their entire website.
==
With regard to SQL extensions that don't ship with PHP, it is true that
this doesn't add security to builtin functions that don't ship with PHP or
its various extensions. Extensions that ship entirely independently to PHP
are free to copy the two-line edit to their codebase to also take advantage
of the feature. If they choose not to, that is their prerogative. In the
meantime, securing MySQLi, Postgres and PDO seems to me to be a good place
to start.
==
With regard to training, I 100% agree that developer security training in
general is pretty bad, but especially so for PHP. For example, none of the
pages on SQL builtins (like this one
http://php.net/manual/en/function.mysql-query.php) mention SQL injection,
why it is bad, and how to prevent it.
By way of contrast, see Microsoft's Database.SqlQuery documentation (
https://msdn.microsoft.com/en-us/library/system.data.entity.database.sqlquery(v=vs.113).aspx)
which states:
>> Creates a raw SQL query that will return elements of the given type. The
type can be any type that has properties that match the names of the
columns returned from the query, or can be a simple primitive type. The
type does not have to be an entity type. The results of this query are
never tracked by the context even if the type of object returned is an
entity type. Use the SqlQuery method to return entities that are tracked by
the context. *As with any API that accepts SQL it is important to
parameterize any user input to protect against a SQL injection attack. You
can include parameter place holders in the SQL query string and then supply
parameter values as additional arguments*. Any parameter values you supply
will automatically be converted to a DbParameter.
context.Database.SqlQuery(typeof(Post), "SELECT * FROM dbo.Posts WHERE
Author = @p0", userSuppliedAuthor); Alternatively, you can also construct a
DbParameter and supply it to SqlQuery. This allows you to use named
parameters in the SQL query string. context.Database.SqlQuery(typeof(Post),
"SELECT * FROM dbo.Posts WHERE Author = @author", new
SqlParameter("@author", userSuppliedAuthor)); (emphasis added).
This feature helps address some of this technical debt. This feature gives
website owners (who may be nontechnical, or technical but with limited
oversight of their large workforce) a tool to prevent unsafe SQL-queries
being written in the first place. If one of their developers then writes
(or exposes) a query that could be tainted with attacker data -- even if
the user data isn't an injection attack in progress -- PHP blocks the query
and provides the developer with a link that can tell them about SQL
injection, why their query was blocked and how they can restructure their
query so that it's not vulnerable to SQL injection any more. By doing this
/as the developer writes code/, rather than via some static analysis tool
or security audit weeks or months later, developers will quickly discover
that writing parameterized queries is the only way to dynamically interact
with a database when the feature is enabled.
Hope that clears some of this up,
Matt
On 5 August 2015 at 21:53, Anthony Ferrara <ircmaxell@gmail.com> wrote:
> Matt,
>
> > To be clear: this feature does not track taint through escape functions,
> > regular expression filters, ctype_filters and the like by design.
> Security
> > best-practice and more than a decade of security consulting experience
> show
> > that developers who rely on filters and escaping rarely manage to do so
> > competently and systematically enough to prevent SQL-injection on
> > non-trivial websites. Rather, this feature recognizes that SQL-injection
> is
> > already a solved problem. It is uncontroversial and overwhelmingly
> accepted
> > security best-practice to ensure that every dynamic SQL query is executed
> > via a prepared statement rather than via string-escaping.
>
> Except that not every part of a query is preparable. And many
> non-trivial complexity websites use these portions of queries
> extensively.
>
> Hence a blanket **programming language level** blocking of it is not
> really going to fly.
>
> > This feature works best for big websites that are following (or in the
> > process of migrating their code to follow) this security-best-practice,
> as
> > it allows them to systematically verify during development that the query
> > string to every SQL statement is guaranteed untainted by attackers.
>
> Actually, this allows them to verify at runtime. Not during
> development (codepaths that aren't hit at devtime can still cause
> problems at runtime).
>
> If this is your goal, I'd suggest doing static analysis to prove (or
> not) it. I have a working proof-of-concept of one here:
> https://github.com/ircmaxell/php-security-scanner
>
> > In terms of whether this RFC is too coupled with SQL extensions, I am
> > sensitive to these concerns, but I don't think they apply for three broad
> > reasons:
> >
> > Firstly, the taint logic tracks "safeconstness" (i.e. whether a
> zend_string
> > is a string literal or linear concatenation of string literals), and
> > by-design does not attempt to interact with escaping functions because
> (as
> > your example clearly shows), escaping functions only /sometimes/ prevent
> > injections, whereas parameterized queries /always/ stop injections.
>
> No they don't. They only stop injections when used correctly. For
> example (an edge case, but an important one):
>
> http://stackoverflow.com/questions/134099/are-pdo-prepared-statements-sufficient-to-prevent-sql-injection/12202218#12202218
>
> And that doesn't even touch on the DB backends that don't support PS.
> And it doesn't even touch on the fact that not every dynamic part of a
> query is preparable.
>
> > reason the taint feature can be trivially applied to any builltin
> function
> > where one parameter is structural and should be constant. It could be
> > deployed without modification to prevent injection into regular
> expression
> > queries for example to prevent denial-of-service, or to prove that the
> > parameter to shell_exec is constant.
> >
> > Secondly, this feature applies globally to all SQL extensions, not just
> > mysqli. This feature encompasses protection of mysqli, PDO and Postgres..
> In
> > future, I would like to build this feature out to include some of the
> other
> > categories of injection later, but given that SQL-injections remain the
> > single most commonly exploited vulnerability in PHP applications, I think
> > starting with them is probably best. Tackling SQL-injection in PHP is a
> big
> > enough task as it is, and is a good place to start.
> >
> > Thirdly, although SQL extensions are extensions, this is a technicality,
> in
> > much the same way that Zend Core is not supposed to be coupled to PHP. In
> > reality, /most/ non-trivial PHP websites use one SQL extension or
> another to
> > interact with a database, and despite parameterized queries existing for
> > over a decade, huge numbers of PHP websites remain vulnerable to them --
> > with a devastating impact on the company and their users when the
> > vulnerability is exploited.
>
> Except that there are a number of DB extensions that don't ship with
> PHP. And those that aren't shipped at all (they are custom propriatary
> extensions). And those that aren't really SQL, but use similar
> semantics (MongoDB).
>
> > Understanding SQL injections is hard for many junior developers to
> > understand, and hard for companies to apply systematically. The impact of
> > them getting it wrong can be catastrophic to companies and is a major
> threat
> > to users' online privacy when their data gets compromised. I think having
> > PHP give developers a hand to write code that is unambiguously safe from
> > hackers would be a good for whole PHP community.
>
> It's hard, because tutorials make it hard. It's hard because we show
> concatenation as the right way of doing things, and then tell them
> it's wrong. It's hard, because we suck at teaching.
>
> Kent Beck had an awesome passage in his book Test-Driven-Development
> By Example. I'll paraphrase here, but he said that every engineer he
> worked with found testing difficult. However, his daughter found it
> easy and never even thought about it. It was because she was taught
> TDD from the ground up. She was taught that you don't write code and
> then test, you just test & write code. So she never had time to learn
> bad practices because she just learned how to do it right.
>
> And prepared statements are precisely like that. How many other
> programming languages have such major problems with SQLi? Most do not.
> Don't get me wrong, it exists in other languages (most definitely).
> But Parameterized Queries are a big focus in other languages.
>
> Our beginner tutorials all teach concatenation. Then escaping. Then
> PS. You want to fix the problem, fix it with education. Tainting can
> be a safeguard, but it's not a solution.
>
> My $0.02
>
> Anthony
>