你的Springboot項(xiàng)目API接口安全嗎萨赁?一招簽名校驗(yàn)讓你睡的安心

前言

現(xiàn)在的項(xiàng)目都采用前后端分類的方式開發(fā)了,前后端的通訊方式都通過API進(jìn)行傳輸兆龙。我們知道杖爽,如果是管理后臺的開發(fā),可以通過shiro或springSecurity進(jìn)行權(quán)限控制紫皇,進(jìn)而保證API接口的安全性慰安,但是,當(dāng)我們在進(jìn)行APP或小程序開發(fā)的時候聪铺,因?yàn)樾枰脩糸L期登錄等問題化焕,再采用shiro等方式進(jìn)行安全控制就顯得不是那么合理的。

可是铃剔,如何讓我們的API接口變得安全點(diǎn)撒桨?不至于當(dāng)其他人通過抓包的方式拿到你的userId或一些重要參數(shù)的時候,對你的數(shù)據(jù)進(jìn)行破壞番宁。

那么元莫,API接口的簽名校驗(yàn)赖阻,將會是你阻擋這些破壞的一堵墻蝶押。

下面,讓我們開始API簽名校驗(yàn)之旅吧火欧。

基礎(chǔ)準(zhǔn)備

首先棋电,我們先要了解一下普通的API接口是如何訪問的(以POSTMAN為例)。


請求/sign/test接口

下面貼一下代碼

@RestController
@RequestMapping(value = "/sign")
public class SignController {

    /**
     * 驗(yàn)簽測試
     *
     * @return
     */
    @RequestMapping(value = "/test")
    public String test(String name) {
        return name;
    }

}

代碼很簡潔苇侵,無需多言赶盔,我想,在沒進(jìn)行簽名校驗(yàn)的時候大多數(shù)人的代碼都是這樣的吧榆浓。

正式開始

實(shí)現(xiàn)效果

1于未、前端請求方式

我們需要用到的就是,http請求的 header陡鹃,將token(令牌) 和 timestamp(時間戳)作為參數(shù)烘浦,一起發(fā)送給我們的后端。然后后端對token和timestamp進(jìn)行校驗(yàn)萍鲸,校驗(yàn)通過后闷叉,才進(jìn)行的正式訪問。


通過postman設(shè)置header

2脊阴、后端處理方式

@RestController
@RequestMapping(value = "/sign")
public class SignController {

    /**
     * 驗(yàn)簽測試
     *
     * @return
     */
    @SignatureValidation
    @RequestMapping(value = "/test")
    public String test(String name) {
        return name;
    }

}

是的握侧,你沒有看錯蚯瞧,就多了一個注解(自定義的,不用去百度什么意思了)品擎。

 @SignatureValidation

加上后埋合,看效果


請求被簽名攔截了

好了,下面去看怎么實(shí)現(xiàn)的吧萄传。

實(shí)現(xiàn)原理

1饥悴、簽名規(guī)則

(1)、前后端都要統(tǒng)一一個秘鑰(secret)盲再,這個秘鑰是自己定義的西设,盡可能復(fù)雜點(diǎn)。這個可別泄露哦答朋。
(2)贷揽、我們需要準(zhǔn)備一個當(dāng)前時間戳 timeStamp,這個很好獲取梦碗,要注意的是禽绪,這個時間戳最好要精確到毫秒。
(3)洪规、我們要確定自己的加密方式印屁。可以使用MD5進(jìn)行加密斩例,你想加密幾次看心情雄人,讓他們猜不出來就行了。
(4)念赶、將秘鑰和時間戳拼接字符串础钠,然后通過你們約定的加密方式進(jìn)行加密,得到TOKEN
偽代碼(一次加密為例)

token = MD5(secret+ timeStamp);

思考:如果一個人通過抓包的方式拿到了你的接口(header 中的token 和 timestamp)叉谜,他如何才能進(jìn)行破解旗吁?

第一:他要知道我們的秘鑰(secret),只要你設(shè)計(jì)的夠復(fù)雜,靠猜是猜不出來的停局。
第二:他要知道我們的加密方式很钓,我這里用MD5這種常規(guī)加密,你們可以換個加密方式董栽,最好是非對稱加密码倦。
第三:他要知道我們的加密次數(shù)。
第四:他要知道我們的加密規(guī)則

如果不是特別重要的接口或者專門要搞你裆泳,大部分會退縮的叹洲。當(dāng)然少部分就會通過反編譯你的源碼去拿到這些數(shù)據(jù),或者意外泄露工禾,那你只能自己去加強(qiáng)相關(guān)的防護(hù)去唄运提』热幔混淆文件啦,應(yīng)用加固啦民泵,用膠帶粘住嘴啦癣丧,方法很多,自己去慢慢研究栈妆。

2胁编、Springboot 實(shí)現(xiàn)(大家最喜歡的環(huán)節(jié),一步步去復(fù)制代碼到自己項(xiàng)目中去吧)

1鳞尔、新建一個文件嬉橙,定義注解接口

文件位置

package com.xxx.aop;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
 * @author tangn
 * 小程序請求認(rèn)證
 */
@Retention(value = RetentionPolicy.RUNTIME)
public @interface SignatureValidation {
}

其中,一定要注意包名(根據(jù)你放這個文件位置)寥假,這個下面會用到市框。

package com.xxx.aop;

2、使用aspect進(jìn)行切點(diǎn)攔截(不知道其實(shí)現(xiàn)原理糕韧,去百度吧)

