ποΈ[μ€νλ§ μνλ¦¬ν° OAuth2] ν ν° κ²μ¦ ꡬν
1. JCA & JCE
1-1. μκ° λ° κ΅¬μ‘°
β JCA (Java Cryptography Architecture) & JCE (Java Cryptography Extention) μκ°
- μλ°λ JCA & JCE νλ μμν¬ λ₯Ό ν΅ν΄ μ체μ μΈ λ³΄μ κ΄λ ¨ κΈ°λ₯μ μ 곡νκ³ μμΌλ©° μ μμλͺ (Digital Signature), λ©μμ§ λ€μ΄μ μ€νΈ(Message Digest, hashs), μΈμ¦μμ μΈμ¦μ μ ν¨μ± κ²μ¬(Certificate Validation), ν€ μμ± λ° κ΄λ¦¬ κ·Έλ¦¬κ³ λ³΄μ λλ€ μ(Secure Random Number) μμ± λ± νλ μ 보 ν΅μ μνΈ κΈ°μ μ€μμ νμμ μΈ κ²μ λͺ¨λ μ 곡νκ³ μλ€
- JCA & JCE νλ μμν¬λ νλ‘λ°μ΄λ 보μ ꡬ쑰λ₯Ό μ¬μ©νμ¬ λ³΄μκ³Ό κ΄λ ¨ν λ€μν APIλ₯Ό μ 곡νκ³ μλ€
- νλ‘λ°μ΄λλ java.security.Provider ν΄λμ€μ ꡬνμ²΄λ‘ λ³΄μ μκ³ λ¦¬μ¦ κ΅¬ν체 λͺ©λ‘μ ν¬ν¨νκ³ μκ³ μ΄λ₯Ό ν΅ν΄ 보μ μλΉμ€λ₯Ό ꡬνν μ μλ€.
- μλ₯Ό λ€μ΄ νΉμ μκ³ λ¦¬μ¦μ μΈμ€ν΄μ€κ° νμν΄μ§λ©΄, JCA & JCE νλ μμν¬λ νλ‘λ°μ΄λ μ μ₯μμμ ν΄λΉ μκ³ λ¦¬μ¦μ μ ν©ν ꡬν체 ν΄λμ€λ₯Ό μ°Ύμ ν΄λμ€ μΈμ€ν΄μ€λ₯Ό μμ±νλλ° νλ‘λ°μ΄λλ₯Ό μ§μ μ§μ ν μλ μλ€
β MessageDigest
- λ©μμ§ λ€μ΄μ μ€νΈμ λͺ©μ μ μλ³Έ νμΌμ΄ κ·Έλλ‘μΈμ§ νμ νλ λ¬΄κ²°μ± κ²μ¬μ΄λ€.
- λ©μμ§ λ€μ΄μ μ€νΈ μκ³ λ¦¬μ¦μ μ λ ₯ κ°μΌλ‘ μ λ¬λ λ€μν κΈΈμ΄μ μλ³Έ κ°μ κ³ μ κΈΈμ΄ ν΄μ κ°μΌλ‘ μΆλ ₯νλ€.
- μ΄ μκ³ λ¦¬μ¦μ λ¨λ°©ν₯μ΄κΈ° λλ¬Έμ ν΄μ κ°μμ κ±°κΎΈλ‘ μλ³Έ κ°μ λμΆν μ μλ€.
- κ°κ³Ό μμ κ΅μ μν©μμ κ°μ μμκ² μ λ¬νκ³ μ νλ μλ³Έκ³Ό κ·Έ μλ³Έμ λ©μμ§ ν΄μ κ° κ·Έλ¦¬κ³ λ©μμ§ λ€μ΄μ μ€νΈ μκ³ λ¦¬μ¦μ 보λΈλ€.
- μμ κ°μ΄ μ λ¬ν μκ³ λ¦¬μ¦κ³Ό μλ³Έμ κ°μ§κ³ λ©μμ§ ν΄μ κ°μ κ³μ°νλ€.
- μμ΄ κ³μ°ν λ©μμ§ ν΄μ κ°κ³Ό κ°μ΄ μ λ¬ν λ©μμ§ ν΄μ κ°μ΄ μΌμΉνλ©΄, κ°μ΄ μ λ¬ν μλ³Έμ΄ λ€νΈμν¬λ₯Ό ν΅ν΄ μμκ² μ€κΈ°κΉμ§ λ³κ²½λμ§ μμλ€λ κ²μ νμΈν μ μλ€.
β Signature
-
Signatureλ μ΄κΈ°ν μ μ 곡λ°μ ν€λ₯Ό μ¬μ©ν΄μ λ°μ΄ν°λ₯Ό μλͺ νκ³ μ μ μλͺ μ μ ν¨μ±μ κ²μ¦ νλλ° μ¬μ©λλ€.
- μλͺ
- Signature κ°μ²΄λ κ°μΈ ν€λ‘ μλͺ νκΈ° μν΄ μ΄κΈ°νλκ³ μλͺ ν μλ³Έ λ°μ΄ν°κ° μ 곡λλ€.
- Signature μ sign() μ κ°μΈ ν€λ‘ μλ³Έ λ°μ΄ν°λ₯Ό μλͺ νλ©΄ ν΄μλ λ°μ΄ν°λ₯Ό μνΈνν Signature Bytes λ₯Ό λ°ννλ€
- κ²μ¦
- κ²μ¦μ΄ νμν κ²½μ° κ²μ¦μ μν΄ Signatureκ°μ²΄λ₯Ό μμ± λ° μ΄κΈ°ννκ³ κ°μΈν€μ μμ μ΄λ£¨λ ν΄λΉ κ³΅κ° ν€λ₯Ό μ 곡νλ€.
- μλ³Έ λ°μ΄ν°μ Signature Bytes κ° κ²μ¦ Signature κ°μ²΄μ μ λ¬λκ³ verify() λ₯Ό μ€ννλ©΄ 곡κ°ν€λ‘ Signature Bytes μ ν΄μλ°μ΄ν°λ₯Ό μΆμΆνκ³ μλ³Έλ°μ΄ν°λ₯Ό ν΄μν κ°κ³Ό λΉκ΅ν΄μ μΌμΉνλ©΄ Signature κ°μ²΄κ° μ±κ³΅μ λ³΄κ³ νλ€.
- μλͺ μ λ©μμ§ λ€μ΄μ μ€νΈμ λΉλμΉν€ μνΈνκ° κ²°ν©ν ννλ‘μ βSHA256WithRSAβ μ²λΌ λ©μμ§ λ€μ΄μ μ€νΈ μκ³ λ¦¬μ¦μΈ βSHA256βμ μ¬μ©νμ¬ μ΄κΈ°μ λκ·λͺ¨ λ°μ΄ν°λ₯Ό λ³΄λ€ κ΄λ¦¬νκΈ° μ¬μ΄ κ³ μ κΈΈμ΄μ νμμΌλ‘ βμμΆβν λ€μ λΉλμΉν€ μνΈνμΈ βRSAβ μκ³ λ¦¬μ¦μΌλ‘ κ³ μ κΈΈμ΄μ 32λ°μ΄νΈ λ©μμ§ λ€μ΄μ μ€νΈμ μλͺ νλ€
β JCA & JCE ꡬ쑰
- Cipher
- μνΈν λ° λ³΅νΈνμ μ¬μ©λλ μνΈν μνΈμ κΈ°λ₯μ μ 곡νλ€.
- μνΈνλ μΌλ° ν μ€νΈμ ν€ λ₯Ό κ°μ Έμ μνΈνλ λ°μ΄ν°λ₯Ό μμ±νλ νλ‘μΈμ€μ.
-
볡νΈνλ μνΈνλ λ°μ΄ν°μ ν€λ₯Ό κ°μ Έμμ μΌλ° ν μ€νΈλ₯Ό μμ±νλ μ κ³Όμ μ΄λ€.
- Cipher κ°μ²΄ μΈμ€ν΄μ€ννκΈ°
- μΈμ€ν΄μ€ μμ± μ λ³νμ μ§μ νλλ° λ³νμ [μνΈν μκ³ λ¦¬μ¦/νΌλλ°± λͺ¨λ/ν¨λ©] or [μνΈν μκ³ λ¦¬μ¦] μΌλ‘ μ§μ νλ€
- Cipher c1 = Cipher.getInstance(βRSA/ECB/OAEPWithSHA1AndMGF1Paddingβ);
- Cipher c1 = Cipher.getInstance(βRSAβ);
- μΈμ€ν΄μ€ μμ± μ λ³νμ μ§μ νλλ° λ³νμ [μνΈν μκ³ λ¦¬μ¦/νΌλλ°± λͺ¨λ/ν¨λ©] or [μνΈν μκ³ λ¦¬μ¦] μΌλ‘ μ§μ νλ€
- Cipher μ΄κΈ°ννκΈ°
- Cipher κ°μ²΄λ₯Ό μ΄κΈ°ννκΈ° μν΄μ Cipherμ μλ λͺ¨λλ₯Ό λνλ΄λ opmode μ Key λλ μ¦λͺ μ(Certificate) λ₯Ό μΈμλ‘ μ λ¬νκ³ init() λ©μλλ₯Ό μ€ννλ€
- opmode
- ENCRYPT_MODE: cipher κ°μ²΄λ₯Ό μνΈν λͺ¨λλ‘ μ΄κΈ°ννλ€.
- DECRYPT_MODE: cipher κ°μ²΄λ₯Ό 볡νΈν λͺ¨λλ‘ μ΄κΈ°ννλ€.
- Cipher cipher = Cipher.getInstance(βRSAβ);
- cipher.init(Cipher.ENCRYPT_MODE, PrivateKey);
1-2. λμΉν€ & λΉλμΉν€
β λμΉν€ μνΈ(symmetric-key algorithm)
- μνΈν μκ³ λ¦¬μ¦μ ν μ’ λ₯λ‘, μνΈνμ 볡νΈνμ κ°μ μνΈ ν€λ₯Ό μ°λ μκ³ λ¦¬μ¦μ μλ―Ένλ€.
- λμΉ ν€ μνΈμμλ μνΈνλ₯Ό νλ μΈ‘κ³Ό 볡νΈνλ₯Ό νλ μΈ‘μ΄ κ°μ μνΈ ν€λ₯Ό 곡μ ν΄μΌ νλ€.
-
λΉλμΉ ν€ μνΈμμ κ³΅κ° ν€μ λΉλ° ν€λ₯Ό λ³λλ‘ κ°μ§λ κ²κ³Ό ꡬλ³λλ©° λλΆλΆμ λμΉ ν€ μνΈλ λΉλμΉ ν€ μνΈμ λΉκ΅νμ¬ κ³μ° μλκ° λΉ λ₯΄λ€λ μ₯μ μ κ°μ§λ€.
- MAC(Message Authentication Code)
- λ©μμ§ μΈμ¦ μ½λλ λ°μ΄ν°κ° λ³μ‘°(μμ , μμ , μ½μ λ±) λμλμ§λ₯Ό κ²μ¦ν μ μλλ‘ λ°μ΄ν°μ λ§λΆμ΄λ μ½λ
- ν΄μ κ°μ μμ±νλ€λ μ μμ λ©μμ§ λ€μ΄μ μ€νΈμ λΉμ·νμ§λ§, μ΄κΈ°ν μ λΉλ°ν€(SecretKey, λμΉν€)λ₯Ό μꡬνλ€λ μ μμ λ€λ₯΄λ€.
- λ©μμ§ λ€μ΄μ μ€νΈλ λ°μ μΈ‘μ΄ λꡬλ λ¬΄κ²°μ± κ²μ¬κ° κ°λ₯νμ§λ§, MACμ μ€μ§ λμΌν λΉλ° ν€λ₯Ό κ°μ§ μͺ½μμλ§ μ λ¬λ°μ λ©μμ§μ 무결μ±μ κ²μ¬ ν μ μλ€.
- μνΈν ν΄μ ν¨μ(MD5, SHA256 λ±)λ₯Ό κΈ°λ°μΌλ‘ νλ MACμ΄ μ μλ €μ§ HMACμ΄λ€.
- HMACμ λ©μμ§ λ€μ΄μ μ€νΈ μκ³ λ¦¬μ¦κ³Ό 곡μ λ λΉλ° ν€μ μ‘°ν©μΌλ‘ κ°λ₯νλ©° λ°μ΄ν°μ 무결μ±κ³Ό κΈ°λ°μ±, μ‘.μμ μκ° μΈμ¦μ 보μ¦νκΈ° μν μνΈν κΈ°λ²μ΄λ€
β λΉ λμΉν€ μνΈ (asymmetric-key algorithm)
- μνΈν μκ³ λ¦¬μ¦μ ν μ’ λ₯λ‘, μνΈνμ 볡νΈνμ λ€λ₯Έ μνΈ ν€λ₯Ό μ°λ μκ³ λ¦¬μ¦μ μλ―Ένλ€.
- μΈλΆμ μ λ λ
ΈμΆλμ΄μλ μλλ κ°μΈν€(Private key)μ 곡κ°μ μΌλ‘ κ°λ°©λμ΄ μλ 곡κ°ν€(Private key)λ₯Ό μμΌλ‘ μ΄λ£¬ ννμ΄λ€
- Aμ 곡κ°ν€λ₯Ό μ΄μ©νμ¬ μνΈνλ λ°μ΄ν°λ Aμ κ°μΈν€λ‘λ§ λ³΅νΈνκ° κ°λ₯νλ€.
- Aμ κ°μΈν€λ₯Ό μ΄μ©νμ¬ μνΈνλ λ°μ΄ν°λ Aμ 곡κ°ν€λ‘λ§ λ³΅νΈνκ° κ°λ₯νλ€.
- λΉλμΉν€λ₯Ό μ¬μ©νμ¬ λκ°μ§ μνΈνμ λ¬Έμ λ₯Ό ν΄κ²°ν μ μλ€
- λ°μ΄ν° 보μ : μ‘μ μ 곡κ°ν€λ‘ μνΈν -> μ‘μ μ κ°μΈν€λ‘ 볡νΈνλ₯Ό ν΅ν΄ λ°μ΄ν°λ₯Ό μμ νκ² μ μ‘ν μ μλ 보μ κ΄μ
- μΈμ¦ : μ‘μ μ κ°μΈν€λ‘ μνΈν -> μ‘μ μ 곡κ°ν€λ‘ 볡νΈνλ₯Ό ν΅ν΄ λ©μμ§λ₯Ό μΈμ¦(λΆμΈλ°©μ§)νλ κ²μ΄ λͺ©μ
- RSA (Ron Rivest, Adi Shamir, Leonard Adleman μΈ μ¬λμ μ±μ λ°μ RSA λΌκ³ μ΄λ¦μ΄ λΆμ μνΈ λ°©μ)
- νμ¬ SSL/TLSμ κ°μ₯ λ§μ΄ μ¬μ©λλ 곡κ°ν€ μνΈν μκ³ λ¦¬μ¦μΌλ‘ μ μΈκ³ λλΆλΆμ μΈν°λ· λ±
νΉ(λνλ―Όκ΅ ν¬ν¨)μ΄ μ΄ RSA-2048 μνΈνλ₯Ό μ¬μ©νλ€.
- νμ¬ SSL/TLSμ κ°μ₯ λ§μ΄ μ¬μ©λλ 곡κ°ν€ μνΈν μκ³ λ¦¬μ¦μΌλ‘ μ μΈκ³ λλΆλΆμ μΈν°λ· λ±
νΉ(λνλ―Όκ΅ ν¬ν¨)μ΄ μ΄ RSA-2048 μνΈνλ₯Ό μ¬μ©νλ€.
β Key μμ± λͺ¨λΈ
- Key
- JCAμμ μ§μνλ λͺ¨λ μ’ λ₯μ ν€μ λν μ΅μμ μΈν°νμ΄μ€
- Key μΈν°νμ΄μ€λ getAlgorithm(), getEncoded(), getFormat() μ μΈ κ°μ§ λ©μλλ₯Ό μ 곡νλ€
- getAlgorithm() : ν€ μκ³ λ¦¬μ¦μ λ³΄ν΅ λμΉν€ μνΈ λ°©μ(AES,DSA λ±) λλ λΉλμΉν€ μ°μ° μκ³ λ¦¬μ¦(RSA)μ΄λ€.
- getEncoded() : κΈ°λ³Έ μΈμ½λ©λ νμμ ν€λ₯Ό λ°ν
- getFormat() : μ΄ ν€μ κΈ°λ³Έ μΈμ½λ© νμμ μ΄λ¦μ λ°ν(νμ€νμμΈ X509 λλ PKCS8)
- KeyPair
- ν€ μ(κ³΅κ° ν€μ κ°μΈ ν€)μ 보κ΄νκ³ μ κ·Όν μ μλ κΈ°λ₯λ§ μ 곡νλ€
- KeyPairGenerator
- κ³΅κ° λ° κ°μΈ ν€ μμ μμ±νλ λ° μμ ν μλ‘μ΄ κ°μ²΄λ₯Ό μμ±νλ€
- KeyFactory
- μ΄λ€ ν€ λ°μ΄ν° κ°μ²΄λ₯Ό λ€λ₯Έ νμ μ ν€ λ°μ΄ν° κ°μ²΄λ‘ μ ννλλ° μ¬μ©νλ€
β Key κ³μΈ΅ ꡬ쑰
2. JWT (JSON Web Token)
2-1. μκ° λ° νΉμ§
β JOSE (JSON Object Signing and Encryption)
- JSON λ°μ΄ν°μ 컨ν μΈ λ₯Ό μνΈν λλ μλͺ μ ννλ‘ λνλ΄κΈ° μν΄ IETFμμ νμ€ν ν μννΈμ¨μ΄ κΈ°μ μΈνΈ
- κΈ°μ μλ λ€μ μ¬μμ΄ ν¬ν¨λλ€
- JWT (JSON Web Token, RFC7519)
- ν΄λ μ κΈ°λ° λ³΄μ κ°μ λνλ΄λ λ°©λ²μΌλ‘ λ λΉμ¬μ κ°μ μμ νκ² μ λ¬λλ ν΄λ μμ νννκΈ° μν κ°λ°©ν νμ€
- JWTλ μΈμ¦, κΆν λΆμ¬ λ° μ 보 κ΅νμ μ¬μ©λλ€
- JWS λλ JWE λ°©μμΌλ‘ ꡬνλλ€
- JWS (JSON WEB SIGNITURE, RFC 7515)
- JSONμ μ¬μ©νμ¬ λμ§νΈ μλͺ λλ MACμΌλ‘ 보μλ μ½ν μΈ λ₯Ό νννλ λ°©λ²
- JWE (JSON WEB ENCRYPTION, RFC 7516)
- JSONμ μ¬μ©νμ¬ μλν μμ μλ§ μ½μ μ μλλ‘ μνΈνλ λ°μ΄ν°(ν ν°)λ₯Ό λνλ΄λ νμ
- JWK (JSON WEB KEY, RFC 7517)
- HMAC μ΄λ νμ 곑μ λλ RSA μκ³ λ¦¬μ¦μ μ¬μ©νμ¬ κ³΅κ° ν€ μΈνΈλ₯Ό JSON κ°μ²΄λ‘ λνλ΄λ JSON ꡬ쑰
- JWA (JSON WEB ALGORITHM, RFC 7518)
- JWS, JWK λ° JWEμ νμν μκ³ λ¦¬μ¦ λͺ©λ‘μΌλ‘ JWS ν€λ λ° JWS νμ΄λ‘λμ λ΄μ©μ μλͺ νλ λ° μ¬μ©λλ€
- JWT (JSON Web Token, RFC7519)
β JWS ꡬ쑰
- JOSE Header
- μΌλ°μ μΌλ‘ JWTμΈ ν ν° μ νκ³Ό HMAC SHA256 λλ RSA μ κ°μ μλͺ μκ³ λ¦¬μ¦μ λ λΆλΆμΌλ‘ ꡬμ±λλ€
- Base64Url λ‘ μΈμ½λ©λμ΄ JSON μΉ ν ν°μ 첫 λ²μ§Έ λΆλΆμ νμ±νλ€
- Payload (JWT Claim Set)
- ν ν°μ ν¬ν¨ν λ΄μ©μΈ ν΄λ μμ ν¬ν¨νλ νμ΄λ‘λλ‘μ νμ€ νλμΈ 7κ°μ λ±λ‘ ν΄λ μ μ΄λ¦(Registered Claim Names) λ° μ¬μ©μ μ§μ ν΄λ μ λ±μΌλ‘ ꡬμ±νλ€
- Base64Url λ‘ μΈμ½λ©λμ΄ JSON μΉ ν ν°μ λ λ²μ§Έ λΆλΆμ νμ±νλ€
- Signiture
- μλͺ μ Base64url μΈμ½λ©μ μ΄μ©νμ¬ ν€λμ νμ΄λ‘λλ₯Ό μΈμ½λ©νκ³ μ΄ λμ μ (.) ꡬλΆμλ‘ ν¨κ» μ°κ²°μν΄μΌλ‘μ¨ κ³μ°λμ΄ ν ν°μ μμ νκ² νμΈνλ€.
β Claims
- κ°λ
- ν΄λ μ(claim) μ μ£Όμ₯νκ³ μ νλ μ 보λ₯Ό λνλ΄λ κ²μΌλ‘ μ΄ μ 보λ₯Ό λͺ¨λ κ°μ§κ³ μλ λ°λ λΆλΆμ Claim Set μ΄λΌκ³ λΆλ₯Έλ€.
- Claim Setμ ν€ λΆλΆμΈ Claim Nameκ³Ό κ° λΆλΆμΈ Claim Valueμ μ¬λ¬ μμΌλ‘ μ΄λ£¨μ΄μ Έ μλ€.
- JWT μλ μ¬λ¬κ°μ ν΄λ μλ€μ λ£μ μ μλ€
β JWT
β λ°μ΄ν° 무결μ±κ³Ό μ·¨μ½μ
- Payload μ ν΄λ μ κ°μ λ³μ‘°νμ¬ ν ν°μ μμ±ν ν μ λ¬νλλΌλ μλͺ μμ ν΄μλ κ°κ³Ό λ³μ‘°λ κ°μ ν΄μλ κ°μ΄ μλ‘ μΌμΉνμ§ μκΈ° λλ¬Έμ κ²μ¦μ΄ μ€ν¨νμ¬ λ°μ΄ν°μ μμ μ±μ 보μ₯νλ€
- SecretKey λ₯Ό νμ·¨λΉνμ κ²½μ°μλ μ€μν μ λ³΄κ° λλλΉν μ μλ μ·¨μ½μ μ΄ λ°μνκΈ° λλ¬Έμ SecretKey λ₯Ό μ£ΌκΈ°μ μΌλ‘ λ³κ²½νλλ‘ νλ key rotation( key rolling) μ μ± μ΄ νμν μ μλ€
2-2. JWK μ΄ν΄
β JWK κ°λ
- μνΈν ν€λ₯Ό μ μ₯νλ λ°©μμΌλ‘ μΈκ°μλ²μμ λ°ννλ JWT ν ν°μ μνΈν λ° μλͺ μ νμν μνΈν ν€μ λ€μν μ 보λ₯Ό λ΄μ JSON κ°μ²΄ νμ€μ΄λ€
- JwkSetUri μ 보λ₯Ό μ€μ νλ©΄ μΈκ°μλ²λ‘λΆν° JWK ννμ μ 보λ₯Ό λ€μ΄λ‘λν μ μκ³ JWT λ₯Ό κ²μ¦ν μ μλ€.
β JWK ꡬ쑰
β JWK νμ₯
- μλ° νμ€ λ³΄μ ν΄λμ€λ₯Ό μ¬μ©νμ¬ λμΉν€, λΉλμΉν€ λ°©μμ JWT μ μνΈν λ° μ μμλͺ , μ΄ν κ²μ¦μ μν ν€ μμ±, λ³ν λ±μ μ§μνλ€
- ꡬν체λ‘μ RSAKey, OctetSequenceKey, ECKey, OctetKeyPair κ° μλ€
β JWKGenerator
- μνΈν μκ³ λ¦¬μ¦ λ°©μμ λ°λΌ JWK μ ꡬνμ²΄κ° μκ³ κ° κ΅¬ν체λ₯Ό νΈλ¦¬νκ² μμ±ν μ μλ μ λλ μ΄ν° ν΄λμ€μ΄λ€
- RSAKeyGenerator β λΉλμΉ μνΈν μκ³ λ¦¬μ¦ ν€λ₯Ό ν¬ν¨νλ JWK μμ±κΈ°
- OctetSequenceKeyGenerator - λμΉ μνΈν μκ³ λ¦¬μ¦ ν€λ₯Ό ν¬ν¨νλ JWK μμ±κΈ°
- EcKeyGenerator - νμ곑μ μνΈν μκ³ λ¦¬μ¦ ν€ ν¬ν¨νλ JWK μμ±κΈ°
3. OAuth2 MAC & RSA κ²μ¦
3-1. κΈ°λ³Έ νκ²½ λ° κ³΅ν΅ ν΄λμ€ κ΅¬μ±
β ν ν° κ²μ¦ λ°©λ²
-
ν ν° κ²μ¦μ λν λ€μν μΌμ΄μ€μ ν μ€νΈλ₯Ό μν΄ λ κ°μ§ λ°©μμΌλ‘ ν ν° λ°ν λ° κ²μ¦μ μ§ννλλ‘ νλ€.
β μνΈν μκ³ λ¦¬μ¦ λ°©μμ λ°λΌ μ§μ λ°νν JWT ν ν°μ λμμΌλ‘ κ²μ¦μ μ§ννλ€
β‘ μΈκ° μλ²μμ λ°νν Access Token μ λμμΌλ‘ κ²μ¦μ μ§ννλ€β JwtDecoder λΉμ μνΈν μκ³ λ¦¬μ¦ λ° νΉμ ν 쑰건μ λ°λΌ κ° μμ±λλ©° λμ½λ©μ΄ μ§νλλ©΄ μ£Όμ΄μ§ μκ³ λ¦¬μ¦μ μν΄ κ²μ¦νκ² λλ€
β ν ν° κ²μ¦ ν μ€νΈ
- MAC λ°©μμ μν κ²μ¦ ν
μ€νΈ
β μ체 ν ν° λ°ν λ° κ²μ¦
β‘ SecretKey μ€μ μ μν κ²μ¦ - RSA λ°©μμ μν κ²μ¦ ν
μ€νΈ
β μ체 ν ν° λ°ν λ° κ²μ¦
β‘ JwtDecoder μ μν κ²μ¦
β’ KeyStore ν΄μ μν κ²μ¦
β£ JwkSetUri μ€μ μ μν κ²μ¦
β ν¨ν€μ§ ꡬμ±
- io.oauth2.resourceserver.configs β μ€μ ν΄λμ€
- Io.oauth2.resourceserver.filter.authentication β μΈμ¦νν°(ν ν° λ°ν λ΄λΉ)
- Io.oauth2.resourceserver.filter.authorization β μΈκ°νν°(ν ν° κ²μ¦ λ΄λΉ)
- Io.oauth2.resourceserver.signature β ν ν° μλͺ λ° λ°ν
- Io.oauth2.resourceserver.controller β 컨νΈλ‘€λ¬
- io.oauth2.resourceserver.dto β μμ² νλΌλ―Έν° κ°μ²΄
- io.oauth2.resourceserver.init β μ΄κΈ°ν μμ
β κΈ°λ³Έ ν΄λμ€ μμ±
- OAuth2ResourceServer β 리μμ€ μλ² μ€μ ν΄λμ€
- IndexController β 컨νΈλ‘€λ¬
β νκ²½μ€μ
- application.yml
β μμ‘΄μ± μΆκ°
- gradle
β SignatureConfig
- μλͺ κ³Ό κ²μ¦, MAC λ° RSA μνΈν JWK λ±μ λΉλ€μ μμ±νλ μ€μ ν΄λμ€
β JwtAuthenticationFilter
- μΈκ°μλ²λ₯Ό λμ νμ¬ ν ν°μ λ°ννλ 컀μ€ν νν°λ‘μ UsernamePasswordAuthenticationFilter λ₯Ό μμνλ€
- POST /login μμ²μ λν΄ μΈμ¦ μ²λ¦¬λ₯Ό λ΄λΉνλ€
- μΈμ¦μ μ±κ³΅νκ² λλ©΄ SecuritySigner λ₯Ό νΈμΆν΄μ JWT ν ν°μ μμ±νκ³ ν΄λΌμ΄μΈνΈμκ² μλ΅νλ€
- MAC κ³Ό RSA μ μλͺ λ° μΈμ¦μ 곡ν΅μΌλ‘ μ¬μ©νλ νν°
β SecuritySigner
- MAC λ° RSA μνΈν λ°©μμ λ°λΌ ν ν°μ λ°ννλ μΆμ ν΄λμ€
3-2. MAC κ²μ¦ κΈ°λ₯ ꡬν
3-2-1. JwtAuthorizationMacFilter μ μν κ²μ¦
β OAuth2ResourceServer
@Bean //리μμ€ μλ² μ€μ ν΄λμ€λ‘μ MAC μΈμ¦ λ° μΈκ° μ²λ¦¬ μ€μ μ νλ€
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests((requests) -> requests.antMatchers("/login","/").permitAll().anyRequest().authenticated());
http.userDetailsService(getUserDetailsService());
http.addFilterBefore(jwtAuthenticationFilter(macSecuritySigner, octetSequenceKey), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(jwtAuthorizationMacFilter(octetSequenceKey), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
β JwtAuthorizationMacFilter
- Bearer ν ν°μ MAC μκ³ λ¦¬μ¦μ μν΄ κ²μ¦νλ©° κ²μ¦ μ±κ³΅μ μΈμ¦ λ° μΈκ°λ₯Ό μ²λ¦¬νλ νν°
β MacSecuritySinger
- SecuritySigner μ μμλ°μΌλ©° MAC κΈ°λ° μλͺ λ° ν ν°μ λ°ννλ ν΄λμ€
3-2-2. JwtDecoder μ μν κ²μ¦
β JwtDecoderConfig
- SecretKey κΈ°λ° JwtDecoder μμ±
- λμΉν€ λ°©μμΌλ‘ μμ±λ ν ν°μ κ²μ¦νκΈ° μν΄ JWK λ₯Ό μμν OctetSequenceKey λ‘ SecretKey κΈ°λ° JwtDecoder λ₯Ό μμ±νλ€
@Bean
@ConditionalOnProperty(prefix = "spring.security.oauth2.resourceserver.jwt", name = "jws-algorithms", havingValue = "HS256", matchIfMissing = false)
public JwtDecoder jwtDecoderBySecretKeyValue(OctetSequenceKey octetSequenceKey,OAuth2ResourceServerProperties properties) {
return NimbusJwtDecoder.withSecretKey(octetSequenceKey.toSecretKey())
.macAlgorithm(MacAlgorithm.from(properties.getJwt().getJwsAlgorithms().get(0)))
.build();
}
β application.yml
spring:
security:
oauth2:
resourceserver:
jwt:
jws-algorithms: HS256
3-3. RSA κ²μ¦ κΈ°λ₯ ꡬν
3-3-1. JwtAuthorizationRsaFilter μ μν κ²μ¦
β OAuth2ResourceServer
@Bean //리μμ€ μλ² μ€μ ν΄λμ€λ‘μ MAC μΈμ¦ λ° μΈκ° μ²λ¦¬ μ€μ μ νλ€
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests((requests) -> requests.antMatchers("/").permitAll().anyRequest().authenticated());
http.userDetailsService(getUserDetailsService());
http.addFilterBefore(jwtAuthenticationFilter(rsaSecuritySigner, rsaKey), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(jwtAuthorizationRsaFilter(rsaKey), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
β JwtAuthorizationRsaFilter
- Bearer ν ν°μ RSA μκ³ λ¦¬μ¦μ μν΄ κ²μ¦νλ©° κ²μ¦ μ±κ³΅μ μΈμ¦ λ° μΈκ°λ₯Ό μ²λ¦¬νλ νν°
β RsaSecuritySinger
- SecuritySigner μ μμλ°μΌλ©° RSA κΈ°λ° μλͺ λ° ν ν°μ λ°ννλ ν΄λμ€
3-3-2. JwtDecoder μ μν κ²μ¦
β JwtDecoderConfig
- PublicKey κΈ°λ° JwtDecoder μμ±
- λΉλμΉν€ λ°©μμΌλ‘ μμ±λ ν ν°μ κ²μ¦νκΈ° μν΄ JWK λ₯Ό μμν RSAKey λ‘ PublicKey κΈ°λ° JwtDecoder λ₯Ό μμ±νλ€
@Bean
@ConditionalOnProperty(prefix = "spring.security.oauth2.resourceserver.jwt", name = "jws-algorithms", havingValue = "RS512", matchIfMissing = false)
public JwtDecoder jwtDecoderByPublicKeyValue(RSAKey rsaKey, OAuth2ResourceServerProperties properties) throws JOSEException {
return NimbusJwtDecoder.withPublicKey(rsaKey.toRSAPublicKey())
.signatureAlgorithm(SignatureAlgorithm.from(properties.getJwt().getJwsAlgorithms().get(0)))
.build();
}
β application.yml
spring:
security:
oauth2:
resourceserver:
jwt:
jws-algorithms: RS512
3-3-3. KeyStore μ μν κ²μ¦
β KeyStore ν΄λμ€
- Java λ KeyStore λΌλ μΈν°νμ΄μ€λ₯Ό ν΅ν΄ μνΈν/볡νΈν λ° μ μ μλͺ μ μ¬μ©λλ Private Key, Public Key μ Certificate λ₯Ό μΆμννμ¬ μ 곡νκ³ μλ€
- KeyStore μλ SecretKey, Private Key, Public Key, Certificate μ κ°μ 보μ νμΌλ€μ΄ μ μ₯λλ©° KeyStore λ νμΌ μμ€ν μ μ μ₯νκ³ μνΈλ‘ 보νΈν μ μλ€
- KeyStore λ keytool μ¬μ©ν΄μ μμ±ν μ μμΌλ©° κΈ°λ³Έ νμ μ jks μ΄λ€
β keytool
- keytool μ μλ°μμ μ 곡νλ μ νΈλ¦¬ν°λ‘ KeyStore κΈ°λ°μΌλ‘ μΈμ¦μμ ν€λ₯Ό κ΄λ¦¬ν μ μμΌλ©° JDK μ ν¬ν¨λμ΄ μλ€.
- C:\Program Files\Java\jdk-11.0.11\bin\keytool.exe
- Keystore μμ± ν PrivateKey, PublicKey, Certificate μμ±
- Private key μμ± : keytool -genkeypair -alias apiKey -keyalg RSA -keypass βpass1234β -keystore apiKey.jks -storepass βpass1234β
- Certificate μμ± : keytool -export -alias apiKey -keystore apiKey.jks -rfc -file trustServer.cer
- Public key μμ± : keytool -import -alias trustServer -file trustServer.cer -keystore publicKey.jks
β μμ
- KeyStore μ κ°μ²΄λ₯Ό μ»λλ€
- keytool μ ν΅ν΄ μ»μ apiKey.jks νμΌμ μ½μ΄μ€λ©΄ ν€μ μΈμ¦μλ₯Ό κ°μ Έ μ¬ μ μμΌλ©° μ¬κΈ°μλ κ°μΈν€μ μΈμ¦μ, 곡κ°ν€ μ 보λ₯Ό λ΄κ³ μλ€
- KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()) // κΈ°λ³Έ νμ μ .jks( java key store)
- keystore.load(new FileInputStream(β/certs/apiKey.jks)β, keystorepassword.toCharArray()); // κΈ°μ‘΄ ν€ μ μ₯μλ₯Ό load νλ€
- keytool μ ν΅ν΄ μ»μ apiKey.jks νμΌμ μ½μ΄μ€λ©΄ ν€μ μΈμ¦μλ₯Ό κ°μ Έ μ¬ μ μμΌλ©° μ¬κΈ°μλ κ°μΈν€μ μΈμ¦μ, 곡κ°ν€ μ 보λ₯Ό λ΄κ³ μλ€
- κ°μΈ ν€λ₯Ό μ»λλ€
- PrivateKey key = (PrivateKey) keystore.getKey(alias, βtest1234β.toCharArray());
- μΈμ¦μλ₯Ό μ»λλ€
- Certificate certificate = keystore.getCertificate(alias);
- μΈμ¦μλ‘λΆν° κ³΅κ° ν€λ₯Ό μ»κ³ Base64 λ‘ μΈμ½λ©ν λ€μ λ¬Έμμ΄μ λ³ννλ€
- PublicKey publicKey = certificate.getPublicKey();
- String publicStr = java.util.Base64.getMimeEncoder().encodeToString(publicKey.getEncoded());
- μΈμ½λ©λ κ³΅κ° ν€ λ¬Έμμ΄μ txt νμΌλ‘ μ μ₯νλ€
- OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(β/certs/publicKey.txtβ), Charset.defaultCharset());
- writer.write(publicStr);
- writer.close();
β JwtDecoderConfig
@Bean
@Conditional(KeyValueCondition.class)
JwtDecoder jwtDecoderByPublicKeyValue() throws Exception {
RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(getKeySpec(this.properties.readPublicKey())));
NimbusJwtDecoder jwtDecoder =
NimbusJwtDecoder.withPublicKey(publicKey).signatureAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
jwtDecoder.setJwtValidator(getValidators(JwtValidators::createDefault));
return jwtDecoder;
}
β OAuth2ResourceServer
- 리μμ€ μλ² μ€μ ν΄λμ€λ‘μ KeyStore μμ μΆμΆν PublicKey μ μν΄ RSA μΈμ¦ λ° μΈκ° μ²λ¦¬ μ€μ μ νλ€
β RsaPublicKeySecuritySigner
- SecuritySigner μ μμλ°μΌλ©° RSA μνΈν λ°©μμ μλͺ λ° ν ν° λ°ν
β RsaKeyExtractor
- apiKey.jks λ‘ λΆν° PrivateKey μ PublicKey λ₯Ό μΆμΆνκ³ νμΌμ μ μ₯νλ ν΄λμ€
3-3-4. JwkSetUri μ μν κ²μ¦
β SecurityJwkSetUriResourceServerConfig
@Bean
@ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
JwtDecoder jwtDecoderByJwkKeySetUri() {
NimbusJwtDecoder nimbusJwtDecoder =
NimbusJwtDecoder.withJwkSetUri(this.properties.getJwkSetUri()).jwsAlgorithm(SignatureAlgorithm.from(this.properties.getJwsAlgorithm())).build();
String issuerUri = this.properties.getIssuerUri();
Supplier<OAuth2TokenValidator<Jwt>> defaultValidator = (issuerUri != null) ? () -> JwtValidators.createDefaultWithIssuer(issuerUri) : JwtValidators::createDefault;
nimbusJwtDecoder.setJwtValidator(getValidators(defaultValidator));
return nimbusJwtDecoder;
}
β OAuth2ResourceServer
- 리μμ€ μλ² μ€μ ν΄λμ€λ‘μ μΈκ°μλ² μλν¬μΈνΈμΈ JwkSetUri λ°©μμ μν RSA μΈμ¦ λ° μΈκ° μ²λ¦¬ μ€μ μ νλ€
4. Authentication / @AuthenticationPrincipal
β Authentication
- 리μμ€ μλ²μμ ν ν° κ²μ¦μ΄ μ΄λ£¨μ΄μ§λ©΄ ν ν°μΌλ‘ λΆν° μ 보λ₯Ό μΆμΆν΄μ μΈμ¦κ°μ²΄λ₯Ό ꡬμ±νκ² λλ€
- μ€νλ§ μν리ν°μ μμμ λν μ κ·Όμ μΈμ¦κ°μ²΄μ μΈμ¦ μ 무μ κΆνμ 보μ λ°λΌ κ²°μ λκΈ° λλ¬Έμ μΈμ¦κ°μ²΄λ₯Ό μμ±ν΄μΌ νλ€
- μΈμ¦ κ°μ²΄λ JwtAuthenticationToken νμ μΌλ‘ μμ±λκ³ SecurityContext μ μ μ₯νλ€
β Jwt
- JwtDecoder λ κ²μ¦μ΄ μ±κ³΅νλ©΄ ν ν°μ ν΄λ μμΌλ‘λΆν° μ 보λ₯Ό μΆμΆν΄μ μ΅μ’ Jwt κ°μ²΄λ₯Ό λ°ννλ€
- Jwt κ°μ²΄λ JwtAuthenticationToken μ principal μμ±μ μ μ₯λλ€
β @AuthenticationPrincipal
- JwtAuthenticationToken μ principal μ μ μ₯λμ΄ μλ Jwt κ°μ²΄λ₯Ό λ°λ‘ μ°Έμ‘°ν μ μλ€
λκΈλ¨κΈ°κΈ°