滑動窗口防重放算法使用經(jīng)驗分享

一、概要

在安全機制的設計過程中进宝,通常考慮多種安全機制枷恕,其中防重放機制是眾多安全機制中較為重要的一個党晋。在尤其在控制信令傳輸環(huán)節(jié),防重放攻擊尤為重要徐块。目前項目中使用到的防重放機制多為流水編號機制未玻,該機制實現(xiàn)簡單,但無法滿足復雜網(wǎng)絡環(huán)境下存在丟包的場景胡控。該案例介紹了兩種滑動窗口的設計思路和實現(xiàn)扳剿,以滿足復雜網(wǎng)絡環(huán)境下丟包和包不連續(xù)的場景。

二铜犬、滑動窗口算法描述

(一)標準滑動窗口算法

  1. 窗口右邊界為已接收的舞终,且最大的數(shù)據(jù)包序列號(Max Sequence Number),窗口左邊界為最大數(shù)據(jù)包序列號減去窗口大小得到的數(shù)值(Max Sequence Number - Windows Size)癣猾。
    假設:窗口大小為32敛劝,Max Sequence Number為100,窗口如下:
    |_____________32_____________|
    68 ?????????100

  2. 當新接收的數(shù)據(jù)包的Sequence Number 大于68且小于100時纷宇,數(shù)據(jù)包合法夸盟,且窗口中對應的位置設置為1,說明該序號已接收像捶。當該序號再次出現(xiàn)時上陕,認為非法桩砰。如當前Sequence Number為78:
    |________1_____32_____________|
    68 ? \color{red}{78} ??????? 100

  3. 當新接收的數(shù)據(jù)包的Sequence Number 小于68時,認為該數(shù)據(jù)包非法释簿。

  4. 當新接收的數(shù)據(jù)包的Sequence Number 大于100亚隅,小于100+32時,數(shù)據(jù)包合法庶溶,并將窗口右邊界設置為該數(shù)據(jù)包Sequence Number 煮纵, 如當前Sequence Number 為120:
    |_____________32_____________|
    88 ?? ????????120

  5. 當新接收的數(shù)據(jù)包的Sequence Number 大于100+32時,數(shù)據(jù)包不合法偏螺。

(二)無右邊界滑動窗口算法

該算法對標準算法第五步進行調(diào)整: 當新接收的數(shù)據(jù)包Sequence Number大于窗口大小行疏,右邊界設置為新接收的Sequence Number,窗口最右端bit設置為1套像,其余設置為0酿联。
該算法設計背景: 在部分UDP連接情況下,數(shù)據(jù)包會有連續(xù)發(fā)送失敗的場景夺巩,導致接收端接收的數(shù)據(jù)包Sequence Number驟然增大贞让,防重放機制會阻擋正常數(shù)據(jù)包的接收,因此需關閉滑動窗口右邊界限制劲够。
該算法引入的風險:新方案關閉滑動窗口右邊界限制震桶,當同一Session下有大于當前Sequence Number的數(shù)據(jù)包混入休傍,會將滑動窗口向右推移征绎,導致正常數(shù)據(jù)無法接收。
風險解決方案:Sequence Number在Session會話有效期內(nèi)不會重新計數(shù)即可磨取。

三人柿、滑動窗口算法運行要求

防重放程序必須在簽名校驗完成且通過后才能開始運行,防止窗口被惡意推動忙厌,導致業(yè)務處理中斷凫岖。

四、算法實現(xiàn)

考慮到滑動窗口計算需要較短的處理時間逢净,因此采用bitmap算法設計滑動窗口實現(xiàn)哥放。并提供固定窗口大小算法和動態(tài)設定窗口大小算法,來滿足復雜環(huán)境下業(yè)務對窗口動態(tài)調(diào)整的需求爹土。

固定窗口大小
// C++ program to demonstrate various functionality of bitset
#include <bits/stdc++.h>
using namespace std;
 
