快试试用 API Key 来保护你的 SpringBoot 接口安全吧

目录

  • 1、概述

  • 2、REST API Security

  • 3、用API Keys保护REST API

  • 4. 测试

1、概述

安全性在REST API开发中扮演着重要的角色。一个不安全的REST API可以直接访问到后台系统中的敏感数据。因此,企业组织需要关注API安全性。

Spring Security 提供了各种机制来保护我们的 REST API。其中之一是 API 密钥。API 密钥是客户端在调用 API
调用时提供的令牌。

在本教程中,我们将讨论如何在Spring Security中实现基于API密钥的身份验证。

2、REST API Security

Spring Security可以用来保护REST API的安全性。REST API是无状态的,因此不应该使用会话或cookie。相反,应该使用Basic
authentication,API Keys,JWT或OAuth2-based tokens来确保其安全性。

2.1. Basic Authentication

Basic authentication是一种简单的认证方案。客户端发送HTTP请求,其中包含Authorization标头的值为Basic
base64_url编码的用户名:密码。Basic authentication仅在HTTPS / SSL等其他安全机制下才被认为是安全的。

2.2. OAuth2

OAuth2是REST API安全的行业标准。它是一种开放的认证和授权标准,允许资源所有者通过访问令牌将授权委托给客户端,以获得对私有数据的访问权限。

2.3. API Keys

一些REST
API使用API密钥进行身份验证。API密钥是一个标记,用于向API客户端标识API,而无需引用实际用户。标记可以作为查询字符串或在请求头中发送。

3、用API Keys保护REST API

3.1 添加Maven 依赖

让我们首先在我们的pom.xml中声明spring-boot-starter-security依赖关系:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
3.2 创建自定义过滤器(Filter)

实现思路是从请求头中获取API Key,然后使用我们的配置检查秘钥。在这种情况下,我们需要在Spring Security
配置类中添加一个自定义的Filter。

我们将从实现GenericFilterBean开始。GenericFilterBean是一个基于javax.servlet.Filter接口的简单Spring实现。

让我们创建AuthenticationFilter类:

public class AuthenticationFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
      throws IOException, ServletException {
        try {
            Authentication authentication = AuthenticationService.getAuthentication((HttpServletRequest) request);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (Exception exp) {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
            PrintWriter writer = httpResponse.getWriter();
            writer.print(exp.getMessage());
            writer.flush();
            writer.close();
        }

        filterChain.doFilter(request, response);
    }
}

我们只需要实现doFilter()方法,在这个方法中我们从请求头中获取API
Key,并将生成的Authentication对象设置到当前的SecurityContext实例中。

然后请求被传递给其余的过滤器处理,接着转发给DispatcherServlet最后到达我们的控制器。

在AuthenticationService类中,实现从Header中获取API Key并构造Authentication对象,代码如下:

public class AuthenticationService {
    private static final String AUTH_TOKEN_HEADER_NAME = "X-API-KEY";
    private static final String AUTH_TOKEN = "Baeldung";

    public static Authentication getAuthentication(HttpServletRequest request) {
        String apiKey = request.getHeader(AUTH_TOKEN_HEADER_NAME);

        if ((apiKey == null) || !apiKey.equals(AUTH_TOKEN)) {
            throw new BadCredentialsException("Invalid API Key");
        }

        return new ApiKeyAuthentication(apiKey, AuthorityUtils.NO_AUTHORITIES);
    }
}

在这里,我们检查请求头是否包含 API Key,如果为空 或者Key值不等于密钥,那么就抛出一个
BadCredentialsException。如果请求头包含 API
Key,并且验证通过,则将密钥添加到安全上下文中,然后调用下一个安全过滤器。getAuthentication 方法非常简单,我们只是比较 API Key
头部和密钥是否相等。

为了构建 Authentication 对象,我们必须使用 Spring Security 为了标准身份验证而构建对象时使用的相同方法。所以,需要扩展
AbstractAuthenticationToken 类并手动触发身份验证。

3.3. 扩展AbstractAuthenticationToken

为了成功地实现我们应用的身份验证功能,我们需要将传入的API
Key转换为AbstractAuthenticationToken类型的身份验证对象。AbstractAuthenticationToken类实现了Authentication接口,表示一个认证请求的主体和认证信息。

让我们创建ApiKeyAuthentication类:

public class ApiKeyAuthentication extends AbstractAuthenticationToken {
    private final String apiKey;

