接口安全设计

![在这里插入图片描述](https://img-
blog.csdnimg.cn/direct/984c14f0ceca4df7a801db1036f5b122.jpeg#pic_center)

接口安全设计

1、防伪装攻击(接口防刷)

设计初衷:不法分子伪装成正常用户,对接口进行超频访问 ,对应需要对接口设计防刷,即限制某段时间内访问次数。

q:服务器如何区分非正常用户?
a:对不同性质的用户不同处理,这里的性质就是“访问频率”,让服务器限制超频访问的用户持续调用

技术方案:

限制某段时间说明对应限制措施,或者说相关技术应该具备时效性;访问次数对应的计数就行,那对应的用户可能很多,我们需要不同对待用户,也就是每个用户都需要计数措施,相对应的这种数据不敏感但数据量又可能很大的话可以使用redis;
限制访问涉及技术就是filter过滤器和interceptor拦截器,对于springboot项目的话选择springmvc提供的interceptor拦截器即可。

q:决定使用redis的话,就需要考虑key的设计,以及value的类型选择?
a:解决接口防刷,涉及的角色有两个,用户和接口,对应的计数措施value就选择String类型即可。将关注点放回key的设计,我们相应的就是关联用户和接口并做到唯一性
,最简单的就是将用户标识和接口标识进行拼接设计为key即可。而其中用户标识就是ip地址(登录用户也可以),接口标识就是对应的接口访问路径URL,所以我们对应key设计就是:ip:url。

代码实现:

创建拦截器并配置

/**
 * 防刷拦截器
 */
public class BrushProofInterceptor implements HandlerInterceptor {
    @Autowired
    private ISecurityRedisService securityRedisService;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        if(!(handler instanceof HandlerMethod)){
            return  true;
        }

        //防刷验证
        String url = request.getRequestURI().substring(1);
        String ip = RequestUtil.getIPAddress();

        String key = RedisKeys.BRUSH_PROOF.join(url, ip);

        if(!securityRedisService.isAllowBrush(key)){  //超过十次,true,拦截
            response.setContentType("text/json;charset=UTF-8");
            response.getWriter().write(JSON.toJSONString(JsonResult.error(500, "请勿频繁访问","谢谢咯")));
            return false;
        }

        return true;
    }
}

redis业务层

@Service
public class SecurityRedisServiceImpl implements ISecurityRedisService {

    @Autowired
    private StringRedisTemplate template;


    @Override
    public boolean isAllowBrush(String key) {
        //redis setnx操作,如果存在对应key则不做任何操作,如果没有则添加,对应就是一分钟内限制访问十次
        template.opsForValue().setIfAbsent(key, "10", RedisKeys.BRUSH_PROOF.getTime(), TimeUnit.SECONDS);
        Long decrement = template.opsForValue().decrement(key);  //自减1,看个人判定
        return decrement >= 0;  //超过十次,也即计数10归0,返回true
    }
}

启动类中配置拦截器和拦截规则

@Bean
public BrushProofInterceptor brushProofInterceptor(){
    return  new BrushProofInterceptor();
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
    //防刷
    registry.addInterceptor(brushProofInterceptor())
        .addPathPatterns("/**");

}

注意:如果是针对某个或者部分请求进行拦截防刷的话,就对应自定义注解结合拦截器使用即可。

2、接口防篡改(参数篡改)

设计初衷:用户正常访问的请求,可能会被不法分子拦截,对应篡改参数后放行。例如,某用户在浏览器发起转账请求,不法分子通过拦截用户请求,然后将转账对象改成自己,钱就被不法分子收取了(当然现实中不是这么简单的拦截、篡改、放行就行了,这里仅举例说明)。

q:接口如何鉴别参数被篡改了?
a:拿到最初请求前的参数,与服务器接收到的参数做对比 ,通过某种判断依据判断参数是否被改变。

技术方案:

使用参数签名,所谓参数签名就是对请求参数的整体描述。

