Serverless.com 安全

Tip

学习并练习 AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

基本信息

组织

一个 组织 是 Serverless Framework 生态系统中的最高级别实体。它代表一个 集体团体,例如公司、部门或任何大型实体,涵盖多个项目、团队和应用程序。

团队

团队 是在组织内有访问权限的用户。团队根据角色帮助组织成员。合作者 可以查看和部署现有应用,而 管理员 可以创建新应用并管理组织设置。

应用

一个 应用 是组织内相关服务的逻辑分组。它代表一个完整的应用程序,由多个无服务器服务组成,这些服务协同工作以提供一致的功能。

服务

一个 服务 是无服务器应用程序的核心组件。它代表您的整个无服务器项目,封装了所需的所有功能、配置和资源。它通常在 serverless.yml 文件中定义,服务包括元数据,如服务名称、提供者配置、功能、事件、资源、插件和自定义变量。

service: my-service
provider:
name: aws
runtime: nodejs14.x
functions:
hello:
handler: handler.hello
功能

一个 Function 代表一个单一的无服务器函数,例如 AWS Lambda 函数。它包含在响应事件时执行的代码。

它在 serverless.ymlfunctions 部分下定义,指定处理程序、运行时、事件、环境变量和其他设置。

functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
事件

事件 是触发您无服务器函数的触发器。它们定义了函数应该如何和何时执行。

常见的事件类型包括 HTTP 请求、计划事件(定时任务)、数据库事件、文件上传等。

functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
- schedule:
rate: rate(10 minutes)
资源

资源 允许您定义您的服务所依赖的额外云资源,例如数据库、存储桶或 IAM 角色。

它们在 resources 部分下指定,通常使用 AWS 的 CloudFormation 语法。

resources:
Resources:
MyDynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: my-table
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
提供者

Provider 对象指定云服务提供商(例如,AWS、Azure、Google Cloud),并包含与该提供商相关的配置设置。

它包括运行时、区域、阶段和凭据等详细信息。

yamlCopy codeprovider:
name: aws
runtime: nodejs14.x
region: us-east-1
stage: dev
阶段和区域

阶段代表不同的环境(例如,开发、预发布、生产),您的服务可以在这些环境中部署。它允许进行特定于环境的配置和部署。

provider:
stage: dev

区域指定了您的资源将要部署的地理区域。这对于延迟、合规性和可用性考虑非常重要。

provider:
region: us-west-2
插件

插件 通过添加新功能或与其他工具和服务集成来扩展 Serverless Framework 的功能。它们在 plugins 部分定义,并通过 npm 安装。

plugins:
- serverless-offline
- serverless-webpack

允许您将共享代码或依赖项与您的函数分开打包和管理。这促进了可重用性并减少了部署包的大小。它们在 layers 部分定义,并由函数引用。

layers:
commonLibs:
path: layer-common
functions:
hello:
handler: handler.hello
layers:
- { Ref: CommonLibsLambdaLayer }
变量和自定义变量

变量 通过允许使用在部署时解析的占位符来实现动态配置。

  • 语法: ${variable} 语法可以引用环境变量、文件内容或其他配置参数。
functions:
hello:
handler: handler.hello
environment:
TABLE_NAME: ${self:custom.tableName}
  • 自定义变量: custom 部分用于定义用户特定的变量和配置,这些变量和配置可以在 serverless.yml 中重复使用。
custom:
tableName: my-dynamodb-table
stage: ${opt:stage, 'dev'}
输出

输出 定义在服务部署后返回的值,例如资源 ARN、端点或其他有用信息。它们在 outputs 部分中指定,通常用于向其他服务公开信息或在部署后方便访问。

¡outputs:
ApiEndpoint:
Description: "API Gateway endpoint URL"
Value:
Fn::Join:
- ""
- - "https://"
- Ref: ApiGatewayRestApi
- ".execute-api."
- Ref: AWS::Region
- ".amazonaws.com/"
- Ref: AWS::Stage
IAM角色和权限

IAM角色和权限 定义了您函数和其他资源的安全凭证和访问权限。它们在 provider 或单个函数设置下进行管理,以指定必要的权限。

provider:
[...]
iam:
role:
statements:
- Effect: 'Allow'
Action:
- 'dynamodb:PutItem'
- 'dynamodb:Get*'
- 'dynamodb:Scan*'
- 'dynamodb:UpdateItem'
- 'dynamodb:DeleteItem'
Resource: arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:service}-customerTable-${sls:stage}
环境变量

变量 允许您将配置设置和秘密传递给您的函数,而无需将它们硬编码。它们在提供者或单个函数的 environment 部分下定义。

