๐Ÿ“Œ [JWT ์ธ์ฆ ์‹œ์Šคํ…œ ์‹œ๋ฆฌ์ฆˆ - 3ํŽธ] Signature ์—”ํ‹ฐํ‹ฐ์™€ JWT ์„œ๋ช… ํ‚ค ์ž๋™ ๊ฐฑ์‹  ๊ตฌ์กฐ

My Pale Blue Dotยท2025๋…„ 5์›” 20์ผ
0

SPRING BOOT

๋ชฉ๋ก ๋ณด๊ธฐ
38/40
post-thumbnail

๐Ÿ“… ๋‚ ์งœ

2025-05-20


๐Ÿ“ ํ•™์Šต ๋‚ด์šฉ

1๏ธโƒฃ ์™œ JWT ์„œ๋ช… ํ‚ค(Signature)๋ฅผ DB์— ์ €์žฅํ•ด์•ผ ํ• ๊นŒ?

JWT๋Š” ์„œ๋ฒ„๊ฐ€ ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋ช… ํ‚ค(Key)๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์„œ๋ฒ„๋ฅผ ์žฌ์‹œ์ž‘ํ•  ๋•Œ๋งˆ๋‹ค ํ‚ค๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋˜๋ฉด, ๊ธฐ์กด์— ๋ฐœ๊ธ‰ํ•œ ํ† ํฐ์€ ๋ชจ๋‘ ๊ฒ€์ฆ ์‹คํŒจํ•˜๊ฒŒ ๋œ๋‹ค.

๊ทธ๋ž˜์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ์„ค๊ณ„ํ–ˆ๋‹ค:

  • Signature ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ†ตํ•ด ํ‚ค๋ฅผ DB์— ์˜์†ํ™”
  • ์„œ๋ฒ„ ์‹œ์ž‘ ์‹œ ๊ธฐ์กด ํ‚ค ๋ถˆ๋Ÿฌ์˜ค๊ธฐ, ์—†์œผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑ
  • SignatureScheduling์„ ํ†ตํ•ด ์ฃผ๊ธฐ์  ํ‚ค ๊ฐฑ์‹ 
  • JwtTokenProvider.setKey()๋ฅผ ์ด์šฉํ•œ ์‹ค์‹œ๊ฐ„ ํ‚ค ๋ฐ˜์˜

2๏ธโƒฃ Signature ์—”ํ‹ฐํ‹ฐ

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Signature {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // ๊ธฐ๋ณธ ํ‚ค๋Š” Long ํƒ€์ž… ์‚ฌ์šฉ
    private Long id;

    @Column(name = "keyBytes", nullable = false)
    private byte[] keyBytes;

    @Column(name = "createAt", nullable = false)
    private LocalDate createAt;
}

๐Ÿ“Œ ๋ณด์™„์  ๋ฐ˜์˜:

  • @Id๋กœ byte[] ๋Œ€์‹  Long ์‚ฌ์šฉ โ†’ JPA ํ˜ธํ™˜์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ
  • keyBytes๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•ด JWT ์„œ๋ช…์šฉ ํ‚ค๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

3๏ธโƒฃ SignatureRepository

@Repository
public interface SignatureRepository extends JpaRepository<Signature, Long> {
}

๐Ÿ“Œ ์ด์ „ ๋ฒ„์ „์—์„œ๋Š” org.springframework.security.web.webauthn.api.Bytes๋ฅผ ID๋กœ ์‚ฌ์šฉํ•ด ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ

โžก๏ธ Long ๊ธฐ๋ณธ ํ‚ค ํƒ€์ž…์œผ๋กœ ๊ต์ฒดํ•˜์—ฌ ์•ˆ์ •์„ฑ ํ™•๋ณด


4๏ธโƒฃ SignatureScheduling โ€“ ํ‚ค ์ž๋™ ๊ฐฑ์‹  (๋งค ์‹œ ์ •๊ฐ)

@Component
@EnableScheduling
public class SignatureScheduling {

