Token的詳細說明展箱,看這一篇就夠了

大家好,我是李俊輝蹬昌!我會把精彩文章在深入看懂的基礎(chǔ)上混驰,過濾出精華轉(zhuǎn)載過來,推薦給大家皂贩,分享給更多的人參考和學(xué)習(xí)栖榨。如果您覺得文章有用,請幫忙點個贊或關(guān)注明刷,也為我鼓勵一下婴栽,堅持寫下去!

對于 Token辈末,在很多大型網(wǎng)站中都有所應(yīng)用愚争,比如 Facebook,Twitter挤聘,Google轰枝,Github 等等,比起傳統(tǒng)的身份驗證方法组去,Token 的擴展性更強鞍陨,也更安全點,非常適合用在 Web 應(yīng)用或者移動應(yīng)用上从隆。Token 的中文有人翻譯成 “令牌”诚撵,我覺得挺好,意思就是键闺,你拿著這個令牌寿烟,才能過一些關(guān)卡。

1.基于Token 的身份驗證方法

使用基于 Token 的身份驗證方法辛燥,在服務(wù)端不需要存儲用戶的登錄記錄韧衣。大概的流程是這樣的:

客戶端使用用戶名跟密碼請求登錄盅藻;
服務(wù)端收到請求,去驗證用戶名與密碼畅铭;
驗證成功后氏淑,服務(wù)端會簽發(fā)一個 Token,再把這個 Token 發(fā)送給客戶端硕噩;
客戶端收到 Token 以后可以把它存儲起來假残,比如放在 Cookie 里或者 Local Storage 里;
客戶端每次向服務(wù)端請求資源的時候需要帶著服務(wù)端簽發(fā)的 Token炉擅;
服務(wù)端收到請求辉懒,然后去驗證客戶端請求里面帶著的 Token,如果驗證成功谍失,就向客戶端返回請求的數(shù)據(jù)眶俩。
2.JWT

實施 Token 驗證的方法挺多的,還有一些標準方法快鱼,比如 JWT颠印,讀作:jot ,表示:JSON Web Tokens 抹竹。JWT 標準的 Token 有三個部分:

1.header(頭部)线罕,頭部信息主要包括(參數(shù)的類型--JWT,簽名的算法--HS256)
2.poyload(負荷),負荷基本就是自己想要存放的信息(因為信息會暴露窃判,不應(yīng)該在載荷里面加入任何敏感的數(shù)據(jù))
3.sign(簽名)钞楼,簽名的作用就是為了防止惡意篡改數(shù)據(jù),下邊會詳細說明

中間用點分隔開袄琳,并且都會使用 Base64 編碼询件,所以真正的 Token 看起來像這樣:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc
2.1 Header

Header 部分主要是兩部分內(nèi)容,一個是 Token 的類型唆樊,另一個是使用的算法宛琅,比如下面類型就是 JWT,使用的算法是 HS256窗轩。

{
    "typ" : "JWT",
    "alg" : "HS256"
}

上面的內(nèi)容要用 Base64 的形式編碼一下,所以就變成這樣:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
2.2 Payload

Payload 里面是 Token 的具體內(nèi)容座咆,這些內(nèi)容里面有一些是標準字段痢艺,你也可以添加其它需要的內(nèi)容。下面是標準字段:

iss:Issuer介陶,發(fā)行者
sub:Subject堤舒,主題
aud:Audience,觀眾
exp:Expiration time哺呜,過期時間
nbf:Not before
iat:Issued at舌缤,發(fā)行時間
jti:JWT ID

比如下面這個 Payload,用到了 iss 發(fā)行人,exp 過期時間国撵,另外還有兩個自定義的字段陵吸,一個是 name ,還有一個是 admin 介牙。

{
    "iss" : "csdn.net",
    "exp" : "201511205211314",
    "name" : "維C果糖",
    "admin" : true
}

使用 Base64 編碼以后就變成了這個樣子:

eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ
2.3 Signature

JWT 的最后一部分是 Signature 壮虫,這部分內(nèi)容有三個部分,先是用 Base64 編碼的 header 和 payload 环础,再用加密算法加密一下囚似,加密的時候要放進去一個 Secret ,這個相當于是一個密碼线得,這個密碼秘密地存儲在服務(wù)端饶唤。

header
payload
secret
var encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload); 
HMACSHA256(encodedString, 'secret');

處理完成以后看起來像這樣:

SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

最后這個在服務(wù)端生成并且要發(fā)送給客戶端的 Token 看起來像這樣:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

客戶端收到這個 Token 以后把它存儲下來,下回向服務(wù)端發(fā)送請求的時候就帶著這個 Token 贯钩。服務(wù)端收到這個 Token 募狂,然后進行驗證,通過以后就會返回給客戶端想要的資源魏保。

3.Web安全