provider:
environment:
STAGE: ${self:provider.stage}
functions:
hello:
handler: handler.hello
environment:
TABLE_NAME: ${self:custom.tableName}
依赖项

依赖项 管理您的函数所需的外部库和模块。它们通常通过像 npm 或 pip 这样的包管理器处理,并使用 serverless-webpack 等工具或插件与您的部署包捆绑在一起。

plugins:
- serverless-webpack
Hooks

Hooks 允许您在部署生命周期的特定时刻运行自定义脚本或命令。它们通过插件或在 serverless.yml 中定义,以在部署之前或之后执行操作。

custom:
hooks:
before:deploy:deploy: echo "Starting deployment..."

教程

这是官方教程的摘要 来自文档:

  1. 创建一个 AWS 账户 (Serverless.com 在 AWS 基础设施上启动)
  2. 在 serverless.com 创建一个账户
  3. 创建一个应用:
# Create temp folder for the tutorial
mkdir /tmp/serverless-tutorial
cd /tmp/serverless-tutorial

# Install Serverless cli
npm install -g serverless

# Generate template
serverless #Choose first one (AWS / Node.js / HTTP API)
## Indicate a name like "Tutorial"
## Login/Register
## Create A New App
## Indicate a name like "tutorialapp)

这应该创建一个名为 apptutorialapp,您可以在 serverless.com 中检查,并创建一个名为 Tutorial 的文件夹,其中包含文件 handler.js,该文件包含一些 JS 代码和 helloworld 代码,以及文件 serverless.yml 声明该函数:

exports.hello = async (event) => {
return {
statusCode: 200,
body: JSON.stringify({
message: "Go Serverless v4! Your function executed successfully!",
}),
}
}
  1. 创建一个 AWS 提供者,进入 dashboardhttps://app.serverless.com/<org name>/settings/providers?providerId=new&provider=aws
  2. 为了给 serverless.com 访问 AWS 的权限,它会要求运行一个 cloudformation stack,使用这个配置文件(在撰写本文时): https://serverless-framework-template.s3.amazonaws.com/roleTemplate.yml
  3. 这个模板生成一个名为 SFRole-<ID> 的角色,具有 arn:aws:iam::aws:policy/AdministratorAccess 的权限,允许 Serverless.com AWS 账户访问该角色。
Yaml roleTemplate ```yaml Description: This stack creates an IAM role that can be used by Serverless Framework for use in deployments. Resources: SFRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: AWS: arn:aws:iam::486128539022:root Action: - sts:AssumeRole Condition: StringEquals: sts:ExternalId: !Sub "ServerlessFramework-${OrgUid}" Path: / RoleName: !Ref RoleName ManagedPolicyArns: - arn:aws:iam::aws:policy/AdministratorAccess ReporterFunction: Type: Custom::ServerlessFrameworkReporter Properties: ServiceToken: "arn:aws:lambda:us-east-1:486128539022:function:sp-providers-stack-reporter-custom-resource-prod-tmen2ec" OrgUid: !Ref OrgUid RoleArn: !GetAtt SFRole.Arn Alias: !Ref Alias Outputs: SFRoleArn: Description: "ARN for the IAM Role used by Serverless Framework" Value: !GetAtt SFRole.Arn Parameters: OrgUid: Description: Serverless Framework Org Uid Type: String Alias: Description: Serverless Framework Provider Alias Type: String RoleName: Description: Serverless Framework Role Name Type: String ```
信任关系 ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::486128539022:root" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "ServerlessFramework-7bf7ddef-e1bf-43eb-a111-4d43e0894ccb" } } } ] } ```
  1. 教程要求创建文件 createCustomer.js,该文件基本上会创建一个由新 JS 文件处理的新 API 端点,并要求修改 serverless.yml 文件以生成一个 新的 DynamoDB 表,定义一个 环境变量,以及将使用生成的 lambdas 的角色。
"use strict"
const AWS = require("aws-sdk")
module.exports.createCustomer = async (event) => {
const body = JSON.parse(Buffer.from(event.body, "base64").toString())
const dynamoDb = new AWS.DynamoDB.DocumentClient()
const putParams = {
TableName: process.env.DYNAMODB_CUSTOMER_TABLE,
Item: {
primary_key: body.name,
email: body.email,
},
}
await dynamoDb.put(putParams).promise()
return {
statusCode: 201,
}
}
  1. 部署它运行 serverless deploy
  2. 部署将通过 CloudFormation Stack 执行
  3. 请注意,lambdas 通过 API gateway 暴露,而不是通过直接 URL
  4. 测试它
  5. 上一步将打印出 URLs,您的 API 端点 lambda 函数已部署在这些地址