    @Autowired
    private SignatureRepository signatureRepository;

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    // ๋งค ์‹œ ์ •๊ฐ๋งˆ๋‹ค ์‹คํ–‰
    @Scheduled(cron = "0 0 * * * *")
    public void signatureScheduled(){
        List<Signature> list = signatureRepository.findAll();

        // ๊ธฐ์กด ํ‚ค ์‚ญ์ œ
        if(!list.isEmpty()){
            signatureRepository.deleteAll();
        }

        // ์ƒˆ ํ‚ค ์ƒ์„ฑ ๋ฐ ์ €์žฅ
        byte[] keyBytes = KeyGenerator.getKeygen();
        Signature newSignature = Signature.builder()
                .keyBytes(keyBytes)
                .createAt(LocalDate.now())
                .build();
        signatureRepository.save(newSignature);

        // JwtTokenProvider์— ์ƒˆ ํ‚ค ๋ฐ˜์˜
        jwtTokenProvider.setKey(Keys.hmacShaKeyFor(keyBytes));
    }
}

5๏ธโƒฃ JwtTokenProvider์™€ Signature ์—ฐ๋™ ๊ตฌ์กฐ

  • ์„œ๋ฒ„๊ฐ€ ์‹œ์ž‘๋˜๋ฉด @PostConstruct๋กœ Signature ํ…Œ์ด๋ธ”์—์„œ ํ‚ค๋ฅผ ๋กœ๋“œ
  • Signature๊ฐ€ ์—†์œผ๋ฉด ํ‚ค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•ด ์ €์žฅ
  • SignatureScheduling์ด ํ‚ค๋ฅผ ์ƒˆ๋กœ ๋ฐœ๊ธ‰ํ•˜๋ฉด, setKey()๋กœ ์‹ค์‹œ๊ฐ„ ๋ฐ˜์˜

๐Ÿ”ฅ ์ •๋ฆฌ

๊ตฌ์„ฑ์š”์†Œ์—ญํ• 
SignatureJWT ์„œ๋ช… ํ‚ค๋ฅผ DB์— ์ €์žฅ
SignatureRepositoryํ‚ค ์ €์žฅ์†Œ ๊ด€๋ฆฌ (Long ๊ธฐ๋ฐ˜ ID๋กœ ์•ˆ์ •์„ฑ ํ™•๋ณด)
SignatureScheduling1์‹œ๊ฐ„๋งˆ๋‹ค ํ‚ค๋ฅผ ์ž๋™ ๊ฐฑ์‹ 
JwtTokenProvider.setKey()๋Ÿฐํƒ€์ž„ ์ค‘ ์ƒˆ ํ‚ค๋กœ JWT ๊ธฐ๋Šฅ ์‹ค์‹œ๊ฐ„ ์ „ํ™˜

๐Ÿ”— ์ฐธ๊ณ  ์ž๋ฃŒ


๐Ÿง  ๋А๋‚€ ์ 

  • JWT ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ์—์„œ ํ‚ค ๊ด€๋ฆฌ๋Š” ๋‹จ์ˆœ ์„ค์ • ์ด์ƒ์˜ ๋ณด์•ˆ ํ•ต์‹ฌ ์š”์†Œ๋ผ๋Š” ๊ฑธ ๋А๊ผˆ๋‹ค.
  • JPA์—์„œ byte[]๋ฅผ ID๋กœ ์“ฐ๋Š” ๊ฒƒ๋ณด๋‹ค Long์„ ์“ฐ๋Š” ๊ฒŒ ํ›จ์”ฌ ์•ˆ์ •์ ์ด๊ณ  ํ˜ธํ™˜์„ฑ๋„ ์ข‹๋‹ค.
  • ํ‚ค๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์€ ์šด์˜ ์ค‘ ํ‚ค ํšŒ์ „(Key Rotation) ์ „๋žต๊นŒ์ง€ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์—ฌ์„œ ํ™•์žฅ์„ฑ์ด ์ข‹๋‹ค.

โœ… ์š”์•ฝ

  • JWT ์„œ๋ช… ํ‚ค๋ฅผ Signature ์—”ํ‹ฐํ‹ฐ์— ์ €์žฅํ•ด ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ํ›„์—๋„ ๊ธฐ์กด ํ† ํฐ์„ ๊ฒ€์ฆ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ–ˆ๋‹ค.
  • SignatureScheduling์„ ํ†ตํ•ด ํ‚ค๋ฅผ ์ฃผ๊ธฐ์ ์œผ๋กœ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ–ˆ๊ณ ,
  • ์ด๋ฅผ ํ†ตํ•ด ๋ณด์•ˆ์„ฑ๊ณผ ์œ ํšจ์„ฑ ๊ด€๋ฆฌ๋ฅผ ๋ชจ๋‘ ๋งŒ์กฑ์‹œํ‚ค๋Š” ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.

profile
Here, My Pale Blue.๐ŸŒ

0๊ฐœ์˜ ๋Œ“๊ธ€