①客户端发起请求之前,将所有参数使用某种算法拼接成字符串,然后对应将字符串进行加密算法加密,得到一个参数签名(sign_client);

②客户端正式发起请求,将所有参数和整理得到的参数签名一并传到服务器;

③服务器获取所有参数包括参数签名,用相同的算法将参数拼接成字符串,再用相同的加密算法加密,得到另一个参签名(sign_server);

④判断两个参数签名是否一致,一致则放行,否则拦截。

代码实现:

前端js代码,封装参数签名,该方法是自定义ajaxGet请求中定义的,目的是将每个请求中的参数都同一使用参数签名

//数据防篡改
function getSignStr(param) {
    var sdic=Object.keys(param).sort();  //对请求参数排序
    var signStr = "";
    for(var i in sdic){  //自定义拼接字符串
        if(i == 0){
            signStr +=sdic[i]+"="+param[sdic[i]];
        }else{
            signStr +="&"+sdic[i]+"="+param[sdic[i]];
        }
    }

    console.log(hex_md5(signStr));  //使用md5加密
    return hex_md5(signStr).toUpperCase();  //转换成大写字母
}
创建拦截器

/**
 * 签名拦截(防篡改)
 */
public class SignInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(!(handler instanceof HandlerMethod)){   //放行如跨域类型、静态资源等请求
            return  true;
        }

        //签名验证
        Map<String, String[]> map = request.getParameterMap();  //使用String[]是因为一个参数的参数值可能不止一个
        Set<String> keys = map.keySet();
        Map<String, Object> param = new HashMap<>();
        for (String s : map.keySet()) {
            if("sign".equalsIgnoreCase(s)){
                continue;
            }
            param.put(s, arrayToString(map.get(s)));   //自定义将数组转成字符串的方法
        }
        String signatures = Md5Utils.signatures(param);  //自定义signatures拼接、加密成sign_client
        String sign = request.getParameter("sign");  //sign_server
        if(sign == null || !sign.equalsIgnoreCase(signatures)){
            response.setContentType("text/json;charset=UTF-8");
            response.getWriter().write(JSON.toJSONString(new JsonResult(501,"签名校验失败","不好意思咯")));
            return false;
        }
        return true;
    }
}

测试的话可以发起一次成功的AjaxGet请求,然后在地址栏将方法签名保存下来,然后更改任意参数值,看对应的请求是否被拦截

注意:
既然我们通过算法设计参数签名,因此对应的算法不能暴露出去。但是前端控制台中是可以找到对应的js文件,然后找到对应的js代码,算法一览无余。因此我们需要对js文件进行加密操作,可以使用js在线加密工具或者其他加密工具对整个js文件加密(该加密工具不能完全解密原js代码),注意不要部分加密,防止整个js无法运行。
演示中的设计方式不适用于文件上传操作,因为文件上传会转换成流,request.getParameterMap()方法是无法识别流的,因此文件上传需要区别处理,如果参数很多,特别是参数体积很大时(比如参数传了一篇文章内容),拼接字符串和加密过程非常麻烦,对应的出现的误差就很多,匹配参数签名的时候就不准确了。

3、接口时效性

设计初衷:一般是业务需求和安全起见,在约定时间内请求有效,超时无效。也即前端发起请求到后台接收请求的某个时间段内,放行用户访问,超时之后拦截请求。

使用场景:微信支付二维码、地铁乘车码等

实现技术:参数签名+有效时间

实现方案就是综合接口防刷和参数篡改方案,使用redis计时拦截器拦截 ,参数签名是防止用户拦截请求篡改时间

技术方案:

①客户端发起请求之前,另外再添加设计一个时间参数,参数值就是当前时间(从前端开始发起请求的时间),将所有参数使用某种算法拼接成字符串,然后对应将字符串进行加密算法加密,得到一个参数签名(sign_client);

②客户端正式发起请求,将所有参数和整理得到的参数签名一并传到服务器;