Serverless.com 的安全审查

错误配置的 IAM 角色和权限

过于宽松的 IAM 角色可能会授予对云资源的未经授权访问,从而导致数据泄露或资源操控。

当没有为 Lambda 函数指定权限时,将创建一个仅具有生成日志权限的角色,如:

最低 lambda 权限 ```json { "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogStream", "logs:CreateLogGroup", "logs:TagResource" ], "Resource": [ "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/jito-cranker-scripts-dev*:*" ], "Effect": "Allow" }, { "Action": ["logs:PutLogEvents"], "Resource": [ "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/jito-cranker-scripts-dev*:*:*" ], "Effect": "Allow" } ] } ```

缓解策略

  • 最小权限原则: 仅为每个函数分配必要的权限。
provider:
[...]
iam:
role:
statements:
- Effect: 'Allow'
Action:
- 'dynamodb:PutItem'
- 'dynamodb:Get*'
- 'dynamodb:Scan*'
- 'dynamodb:UpdateItem'
- 'dynamodb:DeleteItem'
Resource: arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:service}-customerTable-${sls:stage}
  • 使用单独的角色: 根据函数需求区分角色。

不安全的秘密和配置管理

将敏感信息(例如,API 密钥、数据库凭据)直接存储在 serverless.yml 或代码中,如果存储库被泄露,可能会导致暴露。

在撰写本文时,推荐的在 serverless.yml 文件中存储环境变量的方法是使用 ssms3 提供程序,这允许在部署时从这些来源获取 环境值配置 lambdas 的环境变量,文本中不包含值

Caution

因此,任何有权限读取 AWS 中 lambdas 配置的人都将能够 以明文访问所有这些环境变量!

例如,以下示例将使用 SSM 获取环境变量:

provider:
environment:
DB_PASSWORD: ${ssm:/aws/reference/secretsmanager/my-db-password~true}

即使这可以防止在 serverless.yml 文件中硬编码环境变量值,但该值将在部署时获取,并将以明文形式添加到 lambda 环境变量中

Tip

使用 serveless.com 存储环境变量的推荐方法是将其存储在 AWS 秘密中,并仅在环境变量中存储秘密名称,lambda 代码应收集它

缓解策略

  • Secrets Manager 集成: 使用像 AWS Secrets Manager 这样的服务。
  • 加密变量: 利用 Serverless Framework 的加密功能来保护敏感数据。
  • 访问控制: 根据角色限制对秘密的访问。

脆弱的代码和依赖项

过时或不安全的依赖项可能引入漏洞,而不当的输入处理可能导致代码注入攻击。

缓解策略

  • 依赖管理: 定期更新依赖项并扫描漏洞。
plugins:
- serverless-webpack
- serverless-plugin-snyk
  • 输入验证: 实施严格的验证和清理所有输入。
  • 代码审查: 进行全面审查以识别安全缺陷。
  • 静态分析: 使用工具检测代码库中的漏洞。

日志和监控不足

没有适当的日志记录和监控,恶意活动可能会被忽视,从而延迟事件响应。

缓解策略

  • 集中日志记录: 使用像 AWS CloudWatchDatadog 这样的服务聚合日志。
plugins:
- serverless-plugin-datadog
  • 启用详细日志记录: 捕获重要信息而不暴露敏感数据。
  • 设置警报: 配置可疑活动或异常的警报。
  • 定期监控: 持续监控日志和指标以发现潜在的安全事件。

不安全的 API 网关配置

开放或不当保护的 API 可能被利用进行未经授权的访问、拒绝服务 (DoS) 攻击或跨站攻击。

缓解策略

  • 身份验证和授权: 实施强大的机制,如 OAuth、API 密钥或 JWT。
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
authorizer: aws_iam
  • 速率限制和节流: 通过限制请求速率来防止滥用。
provider:
apiGateway:
throttle:
burstLimit: 200
rateLimit: 100
  • 安全的 CORS 配置: 限制允许的来源、方法和头部。
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
cors:
origin: https://yourdomain.com
headers:
- Content-Type
  • 使用 Web 应用防火墙 (WAF): 过滤和监控 HTTP 请求以检测恶意模式。

功能隔离不足

共享资源和不充分的隔离可能导致权限提升或函数之间的意外交互。

缓解策略

  • 隔离函数: 分配独特的资源和 IAM 角色以确保独立操作。
  • 资源分区: 为不同的函数使用单独的数据库或存储桶。
  • 使用 VPC: 在虚拟私有云中部署函数以增强网络隔离。
