JWT란?

2020/10/02 - [IT/기타] - [JWT] Json Web Token이란?

 

1. jjwt란?

jjwt는 JWT 토큰 생성JWT 토큰 파싱, 검증을 해주는 라이브러리 입니다.

 

2. Maven dependency 추가

...
    <dependencies>
        ...
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        ...
    </dependencies>
...

 

3. 예제

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.Jwts;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class TestJWT {
    final String key = "Bamdule";

    public static void main(String[] args) throws UnsupportedEncodingException {
        TestJWT testJWT = new TestJWT();

        String jwt = testJWT.createToken();
        System.out.println(jwt);
        
        Map<String, Object> claimMap = testJWT.verifyJWT(jwt);
        System.out.println(claimMap); // 토큰이 만료되었거나 문제가있으면 null
    }
        
    //토큰 생성
    public String createToken() {

        //Header 부분 설정
        Map<String, Object> headers = new HashMap<>();
        headers.put("typ", "JWT");
        headers.put("alg", "HS256");

        //payload 부분 설정
        Map<String, Object> payloads = new HashMap<>();
        payloads.put("data", "My First JWT !!");

        Long expiredTime = 1000 * 60L * 60L * 2L; // 토큰 유효 시간 (2시간)

        Date ext = new Date(); // 토큰 만료 시간
        ext.setTime(ext.getTime() + expiredTime);
     
        // 토큰 Builder
        String jwt = Jwts.builder()
                .setHeader(headers) // Headers 설정
                .setClaims(payloads) // Claims 설정
                .setSubject("user") // 토큰 용도 
                .setExpiration(ext) // 토큰 만료 시간 설정
                .signWith(SignatureAlgorithm.HS256, key.getBytes()) // HS256과 Key로 Sign
                .compact(); // 토큰 생성

        return jwt;
    }
    
    //토큰 검증
    public Map<String, Object> verifyJWT(String jwt) throws UnsupportedEncodingException {
        Map<String, Object> claimMap = null;
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(key.getBytes("UTF-8")) // Set Key
                    .parseClaimsJws(jwt) // 파싱 및 검증, 실패 시 에러
                    .getBody();

            claimMap = claims;

            //Date expiration = claims.get("exp", Date.class);
            //String data = claims.get("data", String.class);
            
        } catch (ExpiredJwtException e) { // 토큰이 만료되었을 경우
            System.out.println(e);
            ...
        } catch (Exception e) { // 그외 에러났을 경우
            System.out.println(e);
            ...
        }
        return claimMap;
    }    
}

 

4. 결과

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiZGF0YSI6Ik15IEZpcnN0IEpXVCAhISIsImV4cCI6MTU5NzIxNDQzM30.a51SU-jC5OgvX2JgiNShQziKDcO_ARLGBpsnbwbBxqs


{sub=user, data=My First JWT !!, exp=1597145971}

 

1) 토큰 만료 시 출력되는 메시지

io.jsonwebtoken.ExpiredJwtException: JWT expired at 2020-08-12T15:40:33Z. Current time: 2020-08-12T15:40:34Z, a difference of 1388 milliseconds. Allowed clock skew: 0 milliseconds.

 

1. CSRF (Cross-site request forgery, CSRF,XSRF)