enum {
    ReplayWindowSize = 128  //如果需要將窗口大小設置為1甥雕,此處設置ReplayWindowSize = 2
};
typedef unsigned long u_long;
u_long lastSeq = 0;
bitset<ReplayWindowSize> bitmap;
 
int ChkReplayWindow(u_long seq) {
    u_long diff;
 
    if (seq == 0) return 0;             /* first == 0 or wrapped */
    if (seq > lastSeq) {                /* new larger sequence number */
        diff = seq - lastSeq;
        if (diff < ReplayWindowSize) {  /* In window */
            bitmap <<= diff;
            bitmap |= 1;                /* set bit for this packet */
        //} else return 0;          /* 啟用窗口右邊界限制 */
        } else bitmap = 1;        /*關閉窗口右邊界限制 */
        lastSeq = seq;
        return 1;                       /* larger is good */
    }
    diff = lastSeq - seq;
    if (diff >= ReplayWindowSize) return 0; /* too old or wrapped */
    if (bitmap[diff] == 1) return 0; /* already seen */
    bitmap |= ((u_long)1 << diff);              /* mark as seen */
    return 1;                           /* out of order but good */
}
 
char string_buffer[512];
#define STRING_BUFFER_SIZE sizeof(string_buffer)
 
int main()
{
    cout << bitmap << endl; // 00000000000000000000000000000000
 
    int result;
    u_long last, current;
    uint64_t bits;
 
    printf("Input initial state (bits in hex, last msgnum):\n");
    if (!fgets(string_buffer, STRING_BUFFER_SIZE, stdin)) exit(0);
    sscanf(string_buffer, "%lx %lu", &bits, &last);
    if (last != 0)
        bits |= 1;
    bitmap = bits;
    lastSeq = last;
    cout << "bits: " << bitmap << "\n";
    printf("last:%lu\n", lastSeq);
    printf("Input value to test (current):\n");
 
    while (1) {
        if (!fgets(string_buffer, STRING_BUFFER_SIZE, stdin)) break;
        sscanf(string_buffer, "%lu", ¤t);
        result = ChkReplayWindow(current);
        printf("%-3s", result ? "OK " : "BAD ");
        cout << "bits: " << bitmap << "\n";
        printf("last:%lu\n",lastSeq);
    }
    return 0;
} 
動態(tài)窗口大小
// C++ program to demonstrate various functionality of bitset
#include <bits/stdc++.h>
using namespace std;
 
enum {
    ReplayWindowSize = 8    //如果需要將窗口大小設置為1,此處設置ReplayWindowSize = 2
};
typedef unsigned long u_long;
u_long lastSeq = 0;
std::vector<bool> bitmap;
 
void LeftShift(int n){
    for (int i = 0;i < n;i++)
    {
        bitmap.insert(bitmap.begin(),0);
        bitmap.erase(bitmap.end());
    }
}
 
void PrintBit(){
    for (int i = 0; i<bitmap.size();i++)
    {
        std::cout << bitmap[i] << ",";
    }
    std::cout << std::endl;
}
 
int ChkReplayWindow(u_long seq) {
    u_long diff;
 
    if (seq == 0) return 0;             /* first == 0 or wrapped */
    if (seq > lastSeq) {                /* new larger sequence number */
        diff = seq - lastSeq;
        if (diff < ReplayWindowSize) {  /* In window */
            LeftShift(diff);
            bitmap[0] = 1;                /* set bit for this packet */
        //} else return 0;          /*啟用窗口右邊界限制*/
        } else bitmap.clear();bitmap.resize(ReplayWindowSize);bitmap[0] = 1;  /*關閉窗口右邊界限制 */
        lastSeq = seq;
        return 1;                       /* larger is good */
    }
    diff = lastSeq - seq;
    if (diff >= ReplayWindowSize) return 0; /* too old or wrapped */
    if (bitmap[diff] == 1) return 0; /* already seen */
    bitmap[diff] = 1;              /* mark as seen */
    return 1;                           /* out of order but good */
}
 
char string_buffer[512];
#define STRING_BUFFER_SIZE sizeof(string_buffer)
 