Token熬尺,我們稱之為“令牌”,其最大的特點就是隨機性谓罗,不可預(yù)測粱哼。一般黑客或軟件無法猜測出來。那么檩咱,Token 有什么作用揭措?又是什么原理呢?

Token 一般用在兩個地方:

`防止表單重復(fù)提交刻蚯;
Anti CSRF 攻擊(跨站點請求偽造)绊含。`

兩者在原理上都是通過 session token 來實現(xiàn)的。當客戶端請求頁面時炊汹,服務(wù)器會生成一個隨機數(shù) Token躬充,并且將 Token 放置到 session 當中,然后將 Token 發(fā)給客戶端(一般通過構(gòu)造 hidden 表單)讨便。下次客戶端提交請求時充甚,Token 會隨著表單一起提交到服務(wù)器端。

然后霸褒,如果應(yīng)用于“Anti CSRF攻擊”伴找,則服務(wù)器端會對 Token 值進行驗證,判斷是否和session中的Token值相等废菱,若相等技矮,則可以證明請求有效抖誉,不是偽造的。不過衰倦,如果應(yīng)用于“防止表單重復(fù)提交”袒炉,服務(wù)器端第一次驗證相同過后,會將 session 中的 Token 值更新下耿币,若用戶重復(fù)提交梳杏,第二次的驗證判斷將失敗,因為用戶提交的表單中的 Token 沒變淹接,但服務(wù)器端 session 中 Token 已經(jīng)改變了十性。

上面的 session 應(yīng)用相對安全,但也叫繁瑣塑悼,同時當多頁面多請求時劲适,必須采用多 Token 同時生成的方法,這樣占用更多資源厢蒜,執(zhí)行效率會降低霞势。因此,也可用 cookie 存儲驗證信息的方法來代替 session Token斑鸦。比如愕贡,應(yīng)對“重復(fù)提交”時,當?shù)谝淮翁峤缓蟊惆岩呀?jīng)提交的信息寫到 cookie 中巷屿,當?shù)诙翁峤粫r固以,由于 cookie 已經(jīng)有提交記錄,因此第二次提交會失敗嘱巾。不過憨琳,cookie 存儲有個致命弱點,如果 cookie 被劫持(XSS 攻擊很容易得到用戶 cookie)旬昭,那么又一次 game over篙螟,黑客將直接實現(xiàn) CSRF 攻擊。所以问拘,安全和高效相對的遍略,具體問題具體分析吧!

此外骤坐,要避免“加 token 但不進行校驗”的情況绪杏,在 session 中增加了 token,但服務(wù)端沒有對 token 進行驗證或油,這樣根本起不到防范的作用寞忿。還需注意的是驰唬,對數(shù)據(jù)庫有改動的增顶岸、刪腔彰、改操作,需要加 token 驗證辖佣,對于查詢操作霹抛,一定不要加 token,防止攻擊者通過查詢操作獲取 token 進行 CSRF攻擊卷谈。但并不是這樣攻擊者就無法獲得 token杯拐,只是增大攻擊成本而已。

4.結(jié)合后端開發(fā)再次理解token生成過程

在Java的實現(xiàn)中可以有兩種方式世蔗,一種是不借助第三方j(luò)ar端逼,自己生成token,另一種的借助第三方j(luò)ar污淋,傳入自己需要的負荷信息顶滩,生成token。接下來就根據(jù)這兩個逐個說明寸爆。Token的組成就是header.poyload.sign礁鲁。

4.1自己生成token:

headerpoyload的組成都是json字符串,所以先創(chuàng)建頭部的json赁豆,然后用base64編碼(org.apache.axis.encoding.Base64)仅醇,這里選擇的base64要對應(yīng)著編碼和解碼(Base64是一種編碼,也就是說,它是可以被翻譯回原來的樣子來的屎蜓。它并不是一種加密過程)咱揍。然后再創(chuàng)建負荷的json,然后也同樣用base64編碼甲抖,這樣就生成了兩個字符串,然后用.拼接到一起就形成了現(xiàn)在的形式:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0心铃。

在這里只是給大家一個演示准谚,
實際中根據(jù)每個人的負荷參數(shù)的不同,編碼后所生成的字符串也不同去扣。因為沒有借助第三方的jar柱衔,
所有接下來要對上邊拼接成的字符串進行hs256的算法加密生成sign簽名,這里需要自己手動去寫一個類愉棱,然后提供一
個靜態(tài)方法供外界的調(diào)用唆铐。
類的實現(xiàn)代碼如下:

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class HS256 {
public static String returnSign(String message) {
    String hash = "";
    //別人篡改數(shù)據(jù),但是簽名的密匙是在服務(wù)器存儲奔滑,密匙不同艾岂,生成的sign也不同。
    //所以根據(jù)sign的不同就可以知道是否篡改了數(shù)據(jù)朋其。
    String secret = "mystar";//密匙
    try {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(),"HmacSHA256");
        sha256_HMAC.init(secret_key);
        hash = Base64.encodeBase64String(sha256_HMAC.doFinal(message.getBytes()));
        System.out.println(message+"#####"+hash);
    } catch (Exception e) {
        System.out.println("Error");
    }
        return hash;
    }
}