③服务器获取所有参数包括参数签名,用相同的算法将参数拼接成字符串,再用相同的加密算法加密,得到另一个参签名(sign_server);

④判断两个参数签名是否一致,一致则放行,否则拦截;

⑤拿到时间参数,跟后端接收到时间(就是当前时间new Date()的结果),计算两个时间差,如果超过约定时间就拦截请求,否则放行。

4、接口加密(https协议)

所谓接口加密即对请求参数和重要资源标识符URI进行加密,一般我们不自行对参数、URI进行封装加密,而是使用https加密协议。

q:如何在项目中使用https?

a:①申请SSL证书,SSL证书需要向SSL证书颁发机构申请(交钱就行),申请需要提供相关资料(如公司名称、域名、ip信息等)。申请通过之后,机构会“颁发"SSL证书,该证书内容包含加密算法、公钥、秘钥等;

②jdk自带keytool,它可以在生成本地局域网使用的SSL证书,详见keytool生成证书,其证书就是一个tomcat.keystore文件;

③向阿里云申请SSL证书,性质跟SSL证书颁发机构差不多。

具体流程:

①将SSL证书配置到项目的服务器中(如springboot项目就配置到application.properties文件中);

②浏览器第一次发起请求,服务器接收到请求后,将证书副本(不具有原件的私钥)响应到服务器;

③浏览器接收证书副本后,对证书进行识别和认证(浏览器无法认证的证书对应会有警告图标),确认证书有效后,发起信任通道建立请求,服务器根据浏览器的各种请求,对请求接收并建立互信通道(就是建立TCP的三次握手过程);

④互信通道建立后,浏览器发起请求时,使用证书公钥对参数加密,然后携带到服务器,服务器接收参数使用私钥解密,响应数据给浏览器时同样使用私钥加密,浏览器接收数据后使用公钥进行解密,然后渲染数据到页面。(该过程就是对应的浏览器使用公钥加密/解密进行请求和接收响应,服务器使用私钥加密/解密进行接收请求和响应)。

5、接口文档

q:什么是接口文档

a:在项目开发汇总,web项目的前后端是分离开发的。应用程序的开发,需要由前后端工程师共同定义接口,编写接口文档,之后大家都根据这个接口文档进行开发,到项目结束前都要一直维护(如果不是一次性交付的项目后续还得一直维护)。

q:为什么使用接口文档

a:①项目开发过程中前后端工程师有一个统一的文件进行沟通交流开发;

②项目维护中或者项目人员更迭的时候,方便后期人员查看、维护;

③后端提供了接口、接口参数、接口描述,前端直接在接口文档中看到,给什么要什么则自己决定。

接口文档类型

第一代:最简单的纯文档类型

第二代:如showdoc官网在线文档(不仅仅是文档)

第三代:如swagger2官网在线文档(二代上的优化)

springboot整合swagger2接口文档

依赖

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

配置类配置

@Configuration
@EnableSwagger2
public class SwaggerConfig implements WebMvcConfigurer {

