Skip to content

Commit

Permalink
feat(python): add AWS dynamoDB NoSQLi rule (CWE-943)
Browse files Browse the repository at this point in the history
  • Loading branch information
elsapet committed May 23, 2024
1 parent 19abc63 commit 3ce20ef
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 0 deletions.
117 changes: 117 additions & 0 deletions rules/python/third_parties/aws_query_injection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
imports:
- python_shared_common_user_input
- python_shared_lang_import1
patterns:
- pattern: $<CALLER>.$<METHOD>($<...>FilterExpression=$<USER_INPUT>$<...>)
filters:
- variable: CALLER
detection: python_third_parties_aws_query_injection_dynamodb_caller
scope: result
- variable: METHOD
values:
- query
- scan
- variable: USER_INPUT
detection: python_third_parties_aws_query_injection_user_input
scope: result
# legacy
- pattern: $<CALLER>.query($<...>QueryFilter=$<USER_INPUT>$<...>)
filters:
- variable: CALLER
detection: python_third_parties_aws_query_injection_dynamodb_caller
scope: result
- variable: USER_INPUT
detection: python_third_parties_aws_query_injection_user_input
scope: result
- pattern: $<CALLER>.scan($<...>ScanFilter=$<USER_INPUT>$<...>)
filters:
- variable: CALLER
detection: python_third_parties_aws_query_injection_dynamodb_caller
scope: result
- variable: USER_INPUT
detection: python_third_parties_aws_query_injection_user_input
scope: result
auxiliary:
- id: python_third_parties_aws_query_injection_dynamodb_caller
patterns:
- pattern: $<DYNAMODB_INIT>.Table($<...>)
filters:
- variable: DYNAMODB_INIT
detection: python_third_parties_aws_query_injection_dynamodb_init
scope: result
- pattern: $<BOTO3_CLIENT>('dynamodb'$<...>)
filters:
- variable: BOTO3_CLIENT
detection: python_shared_lang_import1
scope: cursor
filters:
- variable: MODULE1
values: [boto3]
- variable: NAME
values: [client]
- id: python_third_parties_aws_query_injection_dynamodb_init
patterns:
- pattern: $<BOTO3_RESOURCE>('dynamodb'$<...>)
filters:
- variable: BOTO3_RESOURCE
detection: python_shared_lang_import1
scope: cursor
filters:
- variable: MODULE1
values: [boto3]
- variable: NAME
values: [resource]
- id: python_third_parties_aws_query_injection_user_input
sanitizer: python_third_parties_aws_query_injection_sanitizer
patterns:
- pattern: $<USER_INPUT>
filters:
- variable: USER_INPUT
detection: python_shared_common_user_input
scope: cursor
- id: python_third_parties_aws_query_injection_sanitizer
patterns:
- pattern: |
{ $<_>: $<!>$<_> }
languages:
- python
severity: critical
metadata:
description: Unsanitized user input in AWS query
remediation_message: |
## Description
Including unsanitized data, such as user input or request data, in raw queries makes your application vulnerable to injection attacks.
## Remediations
- **Do** always sanitize user input especially if it is to be used in database queries. Where possible, such sanitization should include the removal of special characters (like ' or ") that could be used to alter the semantics of a database query.
- **Do** validate user input wherever possible, to ensure it is the expected format and length
- **Do** use parameterized queries rather than concatenating user input directly into the query string. This separates query logic from user input, which is good practice, and also in the case of AWS SimpleDB, lets us take advantage of the internal parameterization and sanitization of `SelectRequest`.
!!! TODO UPDATE ME !!!
```java
// query logic
public static SelectResult executeQuery(String query, String itemName) {
AmazonSimpleDB simpleDBClient = AmazonSimpleDBClientBuilder.defaultClient();
SelectRequest selectRequest = new SelectRequest(query, true).withNextToken(itemName);
return simpleDBClient.select(selectRequest);
}
public static void selectItem(String itemName) { // itemName is dynamic and could be malicious
// parameterized query string
String query = "select * from items where itemName = ?";
SelectResult result = executeQuery(query, itemName);
...
}
```
## References
- [AWS SimpleDB docs](https://docs.aws.amazon.com/AmazonSimpleDB/latest/DeveloperGuide/Welcome.html)
cwe_id:
- 043
id: python_third_parties_aws_query_injection
documentation_url: https://docs.bearer.com/reference/rules/python_third_parties_aws_query_injection
20 changes: 20 additions & 0 deletions tests/python/third_parties/aws_query_injection/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const {
createNewInvoker,
getEnvironment,
} = require("../../../helper.js")
const { ruleId, ruleFile, testBase } = getEnvironment(__dirname)

describe(ruleId, () => {
const invoke = createNewInvoker(ruleId, ruleFile, testBase)

test("aws_query_injection", () => {
const testCase = "main.py"

const results = invoke(testCase)

expect(results).toEqual({
Missing: [],
Extra: []
})
})
})
41 changes: 41 additions & 0 deletions tests/python/third_parties/aws_query_injection/testdata/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import boto3

def bad(event, context):
dynamodb = boto3.resource('dynamodb', '')
users_table = dynamodb.Table('users')

# bearer:expected python_third_parties_aws_query_injection
users_table.query(
Select = 'ALL_ATTRIBUTES',
FilterExpression = event.body.filter
)

# bearer:expected python_third_parties_aws_query_injection
users_table.scan(
Select = 'ALL_ATTRIBUTES',
FilterExpression = event.body.filter
)

def bad2(event, context):
dynamodb = boto3.client('dynamodb')
# bearer:expected python_third_parties_aws_query_injection
dynamodb.query(
TableName='users',
FilterExpression = event.body.filter,
Select = "ALL_ATTRIBUTES"
)

def ok(event, context):
dynamodb = boto3.resource('dynamodb', '')
users_table = dynamodb.Table('users')
user_table.query(
Select = 'ALL_ATTRIBUTES',
FilterExpression = {'username': event.body.username},
)

dynamodb = boto3.client('dynamodb')
dynamodb.query(
TableName='users',
FilterExpression = {'username': event.body.username},
Select = "ALL_ATTRIBUTES"
)

0 comments on commit 3ce20ef

Please sign in to comment.