API架构合规验证

上传API的架构标准后,ESA将自动匹配符合该规范的已管理API,同时针对传入的请求进行合规验证并进行处理,保障业务API安全。

功能原理

当您的API已在ESA API管理中时,即可对已管理的API统一进行架构验证。

image
  1. 用户请求到达ESA节点后,会判断请求调用的是否为已管理API:

    • 若不是,则在该阶段放行,由其他功能设置进行处置;

    • 若是,则匹配对应API的架构规范。

  2. 根据架构规范判断请求是否合规:

    • 若不合规,则根据配置的执行动作进行处置,并记录不合规日志。

    • 若合规,则放行。

配置架构验证设置

在使用架构验证功能之前,需要完成架构规范上传,再打开功能生效开关。

  1. ESA控制台,选择站点管理,在站点列单击目标站点。

  2. 在左侧导航栏,选择安全防护 > API安全

  3. API安全页面,选择架构验证页签,单击架构验证设置image

  4. 在设置页面,单击上传架构,上传自定义的架构文件。image

  5. ESA会根据架构文件自动匹配对应的API,检查后单击确认image

  6. 架构上传后,可以配置针对不合规请求执行的默认动作,建议配置观察,并打开状态开关。image

  7. 返回架构验证页签,即可展示架构验证运行效果。image

分析不合规请求

配置完成架构验证后,ESA将持续对API请求进行检测。您可以在架构验证页签单击API列表菜单栏的image筛选按钮,选择对应的架构筛选出需要分析的架构,即可为您展示相应的API,并在不合规请求列中展示近24小时的不合规请求数。image

不合规请求可能由几个原因导致:

  • 客户端行为问题:客户端出现传参格式错误(如需JSON却传表单数据)、必填参数缺失、类型不匹配(字符串传布尔值)等问题时,可能导致不合规请求数增加。出现此类问题时,需要检查业务前端设计,增加错误检测机制、提交提醒等。

  • 异常攻击行为:当攻击者进行注入攻击、暴力破解等攻击行为时,可能导致不合规请求数增加。出现此类问题时,您的业务系统可能正在遭受攻击,建议您更改执行动作为拦截,并配置更严格WAF规则。

请求详情分析

为了分析定位不合规请求原因,可通过事件分析安全分析功能中的采样日志查看详情。

  1. 首先通过特征筛选出不合规请求异常的API。image

  2. 根据配置的执行动作来选择合适的日志功能:

    • 执行动作为无:由于该类请求没有触发安全执行动作,因此更适合使用安全分析进行分析。

    • 执行动作为观察/拦截:由于该类请求触发了安全执行动作,采集范围相对更集中,更适合使用事件分析

  3. 此处以事件分析为例,在左侧导航栏选择安全防护 > 事件分析

    若需要使用安全分析,则在左侧导航栏选择安全防护 > 安全分析
  4. 事件分析页面下滑至采样日志区域,筛选命中API安全的日志列,单击列前的image展开按钮查看详情,根据请求详情特征进行分析判断。同时您也可以结合实时日志对访问日志进行更详细的分析

更改执行动作

您可以为所有API统一配置默认的不合规请求执行动作,也可根据需求为特定API进行设置。

  • 修改全局默认执行动作:在架构验证页签单击默认执行动作栏的更改按钮,选择合适的动作即可:

    • 拦截:阻止不合规的请求,并记录拦截日志。

    • 观察:放行不合规的请求,并记录日志。

    • :不进行任何操作。

    image

  • 配置特定API执行动作:在架构验证页签的API列表单击对于API列右侧的更改执行动作,选择合适的动作即可。

    • 默认:使用全局默认执行动作。

    • 拦截:阻止不合规的请求,并记录拦截日志。

    • 观察:放行不合规的请求,并记录日志。

    • :不进行任何操作。

      image

分析无架构的API

当您成功上传架构文件后,符合架构的API将自动绑定对应的架构。您可以在架构验证页签单击无架构的API数量栏的筛选按钮进行筛选查看无架构的API列表。image

针对无架构的API,ESA无法进行不合规请求统计,因此针对这类API对业务可能并不安全。无架构的API可能来自:

  • 架构中遗漏:在上传的架构中遗漏了该类API。您可以核对列表中的API路径、主机记录、请求方案等信息特征,重新调整上传架构文件解决。

  • API不合规范:已发现的API不符合规范。在API开发过程中,出现不规范开发,需要重新对不合规API进行修改或重构,通常包含以下几类:

    • 路径不规范:API的路径有误,如正确的paths应为/users,错误时写为/user

    • HTTP方法误用:方法未遵循语义化原则,如用DELETE对应/users/delete/123的路径,错误时写为GET方法。

    • 状态码滥用:API响应状态码有误,如所有响应需返回200 OK,错误时在Body中写{ "responses": “500” }

    • 输入输出结构混乱:输入输出内容有误,如输入应包含email字段,但错写至输出中。

架构文件说明

类型和大小

架构验证文件仅支持 .yml.yaml.json 格式,最大上传大小为 58KB。如果上传架构文件过大,可以使用.json格式并且在本地进行压缩。

架构内容

版本

ESA API安全架构验证当前仅支持OAS v3.0.x版本。

字段

必选字段

  • openapi:API版本信息,如3.0.0

  • info:架构文件说明,如“version”:“1.0.0”

  • paths:至少包含一个API路径,如/api

  • servers:Host信息。支持以下子字段:

    • url:仅支持绝对URL,如https://api.example.com

    • variablesESA不支持服务器变量,解析时将忽略变量占位符。

可选字段

  • schema: 数据结构定义,支持以下类型:

    • int32

    • uint32

    • int64

    • uint64

    • float

    • double

    • boolean

    • email

  • reference:使用$ref指向预定义对象,不支持外部和相对引用。

  • requestbody:定义请求体,仅支持content-typeapplication/json 类型数据。

示例

.json 格式文件为例。
{
    "openapi": "3.0.0",
    "info": {
        "title": "example",
        "description": "example",
        "version": "1.0"
    },
    "servers": [
    {
      "url": "https://example1.aliyun.com",
      "description": "example1 url"
    },
    {
      "url": "https://example2.aliyun.com",
      "description": "example2 url"
    }
    ],
    "components": {
        "schemas": {
            "ParamsObject": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "value": {
                        "type": "string"
                    }
                },
                "required": [
                    "id",
                    "value"
                ]
            }
        }
    },
    "paths": {
        "/example/{param1}": {
            "get": {
                "operationId": "getexampleById",
                "parameters": [
                    {
                        "name": "param1",
                        "in": "path",
                        "required": true,
                        "description": "id",
                        "schema": {
                            "type": "integer",
                            "format": "int32"
                        }
                    }
                ]
            }
        },
        "/api1": {
            "post": {
                "operationId": "post_api1",
                "summary": "post api1 request",
                "parameters": [],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ParamsObject"
                            }
                        }
                    }
                }
            },
            "get" :{
                "operationId": "get_api1",
                "summary": "get api1 request",
                "parameters": [
                    {
                        "name": "id",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "format": "int32"
                        }
                    },
                    {
                        "name": "name",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        }
    }
}