Python Security Issues with os.environ.get

Hi
I am using os.environ.get to pass Environment variables related to database connectivity to python Flask code, and facing below security related errors.

  • The application sends a request to a remote server, for some resource, using client . However, an attacker can control the target of the request, by sending a URL or other data in get.
  • The application’s Flask method receives untrusted, user-controlled data, and uses this data to connect to a database using client. This may enable a Connection String Injection attack.

Could you please suggest ways to overcome these violations.

By VJ via Discussions on Python.org at 24Jun2022 03:42:

I am using os.environ.get to pass Environment variables related to
database connectivity to python Flask code, and facing below security
related errors.

  • The application sends a request to a remote server, for some resource, using client . However, an attacker can control the target of the request, by sending a URL or other data in get.
  • The application’s Flask method receives untrusted,
    user-controlled data, and uses this data to connect to a database using
    client. This may enable a Connection String Injection attack.

The core issues are generally to:

  • know what data is untrusted, and not use it for things that require
    trust
  • correctly manage data; you should never be at risk of an injection
    attack regardless of the user supplied untrusted data, or indeed any
    “unfortunate” data because you should always handle it correctly

I think we need to see some example code and an little diagram
(possibly as prose) to undertand your setup, and why user supplied input
can dictate the application side database connection.

But that latter is just “good practice” stuff: always construct SQL
queries using parameters, always know what you’ve got eg some opaue user
supplied text etc. To make a trite concrete example:

result = dbconn.execute(
    'SELECT id, description FROM some_table WHERE value = ?',
    value_from_user_here)

should be a safe thing to do. This uses a parameterised query where ?
is a placeholder used to construct the actual query by the db
connection layer
. There is no injection risk because the db API knows
that there must be a query parameter at the ? and either correctly
embeds the value_from_user_here in the SQL query, suitably quoted or
otherwise delimited, OR rejects the query as something it cannot
handle. There’s no middle ground where the db API code mishandles
the user data to suffer an injection attack.

This scenario should play out wherever you handle user data (or other,
arbitrary data): provide/use the correct mechanisms to process the data
correctly. DB APIs do that for parameterised queries, and the same
applies in other domains.

For example, you seem to pass some user data through a URL-encoded query
string. That step, both assembling the string and at the receiving end
for decoding the string should be robust: the data should go in
unchanged and be received unchanged (after the decode from the
URL-encoded part).

So suppose your user maybe searches for the text:

Robert'); DROP TABLE Students; --

as per the standard injection attack example: xkcd: Exploits of a Mom

That should be safe:

  • correctly URL-encode the string if you’re stuffing into a URL
  • correctly decode the string at the receiving end
  • correctly pass the string to some SQL query as a parameter, which
    means the DB API also correctly handles the string

All the way along, it is just a string. It may contain anything, but
that doesn’t matter because nothing treats it as anything with extra
meaning.

The core of the injection attack and similar problems is that something,
somewhere, does not treat is as just a string. In the SQL injection
scenario, something mishandles the string and thus treats it as SQL
code. The trivial case is when someone “constructs” SQL like this:

sql_code = "SELECT id, field1 FROM table WHERE field2='%s'" % user_supplied_string

or the equivalent using string concatenation or a format-string, etc.

Here, the code is not correctly managing the user_supplied_string
and is just stuffing it diretly into some generated code. So punctuation
in the user_supplied_string is treated as code punctuation, not just
as arbitrary text.

In fact, do this:

user_supplied_string = "Robert'); DROP TABLE Students; --"
sql_code = "SELECT id, field1 FROM table WHERE field2='%s'" % user_supplied_string
print("SQL CODE:", sql_code)

and see that, because the string has been mishandled, you not have
some SQL code which does something unintended.

Versus running the db query via the DB API:

result = dbconn.execute(
    'SELECT id, field1 FROM table WHERE field2=?'
    user_supplied_string)

where the API correctly handles the query parameter.

Note: some APIs use a %s for the paremeter placeholderr instead of
?: this does not mean that they are subject to injection attacks,
because internally they are not using a dumb insert-text-here
approach; they are still doing the correct thing, just using a different
marker in the query.

Cheers,
Cameron Simpson cs@cskk.id.au