文件位置(忽略那個HttpAspect)

@Aspect
@Component
public class SignatureValidation {
    /**
     * 時間戳請求最小限制(30s)
    * 設(shè)置的越小枫振,安全系數(shù)越高,但是要注意一定的容錯性
     */
    private static final long MAX_REQUEST = 30 * 1000L;
    /**
     * 秘鑰
     */
     private static final long SECRET= "前后端約定的秘鑰";

    /**
     * 驗(yàn)簽切點(diǎn)(完整的找到設(shè)置的文件地址)
     */
    @Pointcut("execution(@com.xxx.aop.SignatureValidation * *(..))")
    private void verifyUserKey() {
    }

    /**
     * 開始驗(yàn)簽
     */
    @Before("verifyUserKey()")
    public void doBasicProfiling() {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String token = request.getHeader("token");
        String timestamp = request.getHeader("timestamp");
        try {
            Boolean check = checkToken(token, timestamp);
            if (!check) {
              // 自定義異常拋出(開發(fā)者自行換成自己的即可)
                throw new MyException(ResultEnums.ERROR, "簽名驗(yàn)證錯誤");
            }
        } catch (Throwable throwable) {
            // 自定義異常拋出(開發(fā)者自行換成自己的即可)
            throw new PlbException(ResultEnums.ERROR, "簽名驗(yàn)證錯誤");
        }
    }

    /**
     * 校驗(yàn)token
     *
     * @param token     簽名
     * @param timestamp 時間戳
     * @return 校驗(yàn)結(jié)果
     */
    private Boolean checkToken(String token, String timestamp) {
        if (StringUtils.isAnyBlank(token, timestamp)) {
            return false;
        }
        long now = System.currentTimeMillis();
        long time = Long.parseLong(timestamp);
        if (now - time > MAX_REQUEST) {
            log.error("時間戳已過期[{}][{}][{}]", now, time, (now - time));
            return false;
        }
        String crypt = MD5Utils.getMD5(SECRET+ timestamp);
        return StringUtils.equals(crypt, token);
    }
}

下面說一下用到的工具類:
MD5Utils
每個項(xiàng)目里面都有吧萤彩,沒有的話網(wǎng)上一搜就行了粪滤。
StringUtils
其實(shí)很簡單,自己寫也行雀扶,引入第三方的也行杖小,我是引用的apache的,你們也可試試怕吴。
pom.xml 文件

   <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

好了窍侧,你又沒有看錯县踢。這樣結(jié)束了转绷。這樣你就有了自己的簽名校驗(yàn)工具類,快拿到你的項(xiàng)目中試試去吧硼啤。
然后你以后的API接口议经,只需要加上這個注解就能進(jìn)行簽名驗(yàn)證了。

 @SignatureValidation

總結(jié)

很多時候谴返,我們在開發(fā)中都只關(guān)心業(yè)務(wù)煞肾,對安全性的問題很可能就忽略了,其實(shí)我們只需要對自己的API接口稍微一處理嗓袱,有可能就會避免一些安全問題籍救。從而避免一些不必要的損失。好吧渠抹,就到這里蝙昙,安心睡覺去吧闪萄。

源碼

https://gitee.com/bean1995/signature_verification
在 tangn_init_20200314 分支
多說一句:看到很多給樓主評論的(可以去看評論區(qū)的討論),加簽是為了讓項(xiàng)目多一層防護(hù)奇颠,具體還要取決于項(xiàng)目的重要程度败去,如果涉及到資金、秘鑰等項(xiàng)目烈拒,可以采用更安全的加密方式圆裕,或者前端加強(qiáng)校驗(yàn)。android荆几、ios加殼吓妆,h5做混淆等。這篇文章主要還是想將非侵入的通過注解方式引入簽名吨铸,具體怎么個簽法耿战,要根據(jù)項(xiàng)目來定呦~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市焊傅,隨后出現(xiàn)的幾起案子剂陡,更是在濱河造成了極大的恐慌,老刑警劉巖狐胎,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸭栖,死亡現(xiàn)場離奇詭異,居然都是意外死亡握巢,警方通過查閱死者的電腦和手機(jī)晕鹊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來暴浦,“玉大人溅话,你說我怎么就攤上這事「杞梗” “怎么了飞几?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長独撇。 經(jīng)常有香客問我屑墨,道長,這世上最難降的妖魔是什么纷铣? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任卵史,我火速辦了婚禮,結(jié)果婚禮上搜立,老公的妹妹穿的比我還像新娘以躯。我一直安慰自己,他們只是感情好啄踊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布忧设。 她就那樣靜靜地躺著色鸳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪见转。 梳的紋絲不亂的頭發(fā)上命雀,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音斩箫,去河邊找鬼吏砂。 笑死,一個胖子當(dāng)著我的面吹牛乘客,可吹牛的內(nèi)容都是我干的狐血。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼易核,長吁一口氣:“原來是場噩夢啊……” “哼匈织!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起牡直,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤缀匕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后碰逸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乡小,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年饵史,在試婚紗的時候發(fā)現(xiàn)自己被綠了满钟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡胳喷,死狀恐怖湃番,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吭露,我是刑警寧澤吠撮,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站奴饮,受9級特大地震影響纬向,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜戴卜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琢岩。 院中可真熱鬧投剥,春花似錦、人聲如沸担孔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至啄育,卻和暖如春酌心,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挑豌。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工安券, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人氓英。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓侯勉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親铝阐。 傳聞我的和親對象是個殘疾皇子址貌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353