    public ApiKeyAuthentication(String apiKey,
        Collection<?extends GrantedAuthority> authorities) {
        super(authorities);
        this.apiKey = apiKey;
        setAuthenticated(true);
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    @Override
    public Object getPrincipal() {
        return apiKey;
    }
}

ApiKeyAuthentication 类是类型为 AbstractAuthenticationToken 的对象,其中包含从 HTTP
请求中获取的 apiKey 信息。在构造方法中使用 setAuthenticated(true) 方法。因此,Authentication对象包含
apiKey 和authenticated字段:

![图片](https://img-
blog.csdnimg.cn/img_convert/3ecdcf7e03f08f97da7a8e9fc161ddb5.png)

3.4. Security Config

通过创建建一个SecurityFilterChain bean,可以通过编程方式把我们上面编写的自定义过滤器(Filter)进行注册。

我们需要在 HttpSecurity 实例上使用 addFilterBefore() 方法在
UsernamePasswordAuthenticationFilter 类之前添加 AuthenticationFilter。

创建SecurityConfig 类:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf()
          .disable()
          .authorizeRequests()
          .antMatchers("/**")
          .authenticated()
          .and()
          .httpBasic()
          .and()
          .sessionManagement()
          .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
          .and()
          .addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

}

此外注意代码中我们吧绘画策略(session policy)设置为无状态(STATELESS),因为我们使用的是REST。

3.5. ResourceController

最后,我们创建ResourceController,实现一个Get请求 /home

@RestController
public class ResourceController {
    @GetMapping("/home")
    public String homeEndpoint() {
        return "Baeldung !";
    }
}
3.6. 禁用 Auto-Configuration
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class})
public class ApiKeySecretAuthApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiKeySecretAuthApplication.class, args);
    }
}

4. 测试

我们先不提供API Key进行测试

curl --location --request GET 'http://localhost:8080/home'

返回 401 未经授权错误。

请求头中加上API Key后,再次请求

curl --location --request GET 'http://localhost:8080/home' \
--header 'X-API-KEY: Baeldung'

请求返回状态200

学习网络安全技术的方法无非三种:

第一种是报网络安全专业,现在叫网络空间安全专业,主要专业课程:程序设计、计算机组成原理原理、数据结构、操作系统原理、数据库系统、 计算机网络、人工智能、自然语言处理、社会计算、网络安全法律法规、网络安全、内容安全、数字取证、机器学习,多媒体技术,信息检索、舆情分析等。

第二种是自学,就是在网上找资源、找教程,或者是想办法认识一-些大佬,抱紧大腿,不过这种方法很耗时间,而且学习没有规划,可能很长一段时间感觉自己没有进步,容易劝退。

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

第三种就是去找培训。

image.png

接下来,我会教你零基础入门快速入门上手网络安全。

网络安全入门到底是先学编程还是先学计算机基础?这是一个争议比较大的问题,有的人会建议先学编程,而有的人会建议先学计算机基础,其实这都是要学的。而且这些对学习网络安全来说非常重要。但是对于完全零基础的人来说又或者急于转行的人来说,学习编程或者计算机基础对他们来说都有一定的难度,并且花费时间太长。

第一阶段:基础准备 4周~6周

这个阶段是所有准备进入安全行业必学的部分,俗话说:基础不劳,地动山摇
image.png

第二阶段:web渗透

学习基础 时间:1周 ~ 2周:

① 了解基本概念:(SQL注入、XSS、上传、CSRF、一句话木马、等)为之后的WEB渗透测试打下基础。
② 查看一些论坛的一些Web渗透,学一学案例的思路,每一个站点都不一样,所以思路是主要的。
③ 学会提问的艺术,如果遇到不懂得要善于提问。
image.png

配置渗透环境 时间:3周 ~ 4周:

① 了解渗透测试常用的工具,例如(AWVS、SQLMAP、NMAP、BURP、中国菜刀等)。
② 下载这些工具无后门版本并且安装到计算机上。
③ 了解这些工具的使用场景,懂得基本的使用,推荐在Google上查找。

渗透实战操作 时间:约6周:

① 在网上搜索渗透实战案例,深入了解SQL注入、文件上传、解析漏洞等在实战中的使用。
② 自己搭建漏洞环境测试,推荐DWVA,SQLi-labs,Upload-labs,bWAPP。
③ 懂得渗透测试的阶段,每一个阶段需要做那些动作:例如PTES渗透测试执行标准。
④ 深入研究手工SQL注入,寻找绕过waf的方法,制作自己的脚本。
⑤ 研究文件上传的原理,如何进行截断、双重后缀欺骗(IIS、PHP)、解析漏洞利用(IIS、Nignix、Apache)等,参照:上传攻击框架。
⑥ 了解XSS形成原理和种类,在DWVA中进行实践,使用一个含有XSS漏洞的cms,安装安全狗等进行测试。
⑦ 了解一句话木马,并尝试编写过狗一句话。
⑧ 研究在Windows和Linux下的提升权限,Google关键词:提权
image.png
以上就是入门阶段

第三阶段:进阶

已经入门并且找到工作之后又该怎么进阶?详情看下图
image.png

给新手小白的入门建议:
新手入门学习最好还是从视频入手进行学习,视频的浅显易懂相比起晦涩的文字而言更容易吸收,这里我给大家准备了一套网络安全从入门到精通的视频学习资料包免费领取哦!

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值