這樣token的三部分就生成了王浴,然后當做參數(shù)傳到前臺脆炎,用cookie或者localstore(推薦)存儲就可以在同一客戶端調(diào)用了。
當從客戶端帶過來token參數(shù)的時候氓辣,直接對頭部和負荷再次調(diào)用加密算法秒裕,看生成的新的簽名和之前的簽名是否一致,判斷數(shù)據(jù)是否被篡改钞啸。

4.2借用第三方的jar(jjwt-0.7.0.jar)生成token:

在這里自己已經(jīng)通過代碼測試几蜻,直接先看代碼:


java后端生成token代碼

調(diào)用這個方法會自動對header和poyload進行base64的編碼,你看過源碼就知道它用的是哪一種体斩,用的是自己jar包自帶的(io.jsonwebtoken.impl.Base64Codec)梭稚,跟自己生成token時,用的base64的jar不一樣絮吵,自己在此列出來:

public static void main(String[] args) {
        // String token = createJWT("11","22","222",11);
        // System.out.println(token);
        JSONObject json_header = new JSONObject();
        json_header.put("typ", "JWT");//類型
        json_header.put("alg", "HS256");//加密算法
        // String header =
        // org.apache.axis.encoding.Base64.encode(json_header.toString().getBytes());
        String header = Base64Codec.BASE64URL.encode(json_header.toString()
                .getBytes());
        String aa = Base64Codec.BASE64URL.decodeToString(header);
        System.out.println(header + "--" + aa);
    }

接著上邊createJWT()方法說哨毁,只要把自己定義的負荷json串當做參數(shù)傳入就行,并且簽名也會對應(yīng)的生成源武,返回一個完整的token扼褪。在測試的過程中,發(fā)現(xiàn)即使自己不定義token的頭部粱栖,也會自動生成header话浇,只是里邊沒有typ這樣的參數(shù)定義,只有HS256闹究,這里源碼里邊幔崖,默認了alg的value。在這里我想說明的是渣淤,假如外界會篡改參數(shù)赏寇,他肯定也知道構(gòu)成,會把負荷里邊的參數(shù)取出來价认,也許會修改嗅定,然后編碼放回去,但是頭部的信息對他來說用處不大用踩,所以自己在這個方法里邊渠退,默認把頭部加上,負荷的值還是自己在調(diào)用的時候傳入進來脐彩。這樣執(zhí)行完碎乃,把生成的token就當做參數(shù)傳到前臺,存儲在cookie里邊惠奸。
然后再說一下梅誓,前臺帶過來token參數(shù)時候,怎么處理,看代碼:

token對比代碼
這個過程的原理跟自己生成token判斷原理一樣梗掰,都是從新生成sign删豺,只是一個是調(diào)用自己的方法,另外一個是調(diào)用第三方的方法愧怜,自己看了源碼(public abstract JwtBuilder signWith(SignatureAlgorithm paramSignatureAlgorithm, String paramString);),沒能單獨把第三方生成sign的方法提出來妈拌,只是一個接口拥坛,但是跟上邊的加密算法實現(xiàn)原理應(yīng)該是基本一致的。

至此尘分,token簽名這一塊的問題大致就先說到這了猜惋,然后再來說一下token過期時間問題。這個相對來說不是太復(fù)雜培愁,可以在負荷里邊多帶一個參數(shù)著摔,把過期時間放進去,其實里邊有一個exp標簽名就是存儲過期時間字段的定续,但是自己在測試過程中谍咆,發(fā)現(xiàn)每次讀出來的都是最原始的時間,自己當時也再花時間去看私股,因為我覺得自己帶參數(shù)其實一個道理摹察。存儲的是時間戳。

存儲:
long nowMillis = System.currentTimeMillis();
long expMillis = nowMillis + 1000*2;//設(shè)置token二秒過期
獲瘸ā:
Date aa = new Date(Long.parseLong(claims.get("aa").toString()));

方式就是這樣了供嚎,我大概列了出來。到時可以存儲一個生成token時間和token過期時間峭状,然后服務(wù)器接收到的時候克滴,可以根據(jù)當前的時間去判斷。當前時間大于token生成時間并且小于token過期時間的情況下优床,繼續(xù)走你接下來的業(yè)務(wù)操作劝赔。

5.token被劫持了,怎樣解決這個安全問題
a胆敞、在存儲的時候把 token 進行對稱加密存儲望忆,用時解開。
b竿秆、將請求 URL启摄、時間戳、token 三者進行合并加鹽簽名幽钢,服務(wù)端校驗有效性歉备。
c、HTTPS 對 URL 進行判斷匪燕。

