
## Review A dedicated reviewer checked the rule description successfully for: - [ ] logical errors and incorrect information - [ ] information gaps and missing content - [ ] text style and tone - [ ] PR summary and labels follow [the guidelines](https://github.com/SonarSource/rspec/#to-modify-an-existing-rule)
87 lines
2.6 KiB
Plaintext
87 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 would
|
|
allow an attacker to manipulate the returned data and bypass authentication:
|
|
|
|
[source, text]
|
|
----
|
|
username=admin&password=size(password) or size(password)=size(password)
|
|
----
|
|
|
|
==== 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`.
|