背景
互联网和计算机系统的广泛应用,伴随着日益增长的网络威胁和安全漏洞。随着技术的不断发展和攻击技术的进步,接口安全性测试和健壮性测试在现代软件开发中越来越重要,通过进行安全测试和健壮性测试,开发团队可以发现并修复潜在的问题,提高系统的整体质量和可靠性,从而为用户提供更安全、更稳定的软件产品。云和大数据部为推进相关工作制定了 《开发运维原则》,基于此,云测试在接口测试中进行实践。
接口安全性测试
接口安全测试是指对软件系统中不同组件之间的通信接口进行安全性评估的过程。通过模拟各种恶意攻击,测试接口在面对潜在威胁时的反应,确保其不会因攻击而泄露敏感信息、导致服务中断或被操控。通过了解常见安全漏洞、掌握测试方法,可以有效地发现和修复接口中的安全问题。
常见的接口安全漏洞类型及接口测试实践
信息泄露
参数溢出:攻击者在参数中输入超长字符串,导致数据溢出,致使应用或者数据库报错引发相关信息泄露,或者引起拒绝服务攻击等问题。
涉及接口:任意需要前端输入字段的接口,比如登录、搜索、新增、修改等。
测试方法:针对接口字段定义类型构造不同的异常数据请求接口,接口响应预期的错误码,不返回internal error、MySQL error等错误。例如:
字符型:请求超长字符串、emoji、特殊符号和""等;
数值型:请求超过定义范围最大最小值校验;
枚举型:请求非枚举值。
测试脚本示例:
Step(
xxx("【操作】调用 xxx 接口修改食物名称长度超过 50 字符的限制,返回错误码")
.with_variables(**{
"food_name": get_random_str(51),
"return_code": shared_error_codes.illegal_argument
})
),
预期结果:接口返回预期错误码,不泄露内部信息。
预期示例:
业务逻辑漏洞
1.业务流程跳跃:业务逻辑流程分步骤进行且能越过中间校验步骤直接进行后续操作,导致中间校验等步骤失效。
涉及接口:完成一个业务场景需要调用2个以上接口,比如重置密码,商城下单等。
测试方法:跳过前置或中间接口,直接调用后面的接口,接口响应预期的错误码且业务不生效。
测试脚本示例:
Step(
# 用户需要先认证邮箱,之后才能修改密码
xxx(
"【断言】未认证邮箱的用户调用 xxx 接口修改密码,返回错误码",
).with_variables(
**{
"email": "$email",
"return_code": send_verify_email_code_error_code.email_not_verified,
}
)
),
预期结果:接口返回预期错误码,业务操作未生效。
预期示例:
2.重放攻击:能重复发送数据包,且能有效地改变结果。
涉及接口:一次性操作的接口,例如:审批、点赞和投票等。
测试方法:多次调用该接口,接口正常响应但业务不生效。
测试脚本示例:
Step(
xxx("【操作】同一个用户调用 xxx 接口多次点赞菜谱")
.parametrize("no_return", [1, 2])
.with_variables(
**{
"recipe_like_status": True,
}
)
),
Step(
xxx("【断言】调用 xxx 接口返回点赞个数增加 1")
.validate()
.assert_json_contains(
"body.result.recipeList[0]",
{
"recipeLikeCount": "${pyexp(recipe_like_count + 1)}",
},
)
),
预期结果:接口正常响应,但点赞数量未重复增加。
预期示例:
3.未授权访问测试:未授权访问指需要安全配置或权限认证的地址、授权页面存在缺陷,导致其他用户可以直接访问,引发重要权限可被操作或敏感信息泄露。
涉及接口:需要用户登录后才能调用的接口,比如修改信息、查看个人信息等。
测试方法:使用其他用户token、错误的token、已经过期的token、或者不传token调用接口修改另外用户的数据,预期返回错误提示且操作不生效。
测试脚本示例:
Step(
xxx("【断言】其他用户调用 xxx 接口设置更换日期返回错误码")
.parametrize("user", ["$member", "$other"])
.with_variables(
**{
"return_code": shared_error_codes.no_permissions,
"countdown_days": 100,
}
)
),
预期结果:接口返回预期错误码,业务操作未生效。
预期示例:
防护功能失效
1.会话重用:用户退出系统后,服务器端Session未失效,攻击者可利用此Session向服务器继续发送服务请求。
涉及接口:使token失效的接口,比如登出、注销等。
测试方法:调用登出接口后,再使用登出前的token调用其他接口,预期返回错误码。
测试脚本示例:
Step(
xxx("【操作】第 5 个设备调用 xxx 接口登出").with_variables(**{"token": "$token5"})
),
Step(
xxx("【断言】设备 5 的 token 调用 xxx 接口返回错误码")
.setup_hook("${sleep(1)}")
.with_variables(
**{"token": "$token5", "return_code": shared_error_codes.token_expired}
)
),
预期结果:接口返回预期错误码,无法继续操作。
预期示例:
输入输出未过滤
1.SQL注入:所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。 造成SQL注入漏洞原因有两个:一个是没有对输入的数据进行过滤(过滤输入),还有一个是没有对发送到数据库的数据进行转义(转义输出)。
涉及接口:任意需要前端输入字段的接口,比如登录、搜索、新增、修改等。
测试方法:构造异常数据(如单引号、双引号、百分号等)请求接口,预期返回错误码。
测试脚本示例:
Step(
xxx("【操作】调用 xxx 接口设置房屋面积 xxx 输入异常数据,返回错误码")
.parametrize(
"house_square", ["'", '"', "')", "%", "1' OR '1'='1", ";--", "/*"]
)
.with_variables(**{"return_code": shared_error_codes.illegal_argument})
),
预期结果:接口返回预期错误码,不执行恶意SQL命令。
预期示例:
接口健壮性测试
接口健壮性测试是指在模拟各种极端条件和异常情况下,评估接口的稳定性和可靠性。其目的是确保接口在面对大数据量、高并发请求或其他不利因素时,仍能保持正常运行,不会出现崩溃、超时或错误响应。通过了解常见常见的接口健壮性开发原则、掌握测试方法,可以发现和修复接口在极端条件下的潜在问题。
常见的接口健壮性开发原则及接口测试实践
大数据量操作
原则:凡是涉及大数据量操作应该分批/分页操作,流式处理。
涉及接口:批量操作或长文本上传接口,例如批量新增、批量修改接口。
测试方法:选取大于边界值的测试数据调用接口,接口响应预期的错误提示,不返回internal error、MySQL error等错误;选取等于和小于边界值的数据调用接口,接口响应正常且再查询数据返回与上传一致。
测试总结:在实际测试中,我们会遇到很多大数据量的场景,比如设备上传数据时,接口未做限制,会导致接口调用失败或接口响应慢。接口测试重点关注接口是否合理设置分页的大小,既满足用户体验又避免过大的数据传输。
测试脚本示例:
Step(
xxx("【操作】调用 xxx 接口上传数据超过 100 条,返回错误码")
.with_variables(
jump_rope_record_list="${gen_upload_data_list($mac_id, 101)}"
)
.with_variables(return_code=shared_error_codes.illegal_argument)
),
预期结果:接口返回预期错误码,未成功上传超过限制的数据。
预期示例:
兼容性
原则:设计的时候,一般应做到前后版本兼容,降低发布难度,确保发布可回滚、可灰度、可复用(针对不同环境)等。
涉及接口:
1.有业务迭代造成数据结构变更的接口,比如数据从mySql迁移到MongoDB。
2.相同功能新开接口且新旧接口产生的数据有差异。
3.同一个接口迭代新增字段。
测试方法:
1.发版前造测试数据,发版后调用相关接口对测试数据增删改查响应正常。
2.调用旧接口造数据,然后调用新接口对测试数据增删改查响应正常。
3.分别覆盖迭代前和迭代后的接口调用逻辑。
测试总结:随着需求的迭代,系统版本也在不断的迭代,在迭代过程中app老版本还会一直存在使用老的调用方式,就会涉及到兼容问题。接口测试重点关注数据兼容、接口兼容。
测试脚本示例:
class TestAddRecipeWithOld(HttpRunner):
"""
1.使用旧的添加接口收藏菜谱,用新接口查询、取消正确
2.使用旧的接口添加、取消后,再使用新的接口添加正确
"""
config = Config("P-使用旧接口添加收藏的菜谱后,使用新接口查询正确").variables(
**{
"client": "${user.client}",
}
)
teststeps = [
Step(
xxx("【提取】调用 xxx 接口根据国家US查询菜谱")
.extract()
.with_jmespath("body.result.recipeList[*].recipeId", "recipe_id_list")
),
Step(
xxx("【操作】调用 xxx 接口收藏菜谱")
.with_variables(
**{
"recipe_id": "${recipe_id_list[0]}",
}
)
),
Step(
xxx("【断言】调用 xxx 接口菜谱板块页查询默认收藏夹")
.validate()
.assert_equal("body.result.recipeList[0].recipeId", "${recipe_id_list[0]}")
)
预期结果:新旧接口兼容,数据操作正常。
预期示例:
资源使用
原则:任何资源使用,都应该有限制(比如应用内缓存限制内存大小、上传文件要限制文件大小、服务端接口限制QPS、数据库客户端限制QPS、批量获取分页单页大小等)。
涉及接口:批量查询、文件上传和特殊限流的接口,比如发送验证码接口限制一段时间内的发送次数。
测试方法:选取大于边界值的测试数据调用接口,接口响应预期的错误码,不返回internal error、MySQL error等错误;选取等于和小于边界值的数据调用接口,接口响应正常。
测试总结:任何资源使用都需要合理的管理和调度,避免潜在的问题,提高资源的利用率。内存缓存限制内存大小、数据库客户端限制QPS需要专门的性能测试。接口测试重点关注数据查询、文件上传、特殊接口限流。
测试脚本示例:
Step(
xxx(
"【操作】调用 xxx 接口重复发送验证码返回错误码"
).with_variables(
**{
"email": "$email",
"return_code": shared_error_codes.requests_too_frequent,
}
)
),
预期结果:接口返回预期错误码,未成功重复发送验证码。
预期示例:
并发
原则:数据变更类接口,应该考虑并发问题,如前端按钮防重复提交,后端数据防止重复插入等。
涉及接口:
1.根据需求限制某些字段的唯一性的接口。
2.校验数据一致性的接口,例如兑换/抽奖类业务中兑换/抽奖次数是有限的,在并发场景中在即将超过次数的临界情况下可能会出现错误导致成功。
测试方法:
1.选取相同的数据重复调用接口,接口响应预期的错误提示或者无错误提示,再次查询无重复数据插入。
2.使用并发测试超过有限的兑换/抽奖次数,接口响应预期的错误提示且兑换/抽奖不成功。
测试总结:并发测试是一种软件测试方法,用于评估系统在多个并发用户或并发操作下的性能和稳定性,主要目的是检测系统在并发负载下的行为、性能瓶颈和潜在的并发问题,需要专门的并发测试。接口测试重点关注在网络异常或前端未做防重复提交校验时,重复数据会提交到后端,后端需要做校验避免出现错误,普通数据重复插入导致出现重复数据,影响用户体验,兑换/抽奖类业务在不满足条件情况下重复兑换/抽奖,造成公司损失。
测试脚本示例:
Step(
xxx("【操作】调用 xxx 接口创建食物与已存在的食物名称重复,返回错误码")
.parametrize("user_food", ["$user_food_1", "$user_food_4"])
.with_variables(**{
"commonly_user_food_list": ["$user_food"],
"return_code": iot_health_shared_error_codes.food_duplicated
})
),
预期结果:接口返回预期错误码,未成功插入重复数据。
预期示例:
总结
接口安全测试和健壮性测试是确保系统安全、稳定运行的重要环节。通过系统的测试方法和规范的测试脚本,可以有效发现并修复潜在的安全漏洞和性能问题,提升用户体验和系统可靠性。开发团队应重视接口测试,遵循最佳实践,持续优化测试流程,以应对日益复杂的网络威胁和业务需求。
在实际工作中我们应该:
多实践:通过实际项目进行测试,积累经验。
持续学习:关注最新的安全测试技术和工具。
团队合作:与开发团队紧密合作,共同提升系统安全性。