HTTP 協(xié)議是無狀態(tài)的蕾羊,在web中使用cookie+session的技術(shù)來保持用戶登陸的狀態(tài)
移動端使用token來保持用戶登陸狀態(tài)由于token在網(wǎng)絡(luò)中傳輸喧笔,很容易被中間人獲取,進而模擬用戶進行其他相關(guān)操作

解決辦法:
服務(wù)器端

響應(yīng)頭增加隨機字符串 CSRF_TOKEN=xxxxxxxxxxx(每次請求都不同)

客戶端

客戶端和服務(wù)端 保留密鑰 secret = yyyyyyyyy
客戶端獲取響應(yīng)頭CSRF_TOKEN下次請求必須攜帶
客戶端 (secret+提交內(nèi)容) 進行簽名
當用戶提交信息到服務(wù)器端龟再,首先驗證簽名數(shù)據(jù)是否被篡改书闸,隨后通過token+隨機字符串比對,正確的話執(zhí)行操作利凑,刷新隨機字符串浆劲,即使token被中間人獲取到了,沒有隨機字符串依舊執(zhí)行不了任何操作哀澈,再糟糕點中間人通過攔截響應(yīng)頭獲取到了隨機字符串牌借,但是密鑰還沒泄露,沒有辦法進行簽名依舊執(zhí)行不了操作

缺點:

以上解決辦法只適用于APP端割按,瀏覽器端不適用膨报,因為沒地方保存密鑰

總結(jié):

所以能上 HTTPS 就用 HTTPS 吧!

名稱解釋:

[1] XSS 攻擊:跨站腳本攻擊(Cross Site Scripting)适荣,惡意攻擊者往 Web 頁面里插入惡意 Script 代碼现柠,當用戶瀏覽該頁之時,嵌入其中 Web 里面的 Script 代碼會被執(zhí)行弛矛,從而達到惡意攻擊用戶的目的晒旅。

[2] CSRF 攻擊:CSRF(Cross-site request forgery)跨站請求偽造,也被稱為“One Click Attack”或者 Session Riding汪诉,通撤狭担縮寫為 CSRF 或者 XSRF,是一種對網(wǎng)站的惡意利用扒寄。盡管聽起來像跨站腳本(XSS)鱼鼓,但它與 XSS 非常不同,XSS 利用站點內(nèi)的信任用戶该编,而 CSRF 則通過偽裝來自受信任用戶的請求來利用受信任的網(wǎng)站迄本。與 XSS 攻擊相比,CSRF 攻擊往往不大流行(因此對其進行防范的資源也相當稀少)和難以防范课竣,所以被認為比 XSS 更具危險性嘉赎。

————————————————
如果你覺李俊輝的文章對您有用,請幫忙點個贊或關(guān)注于樟,也為我鼓勵一下公条,堅持寫下去,在此感謝??迂曲!

轉(zhuǎn)載請一定注明出處靶橱!
原文地址:http://www.reibang.com/p/1422374a404b

本文參考鏈接:
https://blog.csdn.net/qq_35246620/article/details/55049812
https://blog.csdn.net/buyaoshuohua1/article/details/73739419?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/weixin_30677617/article/details/101518468?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/weixin_43644324/article/details/87895729

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子关霸,更是在濱河造成了極大的恐慌传黄,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件队寇,死亡現(xiàn)場離奇詭異膘掰,居然都是意外死亡,警方通過查閱死者的電腦和手機佳遣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門识埋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人苍日,你說我怎么就攤上這事〈吧” “怎么了相恃?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長笨觅。 經(jīng)常有香客問我拦耐,道長,這世上最難降的妖魔是什么见剩? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任杀糯,我火速辦了婚禮,結(jié)果婚禮上苍苞,老公的妹妹穿的比我還像新娘固翰。我一直安慰自己,他們只是感情好羹呵,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布骂际。 她就那樣靜靜地躺著,像睡著了一般冈欢。 火紅的嫁衣襯著肌膚如雪歉铝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天凑耻,我揣著相機與錄音太示,去河邊找鬼。 笑死香浩,一個胖子當著我的面吹牛类缤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播邻吭,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼呀非,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起岸裙,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤猖败,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后降允,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恩闻,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年剧董,在試婚紗的時候發(fā)現(xiàn)自己被綠了幢尚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡翅楼,死狀恐怖尉剩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情毅臊,我是刑警寧澤理茎,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站管嬉,受9級特大地震影響皂林,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚯撩,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一础倍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胎挎,春花似錦沟启、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至项栏,卻和暖如春浦辨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沼沈。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工流酬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人列另。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓芽腾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親页衙。 傳聞我的和親對象是個殘疾皇子摊滔,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

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