int main()
{
    bitmap.resize(ReplayWindowSize);
    PrintBit(); // 00000000000000000000000000000000
 
    int result;
    u_long last, current;
    uint64_t bits;
 
    printf("Input initial state (last msgnum):\n");
    if (!fgets(string_buffer, STRING_BUFFER_SIZE, stdin)) exit(0);
    sscanf(string_buffer, "%lu", &last);
    if (last != 0)
        bitmap[0] = 1;
 
    lastSeq = last;
    PrintBit();
    printf("last:%lu\n", lastSeq);
    printf("Input value to test (current):\n");
 
    while (1) {
        if (!fgets(string_buffer, STRING_BUFFER_SIZE, stdin)) break;
        sscanf(string_buffer, "%lu", ¤t);
        result = ChkReplayWindow(current);
        printf("%-3s", result ? "OK " : "BAD ");
        PrintBit();
        //cout << "bits: " << bitmap << "\n";
        printf("last:%lu\n",lastSeq);
    }
    return 0;
}

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胀茵,一起剝皮案震驚了整個濱河市社露,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌琼娘,老刑警劉巖峭弟,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件附鸽,死亡現(xiàn)場離奇詭異,居然都是意外死亡瞒瘸,警方通過查閱死者的電腦和手機坷备,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來情臭,“玉大人击你,你說我怎么就攤上這事』驯” “怎么了丁侄?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長朝巫。 經(jīng)常有香客問我鸿摇,道長,這世上最難降的妖魔是什么劈猿? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任拙吉,我火速辦了婚禮,結果婚禮上揪荣,老公的妹妹穿的比我還像新娘筷黔。我一直安慰自己,他們只是感情好仗颈,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布佛舱。 她就那樣靜靜地躺著,像睡著了一般挨决。 火紅的嫁衣襯著肌膚如雪请祖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天脖祈,我揣著相機與錄音肆捕,去河邊找鬼。 笑死盖高,一個胖子當著我的面吹牛慎陵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播喻奥,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼席纽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了映凳?” 一聲冷哼從身側響起胆筒,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后仆救,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抒和,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年彤蔽,在試婚紗的時候發(fā)現(xiàn)自己被綠了摧莽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡顿痪,死狀恐怖镊辕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蚁袭,我是刑警寧澤征懈,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站揩悄,受9級特大地震影響卖哎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜删性,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一亏娜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蹬挺,春花似錦维贺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汤善。三九已至,卻和暖如春拒逮,著一層夾襖步出監(jiān)牢的瞬間熄云,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工绰寞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓只恨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親抬虽。 傳聞我的和親對象是個殘疾皇子官觅,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 首先,我們需要知道TCP在網(wǎng)絡ISO的七層模型中的第四層——Transport層阐污,IP在第三層——Network層...
    CodeKing2017閱讀 1,093評論 0 4
  • TCP層分析 傳輸控制協(xié)議休涤,為數(shù)據(jù)提供可靠的端到端傳輸,處理數(shù)據(jù)的順序和錯誤恢復,保證數(shù)據(jù)能夠到達其應到達的地方 ...
    fishmai0閱讀 3,311評論 0 1
  • 傳輸層-TCP功氨, TCP頭部結構 序苏,TCP序列號和確認號詳解 TCP主要解決下面的三個問題 1.數(shù)據(jù)的可靠傳輸...
    抓兔子的貓閱讀 4,505評論 1 46
  • 將TCP與UDP這樣的簡單傳輸協(xié)議區(qū)分開來的是它傳輸數(shù)據(jù)的質(zhì)量。TCP對于發(fā)送數(shù)據(jù)進行跟蹤捷凄,這種數(shù)據(jù)管理需要協(xié)議有...
    殺破魂閱讀 1,001評論 0 2
  • 女兒一家老小5口今早8點8分從深圳出發(fā)忱详,傍晚6點我問車到哪里了,以為快到了呢跺涤,可她回消息并發(fā)來位置圖匈睁,原來這一整天...
    漢天真閱讀 121評論 0 3