
Inline adoc files when they are included exactly once. Also fix language tags because this inlining gives us better information on what language the code is written in.
83 lines
2.6 KiB
Plaintext
83 lines
2.6 KiB
Plaintext
== How to fix it in Amazon DynamoDB
|
|
|
|
=== Code examples
|
|
|
|
The following code is vulnerable to NoSQL injection because untrusted data is
|
|
concatenated to the `FilterExpression` value. This expression determines which items within
|
|
the results should be returned.
|
|
|
|
A malicious HTTP request containing the following
|
|
query parameter values `username=admin&password=size(password) or
|
|
size(password)=size(password)` would allow an attacker to manipulate the returned data and bypass authentication.
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,python,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
@app.route('/login')
|
|
def login():
|
|
dynamodb = AWS_SESSION.client('dynamodb')
|
|
|
|
username = request.args["username"]
|
|
password = request.args["password"]
|
|
|
|
dynamodb.scan(
|
|
FilterExpression= "username = " + username + " and password = " + password, # Noncompliant
|
|
TableName="users",
|
|
ProjectionExpression="username"
|
|
)
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,python,diff-id=1,diff-type=compliant]
|
|
----
|
|
@app.route('/login')
|
|
def login():
|
|
dynamodb = AWS_SESSION.client('dynamodb')
|
|
|
|
username = request.args["username"]
|
|
password = request.args["password"]
|
|
|
|
dynamodb.query(
|
|
KeyConditionExpression= "username = :u",
|
|
FilterExpression= "password = :p",
|
|
ExpressionAttributeValues={
|
|
":u": { 'S': username },
|
|
":p": { 'S': password }
|
|
},
|
|
TableName="users",
|
|
ProjectionExpression="username"
|
|
)
|
|
----
|
|
|
|
=== How does this work?
|
|
|
|
As a rule of thumb, the approach to protect against injection vulnerabilities
|
|
is to ensure that untrusted data cannot break out of the initially intended
|
|
logic.
|
|
|
|
When using DynamoDB with Boto3, the best way to do so is by using expression
|
|
attributes as placeholders (`:placeholder`). It will end up replacing the attribute with
|
|
the value defined in `ExpressionAttributeValues` and prevent any alteration of the
|
|
original query logic. The compliant code example uses such an approach.
|
|
|
|
When possible, use the method `query` over `scan` as it disallows the `OR`
|
|
operator on the `KeyConditionExpression` attribute and therefore reduces the attack
|
|
surface. It also optimizes speed and costs.
|
|
|
|
This logic applies both when using the `DynamoDB.Client` and the `DynamoDB.Table` class, though
|
|
the syntax differs for the latter, and the `ExpressionAttributeValues` would look
|
|
like the following:
|
|
|
|
[source,python]
|
|
----
|
|
ExpressionAttributeValues={
|
|
":u": username,
|
|
":p": password
|
|
}
|
|
----
|
|
|
|
Although injection can occur on all the query or scan `Expression` attributes,
|
|
its most severe impact occurs in the `FilterExpression`.
|