Spring Security 功能介紹

Posted by Kubeguts on 2020-04-11

Spring Security 功能介紹

先介紹以下常用認證功能

User name / password 基本認證

使用使用者名稱/密碼做驗證

SSO / Okta / LDAP

SSO (Single Sign On)

為OAuth的近一步實現,若已經透過Google取得token, 就可以在其他服務的小網站,都使用Google提供的身份驗證服務

Okta

協助非營利組織的方式。從基本的單一登入(single sign-on,簡稱為 SSO)到進階的身份認證和存取權限的管理方案

LDAP (Lightweight Directory Access Protocol)

為一種輕量的目錄服務協定,像是通訊錄一樣紀錄人員資訊,可以拿來做帳號整合,驗證。

LDAP目錄服務通常有層級結構,像是公司組織階層

OAuth (Intra App Authorization)

OAuth讓用戶可以授權第三方網站存取他們在另外服務提供者(ex: Facebook, Line)的某些特定資訊,而非所有內容。

為什麼有OAuth出現?

因為各個網站都做會員機制很麻煩,且小網站可能有資安風險。

故大網站像是Facebook, Line早已經做好超級安全的會員管理機制,大網站幫你管理個資,提供登入的服務。

但提供這樣服務的大廠越來越多,若小網站同時要提供用戶連結到多個有提供身分服務的大網站會變得很複雜,於是就訂定的工業標準:OAuth.

功能

  • 進入小網站 ->
  • 跳轉到大網站登入畫面 ->
  • 登入成功大網站給予一個有時效的token 給小網站 ->
  • 小網站透過token跟大網站索取用戶的資訊 (這也是為什麼每次登入第三方都會詢問你是否要揭露以下資訊給小網站)

不過一般小網站"無法"直接取得token, 而是取得一個code, 再用這個code向大網站換得一個token
(多這道手續的原因是因為,Internet可能會被路上經手的router或其他設備擷取,偽造,變更)

實際情況

在 Line Login時, Line Notify中,組出一個URL,取得Authorization Code, 這一段取得的Code為明碼, 走的是http get,透過瀏覽器網址列來傳遞 (若沒有用SSL傳遞的話,會被任何人擷取看到).

接下來小網站取得Authorization Code後,在透過http post,從後端跟大網站換得token (因為走後端 大網站就知道小網站的身份和所拿的code)

:::warning
OAuth主要功能是授權,不是認證,所以後來才延伸出OpenID Connect (OIDC)來提供認證用。
:::
:::info
Authentication 檢查發送檢查人的身份是誰、是否合格;
Authorization 則是規範使用者權限的規則,規定哪些能做、哪些不能

因此如果該 Request 未帶 token 或是 token 過期、不合法皆算是 Authentication Error ,跟 http status code 的 401 意思一樣 ;

如果 Request 的 token 認證成功但是該使用者的權限不足以執行該 Request 則是 Forbidden Error (即 因 Authorization 發生的錯誤) ,如 http status code 的 403 意思相同。

:::

:::success
單純用大網站的OAuth當自己的會員系統還是有很大的問題
最明顯的是當使用者同時有Google 與 Facebook的帳號時
兩個帳號上面的Email可能不是一樣的
自己的網站很可能無法辨認這是同一個人的帳戶
所以一般還是會需要自己的會員系統做整合
:::

Microservice security (using tokens, JWT)

JWT (JSON web token):

  • JWT基於JSON的開放標準 (RFC 7519)
  • 被用在身份提供者和服務提供者間傳遞,被認證的用戶身份訊息
  • 可額外增加聲明訊息,該JWT token可以直接被用於認證(Authorization),也可被加密
  • 特別適用於SSO

JWT 與 Session差別:

Session:

由於http協議為stateless,無法知道每次request是誰,但每次request若都要帳號密碼很麻煩

故用戶第一次發Request時,就產生一組token紀錄在db與session, 並將token給用戶,告訴用戶將token存在cookie,當下次發送request時,透過token證明自己身份。

JWT

組成內容有三個部分(Header, Paylaod,Signature)並由. 做區隔,最後透過這三個部分,串成一個 Jwt 字串

Header:

1
2
3
4
{
'typ': 'JWT', # 聲明類型
'alg': 'HS256' # 加密的方法: HMAC、SHA256、RSA 進行 Base64 編碼
}

Payload: 放聲明內容,可以說就是存放溝通訊息的地方

在定義上有 3 種聲明 (Claims)

  • Reserved (註冊聲明)
  • Public (公開聲明)
  • Private (私有聲明)

註冊聲明參數 (建議但不強制使用)

  • iss (Issuer) - jwt簽發者
  • sub (Subject) - jwt所面向的用戶
  • aud (Audience) - 接收jwt的一方
  • exp (Expiration Time) - jwt的過期時間,這個過期時間必須要大於簽發時間
  • nbf (Not Before) - 定義在什麼時間之前,該jwt都是不可用的
  • iat (Issued At) - jwt的簽發時間
  • jti (JWT ID) - jwt的唯一身份標識,主要用來作為一次性token,從而迴避重放攻擊
1
2
3
4
5
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}

Signature: 由三個部分組成

  • header (base64後的)
  • payload (base64後的)
  • secret
1
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), 'secret')

:::warning
secret 要保存在 server 端,jwt 的 簽發驗證都必須使用這個 secret,當其他人得知這個 secret,那就意味著客戶端是可以自我簽發 jwt ,因此在任何場景都不應該外流
:::

最後將 Header, Payload, Signature做base64編碼,組成

使用的時候,在reqeust的header加上 Authorization: Bearer <token>

1
2
3
4
5
post('api/user/1', {
headers: {
'Authorization': 'Bearer ' + token
}
})

JWT 前後端互動示意圖

JWT優點

  • 跨語言,因為 json 格式大部分語言都可使用
  • 可儲存一些簡單但非敏感的商業邏輯 - role …
  • 構成內容簡單,佔用 Size 小方便傳輸
  • !!! 不需在 server 保存 session,所以它易於應用的擴展

Spring Security 教學視頻

Spring Boot + Spring Security + JWT from scratch - Java Brains
https://www.youtube.com/watch?v=X80nJ5T7YpE

參考資源:

Okta 如何協助非營利組織-從 25 個免費的授權開始
https://www.techsoup-taiwan.org.tw/okta

LDAP 簡介
https://poychang.github.io/ldap-introduction/

一次搞懂OAuth與SSO在幹什麼?
http://studyhost.blogspot.com/2017/01/oauthsso.html

GraphQL 設計: Autentication 與 Authorization 大全
https://ithelp.ithome.com.tw/articles/10208278

JSON Web Token(JWT) 簡單介紹
https://mgleon08.github.io/blog/2018/07/16/jwt/

What is Spring Security really all about? Java Brains Brain Bytes

https://www.youtube.com/watch?v=sm-8qfMWEV8&list=PLqq-6Pq4lTTYTEooakHchTGglSvkZAjnE