見令如見人,介紹 JWT

12576 단어 jwtchineseruby
JWT是 JSON Web Tokens 的縮寫.
最近工作上需要用 JWT來互傳資訊,
覺得這東西用起來是滿簡單的.
只是結合多個概念,一開始不是很好懂,紀錄下理解的過程.
最後再介紹利用 jwt 這個 보석.來制作 jwt

TL;박사 01 명


個人觀點,不要打我 이자의를 제거한다
  • 可把 JWT當成 JSON
  • JWT是無法修改的 JSON
  • JWT跟加密無關
  • 參考資料

  • JSON Web Tokens
  • GitHub - jwt/ruby-jwt: A ruby implementation of the RFC 7519 OAuth JSON Web Token (JWT) standard.
  • 왜?


    先不提 JWT怎麼實做的,先想像班上有一對情侶 다스틴跟 수시...

    兩人都是 바보
    所以在教室最後一排的 다스틴要傳紙條給第一排的 서양的時候,
    竟然是用 JSON的格式!
    {
      "from": "Dustin",
      "to": "Suzie",
      "message": "Do you want to have dinner with me tonight?",
      "place": "MacDonald's"
    }
    
    不過傳紙條的過程中,
    班上就是會有人硬要打開不是給他的紙條,
    比如 웨일就是打開紙條並把內容改成
    {
      "from": "Dustin",
      "to": "Erica", //  Will 改了
      "message": "Do you want to have dinner with me tonight?",
      "place": "MacDonald's"
    }
    
    於是不僅當晚 다스틴只能孤零零一個人吃大麥克,
    서양還不理他一個禮拜,悲劇.
    其實一切就是他沒辦法控制發出去的訊息會不會被篡改.
    後來 다스틴記取教訓,
    事先跟 서양約定好一個暗號 NeverEndingStory
    並將訊息用 HMAC SHA-256 搭配 NeverEndingStory 這個暗號製作一串亂碼,

    先直接接受HMAC SHA-256搭配相同的暗號跟訊息,會產出唯一的亂碼


    再把亂碼寫在紙條的最下面
    796e0c718cc2768edfb67a53b0f4fed74b4abbac61baaa68876630d9827714a0
    
    서양打開紙條後即可以用暗號 NeverEndingStory以相同的方式將紙上的訊息轉成亂碼,
    再檢查和紙上附的亂碼是否一致, 就知道訊息是完整且沒被修改過.
    這樣就可以避免再次發生悲劇了.
    可以任意找一個線上的 HMAC SHA256轉換器來驗證 Free HMAC-SHA256 Online Generator Tool | Devglan

    只要訊息跟算出來的亂碼不合,即知道訊息已遭到修改或者不完全.
    所以這樣產生出來的亂碼很常被叫做數位簽名
    JWT就是給 JSON加上一個簽名,確保訊息沒有被任何人動過.
    變得好像可以宣告一個 콘스트的 JSON再傳送出去一樣,

    JWT的組成


    JWT最後的呈現是一串字串,有셋個部分,以 . 分開
  • 수확대:註明是用何種演算法製作簽名的
  • 페이로드:就是實際訊息的 JSON
  • 서명:利用 타이틀註明的演算法用 HMAC方式製作出來簽名
  • 可以到 JSON Web Tokens - jwt.io 製作一個 JWT試試看

    左邊即為製作出來的 JWT
    我想這時已經有人握緊拳頭了...

    聽你鬼扯!
    這個 JWT 看起來根本就只是一串亂碼!
    什麼 JSON 、指定的演算法跑到哪裡去了?


    上面的確是漏說了一些細節 😂
    헤드, 페이로드其實是會先經由 base64去編碼
    base64就是個編碼的方式,可理解成一個可編碼及還原的方法.
    可參考上篇文章


    所以紅色部色就是헤딩紫色部分就是 JSON
    這邊用 루비來試著驗證看看
    header = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'
    payload = 'eyJuYW1lIjoiS2V2aW4ifQ'
    # 用 base64 去解碼,可得到原始內容
    require 'base64'
    puts Base64.urlsafe_decode64(header)
    # {"alg":"HS256","typ":"JWT"}
    puts Base64.urlsafe_decode64(payload)
    # {"name":"Kevin"}
    
    # 用 JWT 的方式,把 header 跟 payload 連起來
    # 用 HMAC SHA256 的方式產生簽名
    require 'openssl'
    mac = OpenSSL::HMAC.hexdigest("SHA256", 'mySecret', "#{header}.#{payload}")
    Base64.urlsafe_encode64(mac).gsub('=', '')  # '=' is just padding
    # "IMa4S4W1LMP1xuKVglwBagrHA5wwK9sBu-CVDKudIkg"
    # 跟網站上產出的一樣喔,表示訊息沒被動過
    
    可能會疑惑怎麼可以直接把 페이로드還原成 JSON
    那 JWT裡的資料不就大辣辣地秀出,這樣不是不安全?
    沒錯...因為 JWT好像變成一串亂碼,容易誤會它很安全,
    其實它跟加密完全沒有關係 이자의를 제거한다
    (加密完全是 TLS也就是 https的事,先忽略吧)

    JWT 主要在乎資料是否被篡改, Signature 是否一致而已


    所以別把敏感的資訊放在裡面.
    我們可以先看實際使用 JWT的程式碼

    데모


    因為我主要用 루비,這邊利用 jwt 這個 보석.來데모
    不過幾乎所有的語言都有實作 jwt
    可在 JSON Web Tokens - jwt.io 查找相關資源.
    require 'jwt'
    
    payload = {
      first_name: 'Kevin',
      last_name: 'Luo'
    }
    
    secret = "my secret"
    
    token = JWT.encode payload, secret, 'HS256'
    # "eyJhbGciOiJIUzI1NiJ9.eyJmaXJzdF9uYW1lIjoiS2V2aW4iLCJsYXN0X25hbWUiOiJMdW8ifQ.dZJnejsQ9cWs1hyOvCAij_Q4k87vfbQpeBIjgqYCrgs"
    
    decoded_token = JWT.decode token, secret, true, { algorithm: 'HS256' }
    # [{"first_name"=>"Kevin", "last_name"=>"Luo"}, {"alg"=>"HS256"}]
    
    此外,JWT的格式RFC其實有約定一些參數可以設定,
    不過端看程式有沒有做對應的處理.
    一個常用的是「到期時間」 exp ,設定一個到期時間給 JWT,假使真的到期,디코딩時即丟出 JWT::ExpiredSignature 這個 예외
    require 'jwt'
    exp = Time.now.to_i + 3600 # 1 hour
    exp_payload = { data: payload, exp: exp }
    
    token = JWT.encode exp_payload, secret, 'HS256'
    # "eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7ImZpcnN0X25hbWUiOiJLZXZpbiIsImxhc3RfbmFtZSI6Ikx1byJ9LCJleHAiOjE2MTM4ODU4MjF9.1_NIKXDnBVz1G6Li7_CZbcDwIk5AFaOsreK7BFDS13Q" 
    
    begin
      decoded_token = JWT.decode token, secret, true, { algorithm: HS256 }
      # [{"data"=>{"first_name"=>"Kevin", "last_name"=>"Luo"}, "exp"=>1613885821}, {"alg"=>"HS256"}] 
    rescue JWT::ExpiredSignature
      # 過期
    end
    

    應用


    JWT除了可以讓 2台有共同 비밀.的電腦可互傳確認不會被篡改的資料外,
    最常見的情境應該就是後端 미국 석유 학회使用者登入後發給前端的 토큰了吧.
    會用 미국 석유 학회的 청원的 타이틀中所帶的 토큰 머니來判斷來源是否可以取用該 미국 석유 학회
    雖然拿 JWT當 토큰 머니因為前端應該是不會有共有的 비밀.
    沒辦法去驗證訊息,所以對前端而言它只是一串亂碼.
    不過我覺得用JWT當 토큰應該有 2個優點:
  • 由於 JWT有不會被篡改特性,서버收到 토큰 머니後,可在裡面直接取用資料,比如說 사용자 id之類的.所以才說見令如見人
  • 不同使用者的 JWT因為 사용자 id不同,必長得不同,而不用是檢查碰撞.如果 토큰 머니是隨機產生,我們還得去檢查是否有碰撞(就是2個使用者運氣好,用到相同的亂數字串)
  • 目前就只用過這 2種應用,但不會改篡改的特性有很多想像空間,不知道其它人曾拿它來做什麼事囉?
    JWT的分享到此囉 : )

    좋은 웹페이지 즐겨찾기