웹사이트 취약점 공격의 하나로, 사용자가 자신의 의지와는 무관하게 공격자가 의도한(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격을 말한다.

공격 과정

1. 공격자는 CSRF 공격할 웹사이트를 미리 분석하여, 특정 정보를 등록하거나 변경할 수 있는 URI를 찾아낸다.

그리고 공격자는 해당 URI를 이용해 공격자가 원하는 작업을 수행하는 피싱 사이트를 만들어 이용자가 접근하도록 유도한다.

2. 사용자가 피싱 사이트 링크를 클릭하게 되면 자신의 의도와 무관하게 특정 작업을 실행한다. 이때 사용자가 로그인 한 상태라면 쿠키를 통해 서버에 본인확인을 하기 때문에 서버는 사용자가 의도한 작업인지 아닌지 확인 할 수 없다.

 

'IT > WEB' 카테고리의 다른 글

[CSS] CSS 변수 사용하기  (0) 2021.01.24
[WEB] RESTful 이란?  (0) 2020.10.06
[WEB] HTTP의 특징과 HTTP Message  (0) 2020.07.30

1. 인터넷(Internet)이란?

TCP/IP 기반의 네트워크가 전세계적으로 확대되어 하나로 연결된 거대한 네트워크를 의미한다.

2. WWW란?

World Wide Web의 약자로 인터넷을 통해 연결된 웹페이지 시스템을 의미한다.

WWW의 구성요소

  • HTTP protocol
  • URL, URI
  • HTML

3. HTTP(Hypertext Transfer Protocol)란?

클라이언트(웹 브라우저)와 서버 간 통신 규약이다.
즉 서버로부터 HTML문서, 이미지, 텍스트 등 여러 리소스들을 요청할 수 있도록 해주는 프로토콜을 의미한다.

1) 특징

비연결성 지향(Conectionless)
클라이언트와 서버간 통신이 끝나면 연결을 끊는다.

무상태(Stateless)
연결이 끊기는 순간 클라이언트와 서버간 상태정보를 보관하지 않는다.

2) 장단점

장점
* 불특정 다수를 대상으로 하는 서비스에 적합하다.
* 클라이언트와 서버간 연결을 유지하지 않아서 서버에 부하가 적다. 그래서 많은 유저들이 서비스를 이용할 수 있다.

단점
* 클라이언트와 서버간 연결이 끝나면 연결을 끊어버리기 때문에 이전 상황을 알기 힘들다.
* 접근한 사용자에 대한 구분이 어렵다. (이러한 문제점 때문에 Cookie와 Session이 등장하였다.)

4. Http Message 형식

https://developer.mozilla.org/ko/docs/Web/HTTP/Messages

HTTP의 요청과 응답 메시지 구조는 비슷하다.
start-line : 요청,응답에 대한 전반적인 정보
Http headers : 요청, 응답에 대한 자세한 정보, 각 줄은 LF,CR로 구분
empty line : header와 body를 구분하기 위해 사용
body : 클라이언트가 데이터를 송신하거나 수신할 때 사용하는 공간

 

 

참조 : https://medium.com/dream-youngs/www-%EB%9E%80-b2c069c730a4

https://developer.mozilla.org/ko/docs/Web/HTTP/Messages

'IT > WEB' 카테고리의 다른 글

[CSS] CSS 변수 사용하기  (0) 2021.01.24
[WEB] RESTful 이란?  (0) 2020.10.06
[WEB] CSRF란 ?  (0) 2020.07.30

1. ON DUPLICATE KEY UPDATE

데이터 삽입 시, PRIMERY KEY나 UNIQUE KEY가 중복되었을 경우 지정한 데이터만 UPDATE하는 명령어를 의미한다.
(중복된 키가 없을 경우 INSERT 로직을 수행한다.) 

1) member 테이블 생성

CREATE TABLE member (
	id INT AUTO_INCREMENT primary KEY,
	NAME VARCHAR(50) UNIQUE KEY,
	price INT NOT NULL DEFAULT 0,
	cnt INT NOT NULL DEFAULT 0
);

2) 데이터 삽입

INSERT INTO member (NAME, price, cnt) VALUES ('kim', 1000, 0) 
ON DUPLICATE KEY UPDATE 
  price = price * 2, 
  cnt = cnt + 1;

한번 더 데이터를 삽입 할 경우

새로운 행이 삽입 되지 않고, price와 cnt가 변경된 것을 볼 수 있다.

즉, 데이터 삽입 시, 중복키 제약조건에 위배 되면 ON DUPLICATE KEY UPDATE 아래에 지정한 필드가 수정된다.

