add a RemoteFlowSource for serverless handlers

This commit is contained in:
Erik Krogh Kristensen
2020-09-23 13:55:21 +02:00
parent 050ed97d9c
commit 1ed026fcce
14 changed files with 185 additions and 0 deletions

View File

@@ -94,6 +94,7 @@ import semmle.javascript.frameworks.PropertyProjection
import semmle.javascript.frameworks.React
import semmle.javascript.frameworks.ReactNative
import semmle.javascript.frameworks.Request
import semmle.javascript.frameworks.ServerLess
import semmle.javascript.frameworks.ShellJS
import semmle.javascript.frameworks.SystemCommandExecutors
import semmle.javascript.frameworks.SQL

View File

@@ -0,0 +1,91 @@
/**
* Provides classes and predicates for working with serverless handlers.
* E.g. AWS: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html
*/
import javascript
private import semmle.javascript.PackageExports as Exports
/**
* Provides classes and predicates for working with serverless handlers.
*/
private module ServerLess {
/**
* Holds if the `.yml` file `ymlFile` contains a serverless configuration with `handler` and `codeURI` properties.
* `codeURI` defaults to the empty string if no explicit value is set in the configuration.
*/
private predicate hasServerlessHandler(File ymlFile, string handler, string codeURI) {
exists(YAMLMapping resource | ymlFile = resource.getFile() |
// There exists at least "AWS::Serverless::Function" and "Aliyun::Serverless::Function"
resource.lookup("Type").(YAMLScalar).getValue().regexpMatch(".*::Serverless::Function") and
exists(YAMLMapping properties | properties = resource.lookup("Properties") |
handler = properties.lookup("Handler").(YAMLScalar).getValue() and
if exists(properties.lookup("CodeUri"))
then codeURI = properties.lookup("CodeUri").(YAMLScalar).getValue()
else codeURI = ""
)
)
}
/**
* Gets a string where an ending "/." is simplified to "/" (if it exists).
*/
bindingset[base]
private string removeTrailingDot(string base) {
if base.regexpMatch(".*/\\.")
then result = base.substring(0, base.length() - 1)
else result = base
}
/**
* Gets a string where a leading "./" is simplified to "" (if it exists).
*/
bindingset[base]
private string removeLeadingDotSlash(string base) {
if base.regexpMatch("\\./.*") then result = base.substring(2, base.length()) else result = base
}
/**
* Gets a path to a file from a `codeURI` property and a file name from a serverless configuration.
*/
bindingset[codeURI, file]
private string getPathFromHandlerProperties(string codeURI, string file) {
exists(string folder | folder = removeLeadingDotSlash(removeTrailingDot(codeURI)) |
if folder.regexpMatch(".*\\..+") then result = folder else result = folder + file + ".js"
)
}
/**
* Holds if `file` has a serverless handler function with name `func`.
*/
private predicate hasServerlessHandler(File file, string func) {
exists(File ymlFile, string handler, string codeURI, string fileName |
hasServerlessHandler(ymlFile, handler, codeURI) and
func = handler.regexpCapture(".*\\.(.*)", 1) and
fileName = handler.regexpCapture("([^.]+).*", 1)
|
file.getAbsolutePath() =
ymlFile.getParentContainer().getAbsolutePath() + "/" +
getPathFromHandlerProperties(codeURI, fileName)
)
}
/**
* Gets a function that is a serverless request handler.
*/
private DataFlow::FunctionNode getAServerlessHandler() {
exists(File file, string handler, Module mod | hasServerlessHandler(file, handler) |
mod.getFile() = file and
result = mod.getAnExportedValue(handler).getAFunctionValue()
)
}
/**
* A serverless request handler event, seen as a RemoteFlowSource.
*/
private class ServerlessHandlerEventAsRemoteFlow extends RemoteFlowSource {
ServerlessHandlerEventAsRemoteFlow() { this = getAServerlessHandler().getParameter(0) }
override string getSourceType() { result = "Serverless event" }
}
}

View File

@@ -0,0 +1,5 @@
| tst1/backend/src/mylibrary.js:1:36:1:40 | event |
| tst2/nodejs/index.js:1:36:1:40 | event |
| tst3/function/index.js:1:36:1:40 | event |
| tst4/app.js:1:36:1:40 | event |
| tst5/app.js:1:36:1:40 | event |

View File

@@ -0,0 +1,3 @@
import javascript
query RemoteFlowSource remoteFlow() { any() }

View File

@@ -0,0 +1,3 @@
module.exports.handler = function (event) {
console.log(event);
}

View File

@@ -0,0 +1,19 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: 'Serverless thing'
Globals:
Api:
Cors:
AllowMethods: "'*'"
AllowHeaders: "'*'"
AllowOrigin: "'*'"
Resources:
OrderManagerJsFunction:
Type: 'AWS::Serverless::Function'
Properties:
FunctionName: MY-SERVERLESS-THING
Handler: mylibrary.handler
Runtime: nodejs12.x
CodeUri: backend/src/

View File

@@ -0,0 +1,3 @@
module.exports.handler = function (event) {
console.log(event);
}

View File

@@ -0,0 +1,18 @@
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
fc-mongo:
Type: 'Aliyun::Serverless::Service'
Properties:
Description: MyServiceThing
nodejs:
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: index.handler
Runtime: nodejs10
CodeUri: nodejs/
python:
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: 'index.handler'
Runtime: python3
CodeUri: python/

View File

@@ -0,0 +1,3 @@
module.exports.handler = function (event) {
console.log(event);
}

View File

@@ -0,0 +1,10 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: An AWS Lambda application.
Resources:
function:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs12.x
CodeUri: function/.

View File

@@ -0,0 +1,3 @@
module.exports.handler = function (event) {
console.log(event);
}

View File

@@ -0,0 +1,12 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: A AWS Lambda function.
Resources:
helloworld:
Type: 'AWS::Serverless::Function'
Properties:
Handler: app.handler
Runtime: nodejs6.10
CodeUri: ./
Description: A AWS Lambda function.

View File

@@ -0,0 +1,3 @@
module.exports.handler = function (event) {
console.log(event);
}

View File

@@ -0,0 +1,11 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: A AWS Lambda function.
Resources:
helloworld:
Type: 'AWS::Serverless::Function'
Properties:
Handler: app.handler
Runtime: nodejs6.10
Description: A AWS Lambda function.