## 什么是重放攻擊(Replay Attacks)
`重放攻擊`是一種黑客常用的攻擊手段, 又稱`重播攻擊`、`回放攻擊`, 是指攻擊者發送目的主機`已接收過的數據`, 以達到欺騙系統的目的, 主要用于身份認證過程, 破壞認證的正確性.

### HTTPS數據加密是否可以防止重放攻擊?
否,加密可以有效防止明文數據被監聽,但是卻防止不了重放攻擊。
## 如何防御重放攻擊
1. `加隨機數nonce`: 該方法優點是認證雙方不需要時間同步,雙方記住使用過的隨機數, 如發現報文中有以前使用過的隨機數, 就認為是重放攻擊. 缺點是需要額外保存使用過的隨機數, 若記錄的時間段較長, 則保存和查詢的開銷較大.
2. `加時間戳timestamp`: 該方法優點是不用額外保存其他信息. 缺點是認證雙方需要準確的時間同步, 同步越好, 受攻擊的可能性就越小. 但當系統很龐大, 跨越的區域較廣時, 要做到精確的時間同步并不是很容易.
3. `加流水號`: 就是雙方在報文中添加一個逐步遞增的整數, 只要接收到一個不連續的流水號報文(太大或太小), 就認定有重放威脅. 該方法優點是不需要時間同步, 保存的信息量比隨機數方式小. 缺點是一旦攻擊者對報文解密成功, 就可以獲得流水號, 從而每次將流水號遞增欺騙認證端.
在實際使用中, 常將1和2結合使用, 時間戳有效期內判斷隨機數是否已存在, 有效期外則直接丟棄.
## 使用timestamp和nonce
我們采取`時間戳`+`隨機數`的方式來實現一個簡單的重放攻擊攔截器. 時間戳和隨機數互補, 既能在時間有效范圍內通過校驗緩存中的隨機數是否存在來分辨是否為重放請求, 也能在緩存失效后(緩存有效時間和時間范圍一致)通過時間戳來校驗該請求是否為重放. 如圖:

```
@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`
* 隨機數的方式可能造成過多的緩存, 故需要配合時間戳進行過濾, 時間戳不在有效范圍內的一律拒絕.
重放攻擊是一種常用且有效的攻擊手段, 其危害不可忽視, 盡管可以通過業務層面來保障數據的正確性, 但依舊會給系統造成不必要開銷, 在網關層過濾掉重放請求是一個不錯的選擇.
## 參考資料
> https://segmentfault.com/a/1190000020036097?utm_source=sf-related
https://segmentfault.com/a/1190000014821815