    @Bean
    public Docket productApi() {

        //添加head参数start
        ParameterBuilder tokenPar = new ParameterBuilder();
        List<Parameter> pars = new ArrayList<Parameter>();
        tokenPar.name("token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
        pars.add(tokenPar.build());

        return new Docket(DocumentationType.SWAGGER_2).select()
                // 扫描的包路径
                .apis(RequestHandlerSelectors.basePackage("cn.wolfcode.luowowo.controller"))
                // 定义要生成文档的Api的url路径规则
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(pars)
                // 设置swagger-ui.html页面上的一些元素信息。
                .apiInfo(metaData());
    }

    private ApiInfo metaData() {
        return new ApiInfoBuilder()
                // 标题
                .title("SpringBoot集成Swagger2")
                // 描述
                .description("骡窝窝项目接口文档")
                // 文档版本
                .version("1.0.0")
                .license("Apache License Version 2.0")
                .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0")
                .build();
    }

    //ui页面
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

访问

http://localhost:8080/swagger-ui.html(或者http://localhost:8080/doc.html)

Swagger常见注解

//@Api:用在类上,说明该类的作用
@Api(value = "用户资源",description = "用户资源控制器")

//@ApiOperation:用在方法上,说明方法的作用
@ApiOperation(value = "注册功能",notes = "其实就是新增用户")
//@ApiImplicitParams:用在方法上包含一组参数说明
//@ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面
//paramType:参数放在哪个地方
//header-->请求参数的获取
//query-->请求参数的获取
//path-->请求参数的获取(用于restful接口):
//body-->请求实体中

@ApiImplicitParams({
            @ApiImplicitParam(value = "昵称",name = "nickName",dataType = "String",required = true),
            @ApiImplicitParam(value = "邮箱",name = "email",dataType = "String",required = true),
            @ApiImplicitParam(value = "密码",name = "password",dataType = "String",required = true)
    })
//@ApiModel:描述一个Model的信息
//(这种一般用在post创建的时候,使用@RequestBody这样的场景,请求参数无法使用@ApiImplicitParam注解进行描述的时候)
//@ApiModelProperty:描述一个model的属性

@ApiModel(value="用户",description="平台注册用户模型")
@ApiModelProperty(value="昵称",name="nickName",dataType = "String",required = true)
//@ApiResponses:用于表示一组响应
/**@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息(200相应不写在这里面)
  code:数字,例如400
  message:信息,例如"请求参数没填好"
  response:抛出的异常类**/

@ApiResponses({
 @ApiResponse(code=200,message="用户注册成功")
})
//@ApiIgnore:贴在类上则将该接口对外隐藏

这是一个基于JeecgBoot(低代码平台)开发的web后台系统,其使用了Swagger2,这是后台的接口文档
![在这里插入图片描述](https://img-
blog.csdnimg.cn/direct/117bc1aa2d64416d93abfcf514242b52.png#pic_center)

最后

从时代发展的角度看,网络安全的知识是学不完的,而且以后要学的会更多,同学们要摆正心态,既然选择入门网络安全,就不能仅仅只是入门程度而已,能力越强机会才越多。

因为入门学习阶段知识点比较杂,所以我讲得比较笼统,大家如果有不懂的地方可以找我咨询,我保证知无不言言无不尽,需要相关资料也可以找我要,我的网盘里一大堆资料都在吃灰呢。

干货主要有:

①1000+CTF历届题库(主流和经典的应该都有了)

②CTF技术文档(最全中文版)

③项目源码(四五十个有趣且经典的练手项目及源码)

④ CTF大赛、web安全、渗透测试方面的视频(适合小白学习)

⑤ 网络安全学习路线图(告别不入流的学习)

⑥ CTF/渗透测试工具镜像文件大全

⑦ 2023密码学/隐身术/PWN技术手册大全

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

扫码领取

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Web接口安全设计文档 1. 身份认证: 对于所有的web接口请求,都需要进行身份认证。可以使用基于用户名/密码的身份验证或者更为安全的基于数字证书的身份验证。 2. 数据加密: 在传输过程中,所有的数据都应该被加密。可以使用HTTPS协议或者TLS来实现数据加密。 3. 接口访问控制: 对于每一个web接口,应该设置不同的访问级别。只有经过身份认证的用户才能访问特定的接口。 4. 审计日志: 应该对所有的web接口请求进行审计日志记录,以便在发生安全事件时进行追溯。 5. 防护攻击: 应该采取措施防范常见的攻击手段,如SQL注入、跨站脚本攻击等。 6. 合规性: 遵守相关的法律法规,如GDPR,HIPAA等。 7. 安全测试: 定期进行安全测试,发现并修复漏洞。 ### 回答2: Web接口安全设计文档是为了保障Web应用程序的接口系统在信息传输过程中的安全性而制定的指南。该文档包含以下几个方面的设计要点: 1. 身份验证与授权: 设计接口时,必须对用户进行身份验证,并为每个用户分配适当的授权级别。常用的身份验证方式包括用户名和密码、OAuth、Token等。同时,需要确保用户只能访问其授权范围内的接口。 2. 加密传输: 为了保证数据在传输过程中不被窃取或篡改,需要采用HTTPS协议进行数据的加密传输。通过使用SSL证书对数据进行加密,可有效防止恶意攻击者获取敏感数据。 3. 输入验证与过滤: 对于用户的输入数据,需要进行有效性验证和过滤,以防止SQL注入、XSS攻击等常见的安全威胁。可使用正则表达式、白名单过滤等方式来验证输入数据的合法性。 4. 安全漏洞扫描与漏洞修复: 定期进行安全漏洞扫描,包括常见的漏洞如跨站脚本、跨站请求伪造等。对于发现的漏洞,要及时修复,并进行相应的补丁升级。 5. 日志和监控: 记录接口的访问日志,包括用户的操作、请求参数、返回结果等,以便追溯和分析异常情况。同时,设置监控系统,实时监控接口的运行状态,及时发现并解决潜在的安全问题。 6. 接口关联限制: 对于敏感接口,应设置相关限制,包括接口调用频率限制、黑名单/白名单控制等。通过限制接口的调用次数和访问权限,可以有效防止恶意攻击和滥用接口。 7. 代码审计与防护机制: 进行代码审计,确保接口系统代码的安全性,避免可能的漏洞和错误。同时,采用防御性编程,使用安全的编程方法和框架,加强对各种攻击的防护能力。 通过以上安全设计要点的考虑和实施,可以提高Web接口安全性,保护用户的数据和隐私,减少潜在的安全风险。在设计过程中,还应根据具体业务需求和安全风险评估,制定相应的安全策略和应急预案,确保接口系统的稳定和安全运行。 ### 回答3: Web 接口安全设计文档是为了保护 Web 应用程序的接口免受恶意攻击和未授权访问。以下是一个简单的Web接口安全设计文档: 1. 使用 HTTPS:必须使用HTTPS协议来保障数据在传输过程中的安全性。使用有效的证书来确保HTTPS连接的真实性和完整性。 2. 身份验证和授权:实施适当的身份验证和授权机制,确保只有经过身份验证和授权的用户才能访问受限资源。可以使用令牌(token)或基于角色的访问控制(RBAC)来管理用户权限。 3. 防御 CSRF 攻击:使用 CSRF 令牌验证来防止 CSRF 攻击。通过在每个用户请求中包含与用户会话相关的令牌,确保请求的合法性和完整性。 4. 输入验证:对所有传入的数据进行严格的输入验证,以防止 SQL 注入、跨站脚本(XSS)和其他常见的输入验证攻击。 5. 限制访问频率和速率:确保接口只允许合理频率和速率的请求。这可以通过限制每个用户的请求速率、设置访问频率限制或使用令牌桶算法进行实现。 6. 记录和审计:实施完整的日志记录和审计跟踪。记录所有访问请求、错误日志和异常事件,并监控和分析这些日志以及审计日志以及其他异常行为。 7. API 版本控制:使用 API 版本控制来控制和管理接口的演进。确保向后兼容性,并提供合适的通知和过渡策略。 8. 安全扫描和漏洞管理:定期进行安全扫描,使用工具来检测和修复应用程序的漏洞,并及时更新和升级依赖项。 9. 安全培训和意识:培训开发人员和其他相关人员关于最佳安全实践、常见的安全威胁和攻击,并提高他们的安全意识。 10. 紧急响应计划:建立一个紧急响应计划,包括用于检测和应对安全事件或潜在漏洞的过程和策略。 以上是一个简单的Web接口安全设计文档的示例,具体的安全措施和实施细节应根据具体应用程序的需求和环境来进行定制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值