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