provider:
vpc:
securityGroupIds:
- sg-xxxxxxxx
subnetIds:
- subnet-xxxxxx
  • 限制函数权限: 确保函数无法访问或干扰彼此的资源,除非明确需要。

数据保护不足

静态或传输中的未加密数据可能会被暴露,导致数据泄露或篡改。

缓解策略

  • 加密静态数据: 利用云服务的加密功能。
resources:
Resources:
MyDynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
SSESpecification:
SSEEnabled: true
  • 加密传输中的数据: 对所有数据传输使用 HTTPS/TLS。
  • 安全的 API 通信: 强制执行加密协议并验证证书。
  • 安全管理加密密钥: 使用托管密钥服务并定期轮换密钥。

缺乏适当的错误处理

详细的错误消息可能泄露有关基础设施或代码库的敏感信息,而未处理的异常可能导致应用程序崩溃。

缓解策略

  • 通用错误消息: 避免在错误响应中暴露内部细节。
javascriptCopy code// Example in Node.js
exports.hello = async (event) => {
try {
// Function logic
} catch (error) {
console.error(error);
return {
statusCode: 500,
body: JSON.stringify({ message: 'Internal Server Error' }),
};
}
};
  • 集中错误处理: 在所有函数中一致地管理和清理错误。
  • 监控和记录错误: 跟踪和分析内部错误,而不向最终用户暴露细节。

不安全的部署实践

暴露的部署配置或对 CI/CD 管道的未经授权访问可能导致恶意代码部署或配置错误。

缓解策略

  • 安全的 CI/CD 管道: 实施严格的访问控制、多因素身份验证 (MFA) 和定期审计。
  • 安全存储配置: 确保部署文件不包含硬编码的秘密和敏感数据。
  • 使用基础设施即代码 (IaC) 安全工具: 使用 CheckovTerraform Sentinel 等工具来强制执行安全策略。
  • 不可变部署: 通过采用不可变基础设施实践,防止部署后未经授权的更改。

插件和扩展中的漏洞

使用未经审查或恶意的第三方插件可能会将漏洞引入您的无服务器应用程序。

缓解策略

  • 彻底审查插件: 在集成之前评估插件的安全性,优先选择来自信誉良好的来源的插件。
  • 限制插件使用: 仅使用必要的插件以最小化攻击面。
  • 监控插件更新: 保持插件更新,以便受益于安全补丁。
  • 隔离插件环境: 在隔离环境中运行插件,以限制潜在的妥协。

敏感端点的暴露

公开可访问的函数或不受限制的 API 可能被利用进行未经授权的操作。

缓解策略

  • 限制函数访问: 使用 VPC、安全组和防火墙规则限制对受信任来源的访问。
  • 实施强大的身份验证: 确保所有公开的端点都需要适当的身份验证和授权。
  • 安全使用 API 网关: 配置 API 网关以强制执行安全策略,包括输入验证和速率限制。
  • 禁用未使用的端点: 定期审查并禁用任何不再使用的端点。

团队成员和外部合作者的权限过大

向团队成员和外部合作者授予过多权限可能导致未经授权的访问、数据泄露和资源滥用。在多个个人具有不同级别访问权限的环境中,这种风险会加大,增加攻击面和内部威胁的潜力。

缓解策略

  • 最小权限原则: 确保团队成员和合作者仅拥有执行其任务所需的权限。

访问密钥和许可证密钥安全

访问密钥许可证密钥是用于验证和授权与 Serverless Framework CLI 交互的关键凭据。

  • 许可证密钥: 它们是用于验证对 Serverless Framework 版本 4 的访问的唯一标识符,允许通过 CLI 登录。
  • 访问密钥: 允许 Serverless Framework CLI 与 Serverless Framework Dashboard 进行身份验证的凭据。当使用 serverless cli 登录时,将生成并存储在笔记本电脑中的访问密钥。您还可以将其设置为名为 SERVERLESS_ACCESS_KEY 的环境变量。

安全风险

  1. 通过代码库暴露:
  • 硬编码或意外提交访问密钥和许可证密钥到版本控制系统可能导致未经授权的访问。
  1. 不安全的存储:
  • 在环境变量或配置文件中以明文存储密钥而没有适当的加密,增加了泄露的可能性。
  1. 不当分发:
  • 通过不安全的渠道(例如电子邮件、聊天)共享密钥可能导致被恶意行为者拦截。
  1. 缺乏轮换:
  • 不定期轮换密钥会延长密钥被泄露的暴露期。
  1. 权限过大:
  • 拥有广泛权限的密钥可能被利用在多个资源上执行未经授权的操作。

Tip

学习并练习 AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks