专栏首页代码如诗开放API网关实践(二) —— 重放攻击及防御

开放API网关实践(二) —— 重放攻击及防御

.example_responsive_1 { width: 200px; height: 50px; } @media(min-width: 290px) { .example_responsive_1 { width: 270px; height: 50px; } } @media(min-width: 370px) { .example_responsive_1 { width: 339px; height: 50px; } } @media(min-width: 500px) { .example_responsive_1 { width: 468px; height: 50px; } } @media(min-width: 720px) { .example_responsive_1 { width: 655px; height: 50px; } } @media(min-width: 800px) { .example_responsive_1 { width: 728px; height: 50px; } } (adsbygoogle = window.adsbygoogle || []).push({});

开放API网关实践(二) —— 重放攻击及防御

目录

如何设计实现一个轻量的开放API网关之重放攻击及防御 文章地址: https://blog.piaoruiqing.com/2019/08/11/openapi-gateway-replay-attack/

前言

上一篇文章《开放API网关实践(一)》中的接口设计提到timestampnonce两个参数的作用是用来放重放. 本文就重放攻击及其防御进行探讨. 先抛出两个问题:

  • 什么是重放攻击
  • 如何防御重放攻击

什么是重放攻击(Replay Attacks)

什么是重放, 先举个例子:

打开浏览器的调试工具并访问一个网站, 在网络工具中找到一个请求并右键选择Replay. 如图:

上述的重放操作是接口调试中比较常用的手段, 这种操作可以让我们跳过认证信息的生成过程, 直接重复发起多次有效的请求.

重放攻击是一种黑客常用的攻击手段, 又称重播攻击回放攻击, 是指攻击者发送目的主机已接收过的数据, 以达到欺骗系统的目的, 主要用于身份认证过程, 破坏认证的正确性.

举个易懂的例子:

  • 服务端提供了打款接口, 用户A向服务端请求发起一次打款5元的操作(附带了签名并进行了加密), 服务端接收到了数据并正确打款给用户B.
  • 但这个请求被黑客拦截到(可能就是用户B干的 ( ̄▽ ̄)"), 黑客将请求原封不动地向服务器发送, 服务器多次错误地打款给用户B. (当然, 这些都是是建立在服务端的付款没做幂等等防范措施、安全级别较低的前提下)
  • 尽管A发起的请求有签名和加密, 但B无需破解这个数据, 只是将同样的数据重复发给服务器就能达到欺骗的目的.

模拟重放攻击

实验器材

序号

名称

数量

备注

1

服务器

2

10.33.30.101 – 真实服务器10.33.30.100 – 伪造服务器

2

域名

1

replay-test.piaoruiqing.com (10.33.30.101)

3

DNS服务器

1

用来模拟DNS劫持

实验步骤

  1. 启动服务器, 请求接口并收到响应数据.
  2. 劫持DNS(在路由器中修改DNS服务器地址模拟劫持), 并拦截请求数据.
  3. 向服务器重复发送拦截到的数据(重放攻击).

过程记录

准备工作

DNS配置, 将域名replay-test.piaoruiqing.com指向内网中服务器的IP. 并启动服务器.

正常请求

使用postman发起一个正常的请求, 其中签名已在Pre-request-script中生成.

通过DNS劫持来拦截数据

修改内网的dnsmasq配置, 将域名replay-test.piaoruiqing.com指向伪造的服务器10.33.30.100.

此时向replay-test.piaoruiqing.com发起的请求便会被发送到伪造的服务器上(10.33.30.100), 手动将请求的数据保存下来. 由于请求带有签名, 且攻击者并没有拿到私钥, 故无法篡改请求, 但可以进行重放攻击. 如图, 伪造服务器已成功接收到请求数据:

[版权声明] 本文发布于朴瑞卿的博客, 允许非商业用途转载, 但转载必须保留原作者朴瑞卿 及链接:https://blog.piaoruiqing.com. 如有授权方面的协商或合作, 请联系邮箱: piaoruiqing@gmail.com.

重放请求

使用上一步保存下来的数据, 直接向真实服务器发送请求(带有签名数据). 如图:

事实上, 签名、加密等手段并不能防御重放攻击, 因为攻击者拦截到的数据已是正确的请求数据, 即使无法破解其内容, 也可以重放向服务器发送原数据以达到欺骗的目的.

如何防御重放攻击

百度百科

  1. 加随机数: 该方法优点是认证双方不需要时间同步,双方记住使用过的随机数, 如发现报文中有以前使用过的随机数, 就认为是重放攻击. 缺点是需要额外保存使用过的随机数, 若记录的时间段较长, 则保存和查询的开销较大.
  2. 加时间戳: 该方法优点是不用额外保存其他信息. 缺点是认证双方需要准确的时间同步, 同步越好, 受攻击的可能性就越小. 但当系统很庞大, 跨越的区域较广时, 要做到精确的时间同步并不是很容易.
  3. 加流水号: 就是双方在报文中添加一个逐步递增的整数, 只要接收到一个不连续的流水号报文(太大或太小), 就认定有重放威胁. 该方法优点是不需要时间同步, 保存的信息量比随机数方式小. 缺点是一旦攻击者对报文解密成功, 就可以获得流水号, 从而每次将流水号递增欺骗认证端.

在实际使用中, 常将1和2结合使用, 时间戳有效期内判断随机数是否已存在, 有效期外则直接丢弃.

重放攻击防御实践

我们采取时间戳+随机数的方式来实现一个简单的重放攻击拦截器. 时间戳和随机数互补, 既能在时间有效范围内通过校验缓存中的随机数是否存在来分辨是否为重放请求, 也能在缓存失效后(缓存有效时间和时间范围一致)通过时间戳来校验该请求是否为重放. 如图:

代码如下:

@Resource
private ReactiveStringRedisTemplate reactiveStringRedisTemplate;

private ReactiveValueOperations<String, String> reactiveValueOperations;

@PostConstruct
public void postConstruct() {
    reactiveValueOperations = reactiveStringRedisTemplate.opsForValue();
}

@Override
protected Mono<Void> doFilter(ServerWebExchange exchange, WebFilterChain chain) {
    // 此处的<code>ATTRIBUTE_OPEN_API_REQUEST_BODY</code>是前面过滤器存入的
    OpenApiRequest<String> body 
        = exchange.getRequiredAttribute(ATTRIBUTE_OPEN_API_REQUEST_BODY);
    if (!ObjectUtils.allNotNull(body, body.getTimestamp(), body.getNonce())) {
        return fail(exchange);
    }
    Long gmt = System.currentTimeMillis();
    // (一)
    if (gmt + effectiveTimeRange < body.getTimestamp() || 
        gmt - effectiveTimeRange > body.getTimestamp()) {
        return fail(exchange);
    }
    // (二)
    return reactiveValueOperations.setIfAbsent(MessageFormat.format(
            KEY_REPLAY_NONCE, body.getAppId(), body.getNonce()),
            String.valueOf(System.currentTimeMillis()),
            Duration.ofMillis(effectiveTimeRange * 2L))
        .log(LOGGER, Level.FINE, true)
        .flatMap(approved -> approved ? 
                 chain.filter(exchange) : fail(FORBIDDEN, exchange)
            );
  • (一): 请求时间超出时间范围的将被拒绝.
  • (二): 缓存过期时间等于有效时间的跨度, 若缓存中已存在该随机数, 则拒绝.

结语

重放攻击防御的关键点:

  • 记录请求标识并缓存, 接受请求时校验, 拒绝重放, 即将nonce存入缓存, 拒绝相同的nonce
  • 随机数的方式可能造成过多的缓存, 故需要配合时间戳进行过滤, 时间戳不在有效范围内的一律拒绝.

重放攻击是一种常用且有效的攻击手段, 其危害不可忽视, 尽管可以通过业务层面来保障数据的正确性, 但依旧会给系统造成不必要开销, 在网关层过滤掉重放请求是一个不错的选择.

© 2019, 朴瑞卿.

[版权声明] 本文发布于朴瑞卿的博客, 允许非商业用途转载, 但转载必须保留原作者朴瑞卿 及链接:https://blog.piaoruiqing.com. 如有授权方面的协商或合作, 请联系邮箱: piaoruiqing@gmail.com.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Mac中安全地使用rm命令

    .example_responsive_1 { width: 200px; height: 50px; } @media(min-width: 290px)...

    草堂笺
  • 我是如何通过Nginx日志实时封禁风险IP的

    .example_responsive_1 { width: 200px; height: 50px; } @media(min-width: 290px)...

    草堂笺
  • 记一次Redis连接超限排查

    .example_responsive_1 { width: 200px; height: 50px; } @media(min-width: 290px)...

    草堂笺
  • 如何取消ajax请求的回调

    我们在开发过程中有时候会碰到这样的需求,连续发送多个ajax请求,请求个数大于等于2,后面的ajax请求发送时,如果前面的ajax请求还没有返回,就取消前面aj...

    挥刀北上
  • HTTP状态码及其含义

    iOSSir
  • 用 Python 爬取网易严选妹子内衣信息,探究妹纸们的偏好

    在商品页面,打开 Chrome 的控制台,切换至 Network 页,再把商品页面切换到评价标签下,选择一个评论文字,如“薄款、穿着舒适、满意”,在 Netwo...

    Java识堂
  • 如何快速的为系统做安全检测

    ag -g a.txt 查找名字为a.txt的文件 ag -i test 忽略大小写搜索包含test的文本 ag -A 5 abc 显示搜索到的包含abc的行以...

    致码DevOps
  • Java之static作用的全方位总结

     引用一位网友的话,说的非常好,如果别人问你static的作用;如果你说静态修饰 类的属性 和 类的方法 别人认为你是合格的;如果是说 可以构成 静态代码块,...

    小勇DW3
  • centos7格式化大于2T的硬盘

    (adsbygoogle = window.adsbygoogle || []).push({});

    拓荒者
  • windows下 zookeeper dubbo 安装+配置+demo 详细图文教程

    互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的。...

    良月柒

扫码关注云+社区

领取腾讯云代金券