위 테이블에 경우 name 값이 중복 되므로 price와 cnt 필드가 지정한 값으로 수정되었다.

2. INSERT IGNORE

중복키 제약조건에 위배되면 Insert를 무시한다.

INSERT IGNORE INTO member (NAME, price, cnt) VALUES ('kim', 1000, 0);

3. REPLACE INTO

중복키 제약조건에 위배되면 해당 레코드를 삭제하고 다시 삽입한다.

REPLACE INTO member (NAME, price, cnt) VALUES ('kim', 1000, 0);

레코드가 삭제되고 다시 삽입되기 때문에 AUTO_INCREMENT로 ID(PK)값을 지정했을 경우 ID값이 변하게 된다.

1. 공개키 암호화 방식이란?

암호화와 복호화를 하는데 사용하는 키가 서로 다른 암호화 방식을 의미합니다.

암호화 할 때 사용하는 키를 공개키, 복호화 할 때 사용하는 키를 개인키라고 합니다.

2. 중요한 데이터의 전달 방법

공개키 암호화 방식을 이용해서 A가 B에게 중요한 데이터 전달하는 방법

1. B는 자신의 공개키를 공개한다.
2. A는 전달할 데이터를 B의 공개키로 암호화한다.
3. A는 암호화된 데이터를 B에게 전달한다.
4. B는 전달받은 데이터를 자신의 개인키로 복호화한다. 

3. 종류

  • RSA 암호화
  • 디피-헬만 키 교환
  • Rabin 암호
  • ElGamal
  • DSA
  • 타원 곡선 암호

참조 : https://namu.wiki/w/%EA%B3%B5%EA%B0%9C%ED%82%A4%20%EC%95%94%ED%98%B8%ED%99%94%20%EB%B0%A9%EC%8B%9D

'IT > 기타' 카테고리의 다른 글

[JWT] Json Web Token이란?  (0) 2020.10.02
[Javascript] Jqgrid Custom  (0) 2020.09.14
[DEV] 컴파일과 빌드란  (0) 2020.09.10
XSS란?  (0) 2020.07.16
OAuth2 란?  (1) 2020.02.29

1. XSS (Cross-Site Scripting) 

서버로 보내는 입력 값에 악성 자바스크립트를 함께 보내고 특정 사용자가 악성 스크립트를 실행하게끔 만드는 공격 방법입니다.

2. XSS 공격의 종류

  • Stored XSS
    해커가 웹 서버에 댓글이나 게시글 등에 악성 스크립트가 삽입된 글을 등록하고, 그것을 사용자가 열람했을 때 삽입된 악성스크립트가 실행되어 사용자의 정보를 탈취하는 공격 방법입니다. 
  • Reflected XSS
    해커는 악성 스크립트가 삽입된 URL을 사용자가 누르게 유도하고, URL을 누르면, 악성스크립트가 실행되게하는 공격방법입니다. 

'IT > 기타' 카테고리의 다른 글

[JWT] Json Web Token이란?  (0) 2020.10.02
[Javascript] Jqgrid Custom  (0) 2020.09.14
[DEV] 컴파일과 빌드란  (0) 2020.09.10
[보안] 공개키 암호화 방식  (0) 2020.07.20
OAuth2 란?  (1) 2020.02.29

Spring에서 JSR 303 어노테이션을 이용해 데이터 유효성검사를 진행할 수 있습니다.
보통 @NotBlank, @Size, @NotNull ...등 이미 만들어진 검증 어노테이션을 이용할 수 있지만, 자신의 목적에 맞는 검증 어노테이션을 커스텀하여 제작할 수 있습니다.

간단하게 password를 검증하는 어노테이션을 만들어보겠습니다.

1. Password Annotation 생성

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import kr.co.tlab.ppl.validator.impl.PasswordValidator;

@Documented
@Constraint(validatedBy = PasswordValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Password {

    String message() default "";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    public int min() default 0;

    public int max() default 2147483647;

    public boolean nullable() default false;
}

2. Password 검증 로직이 있는 ConstraintValidator 구현 

  • 비밀번호는 정해진 길이만큼 입력해야한다. (min ~ max)
  • 비밀번호는 nullable 속성을 통해 Null값을 받을 수 있다. (true/false)
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import kr.co.tlab.ppl.validator.Password;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

public class PasswordValidator implements ConstraintValidator<Password, String> {

    private int min;
    private int max;
    private boolean nullable;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void initialize(Password passwordValidator) {
        //어노테이션 등록 시, 입력했던 Parameter를 초기화한다.
        min = passwordValidator.min();
        max = passwordValidator.max();
        nullable = passwordValidator.nullable();
    }

    @Override
    public boolean isValid(String password, ConstraintValidatorContext context) {
        //if password is not blank
        if (StringUtils.hasText(password)) {
            if (password.length() < min || password.length() > max) {
                addConstraintViolation(
                        context,
                        String.format("비밀번호는 %d자 ~ %d자 사이로 입력해주세요.", min, max)
                );
                return false;
            }
        } 
        else if (!nullable){
            addConstraintViolation(
                    context,
                    "비밀번호를 입력해주세요."
            );
            return false;
        }

        return true;
    }

    private void addConstraintViolation(ConstraintValidatorContext context, String msg) {
        //기본 메시지 비활성화
        context.disableDefaultConstraintViolation();
        //새로운 메시지 추가
        context.buildConstraintViolationWithTemplate(msg).addConstraintViolation();
    }

}

 

3. Member

public class Member{

    private Integer id;
    
    @NotBlank
    private String account;

    //Password 검증 어노테이션 등록
    @Password(min = 3, max = 10, nullable = true)
    private String password;

    @NotBlank
    private String name;

    private String email;

	//setter,getter 생략
}

 

4. ValidationTestController 

@Controller
@RequestMapping(value = "")
public class ValidationTestController {

    @PostMapping(value = "/member/save")
    @ResponseBody
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void saveMember(@Valid Member member) {
    	... save logic
    }
    
}

 

5. 비밀번호 "1" 입력 시 Response 결과

{
    "timestamp": 1594282566312,
    "status": 400,
    "error": "Bad Request",
    "errors": [{
            "codes": ["Password.member.password", "Password.password", "Password.java.lang.String", "Password"],
            "arguments": [{
                    "codes": ["member.password", "password"],
                    "arguments": null,
                    "defaultMessage": "password",
                    "code": "password"
                }, 10, 3, true],
            "defaultMessage": "비밀번호는 3자 ~ 10자 사이로 입력해주세요.",
            "objectName": "member",
            "field": "password",
            "rejectedValue": "1",
            "bindingFailure": false,
            "code": "Password"
        }],
    "message": "Validation failed for object='member'. Error count: 1",
    "path": "/member/save"
}

1. 배열이란

메모리 상에 동일한 타입의 데이터를 연속적으로 나열하여 저장하는 자료구조입니다.

2. 배열의 특징

  • 메모리 상에 특정 길이 만큼 메모리 공간을 선언하면, 변경할 수 없다.
  • 배열은 연속된 메모리 공간을 갖고 있다.
  • 배열은 인덱스를 통해서 데이터에 접근할 수 있다.

3. 배열 선언 및 초기화, 출력

public class Main {

    public static void main(String[] args) {

        //배열을 초기화하는 3가지 방법
        int[] arr1 = new int[10];
        int[] arr2 = {1, 3, 4, 5, 6};
        int[] arr3 = new int[]{1, 3, 2, 4, 1, 5, 1};

        //특정 인덱스에 데이터 삽입
        arr3[0] = 500;

        //배열을 출력하는 방법(향상된 for문)
        for (int n : arr3) {
            System.out.println(n);
        }
        
        //일반적인 배열 출력
        for (int index = 0; index < arr3.length; index++) {
            System.out.println(arr3[index]);
        }
    }
}

+ Recent posts