https://jwt.io/

 

[JWT]

Json Web Token 의 약자로 토큰값 자체에 데이터를 가지고 있는 인증 토큰.

.으로 구분되는 3개 영역, Header.Payload.Signature 으로 나뉘어 진다. 

모든 영역은 Base64로 인코딩 되어 있다.

* Base64란? Binary Data를 Text로 바꾸는 Encoding 방법 중 하나로 Binary Data를 Character set 에 영향을 받지 않는 공통 ASCII 영역의 문자로만 이루어진 문자열로 바꾸는 Encoding.

 

[Header.Payload.Signature]

1. Header : 토큰에 사용된 알고리즘(SHA256, HS512 등)과 MIME 타입(보통 "typ" : "JWT" 사용)

2. Payload : 토큰의 바디로써 Claim(User Id 와 같은 Entity 정보) 정보를 담고 있음.

  암호화 되어있지 않고 단순 Base64 인코딩이 되어있으므로 패스워드와 같이 중요한 데이터를 담지 않도록 주의

3. Signature : Header 와 Payload 가 위변조 되었는지 검증하기 위한 부분으로써 Header와 Payload 를 base64 encoding 해서 만든 두 값을 . 로 이어 붙이고 Header 에서 지정한 알고리즘(alg)로 인코딩하여 Signature 를 만듬.

 

https://blog.outsider.ne.kr/1160

반응형

'back > SECURITY' 카테고리의 다른 글

[SECURITY] Authentication vs Authorization  (0) 2022.08.16

 

Authentication (인증) 과 Authorization (인가) 의 차이

 

인증 : 유저가 누구인지 확인

인가 : 유저에게 권한을 부여

 

반응형

'back > SECURITY' 카테고리의 다른 글

[SECURITY] JWT  (0) 2022.08.16

 

[compileOnly vs rumtimeOnly]

compileOnly : compile시 필요한 library. compileClasspath 에만 들어감 (대표적으로 lombok)

runtimeOnly : rumtime시 필요한 library. runtimeClasspath 에만 들어감 (대표적으로 h2database)

 

[compile(api) vs implementation]

implementation : 지정한 라이브러리만 빌드

compile : 의존하고 있는 상위 라이브러리 까지 빌드

* compile 키워드는 gradle 7.x 부터 deprecated 되었음 (api 로 대체)

 

A > B > C 의존성을 갖는 상황, C 가 변경되었을 때

compile : A, B 까지 rebuild

implementation : B 만 rebuild 

* compile(api) 은 프로젝트가 무거워지므로 사용을 지양할 것

https://kotlinworld.com/317

https://medium.com/mindorks/implementation-vs-api-in-gradle-3-0-494c817a6fa

https://stackoverflow.com/questions/44413952/gradle-implementation-vs-api-configuration

 

annotationprocessor : 

 

https://tomgregory.com/annotation-processors-in-gradle-with-the-annotationprocessor-dependency-configuration/#:~:text=Annotation%20processing%20is%20a%20Java,such%20as%20classes%20or%20documentation.

 

 

 

https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations_graph

 

 

 

반응형

 

SIFT Appender 를 사용하여 로그 분기처리

 

[설정]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?xml version="1.0" encoding="UTF-8"?>
 
<configuration>
 
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}[%-5level] : %msg%n</Pattern>
        </encoder>
    </appender>
 
    <appender name="TST" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}[%-5level]-%msg%n</Pattern>
        </encoder>
    </appender>
 
    <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
        <discriminator>
            <key>discr</key>
            <defaultValue>type</defaultValue>
        </discriminator>
        <sift>
            <appender name="FILE-${discr}" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <file>/${discr}.log</file>
                <layout class="ch.qos.logback.classic.PatternLayout">
                    <Pattern>%d [%thread] %level %mdc %logger{35} SIFT- %msg%n</Pattern>
                </layout>
                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                    <fileNamePattern>/${discr}_%d{yyyy-MM-dd-HH-mm}.%i.log</fileNamePattern>
                </rollingPolicy>
            </appender>
        </sift>
    </appender>
 
 
    <logger name="jpabook.jpashop.service.OrderService" level="error" additivity="false">
        <!--<appender-ref ref="TST"/>-->
        <appender-ref ref="SIFT"/>
    </logger>
 
    <root level="debug">
        <appender-ref ref="CONSOLE"/>
    </root>
 
 
</configuration>
cs

 

[테스트]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.slf4j.MDC;
 
@Slf4j
public class Sample {
    public void testLog(){
        MDC.put("discr""TYP1");
        //log.
        log.trace("test trace");
        log.debug("test debug");
        log.info("test info");
        log.warn("test warn");
        log.error("test error");
 
        MDC.put("discr""TYP2");
        log.error("test error222");
    }
}
cs

 

[결과]

 

* ThreadPool 사용시 MDC key값을 전달받지 못함.

 : MDC.setContextMap 으로 key 값 전달가능

 참고 : https://stackoverflow.com/questions/6073019/how-to-use-mdc-with-thread-pools

 

* slf4j MDC 를 사용하지 않더라도, strategy pattern 과 같은 디자인 패턴을 사용하고, 분기처리할 구현체에 logger 를 지정하여 패키지 경로마다 별도 로그 파일 및 별도 경로의 로그파일에 로그 적재가 가능할 듯.

 

반응형


자바 직렬화

https://devlog-wjdrbs96.tistory.com/268
https://findmypiece.tistory.com/m/166


반응형

POM

1
2
3
4
5
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
    @Override
    public String makeJwt(HttpServletRequest res) throws Exception {
        String secretKey = PropertiesService.getPropertiesValue(Constants.PROP_KEY_JWT_SECRET);
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        Date expireTime = new Date();
        
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(secretKey);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
        
        Map<String, Object> headerMap = new HashMap<String, Object>();
        headerMap.put("typ","JWT");
        headerMap.put("alg","HS256");
        
        expireTime.setTime(expireTime.getTime() + 1000 * 60 * 1);
        String name = res.getParameter("name");
        String email = res.getParameter("email");
        
        Map<String, Object> map= new HashMap<String, Object>();
        map.put("name", name);
        map.put("email", email);
        
        JwtBuilder builder = Jwts.builder().setHeader(headerMap)
            .setClaims(map)
            .setExpiration(expireTime)
            .signWith(signatureAlgorithm, signingKey);
        
        return builder.compact();
    }
   
    @Override
    public HashMap<StringString> checkJwt(String jwt) throws Exception {
        HashMap<StringString> jwtInfo = new HashMap<StringString>();
        
        try {
            String secretKey = PropertiesService.getPropertiesValue(Constants.PROP_KEY_JWT_SECRET);
            logger.info("- token: "+ jwt);
            
            // base64 none
            byte[] token = secretKey.getBytes("UTF-8");
            // base64 check
//            byte[] token = DatatypeConverter.parseBase64Binary(secretKey);
            Claims claims = Jwts.parser().setSigningKey(token)
                    .parseClaimsJws(jwt).getBody(); // 정상 수행된다면 해당 토큰은 정상토큰
            jwtInfo.put("exp", claims.getExpiration().toString());
            jwtInfo.put("sno", claims.get("sno").toString());
            jwtInfo.put("result""OK");
            logger.info("- expireTime :" + claims.getExpiration());
            logger.info("- sno: "+ claims.get("sno").toString());
        } catch (ExpiredJwtException exception) {
            logger.info("token expired");
            jwtInfo.put("result""False");
        } catch (JwtException exception) {
            logger.info("token falsified");
            jwtInfo.put("result""False");
        }
        return jwtInfo;
    }
cs

반응형

'back' 카테고리의 다른 글

[Java] 일급콜렉션 : First Class Collection  (0) 2022.10.06
[TDD] 테스트주도개발  (0) 2022.10.04
[gradle] jar build, war build  (0) 2020.03.25

메소드 안에서 다음과 같이 쌩뚱맞은 중괄호 블락이 보인다면,

이는 변수의 유효 범위(scope)를 제한하기 위함이다.

 

1
2
3
4
5
6
7
8
9
public void methodA(){
    {
        int a = 0;
    }
    
    int a = 2;
 
    return b;
}
cs

3번째 라인의 a 변수는 { } 안에서만 유효한 지역변수이며,

위와 같이 a 변수를 6번라인에서 선언해도 문제 되지 않는다.

 

* 변수 유효범위를 제한하여 코딩할 때 사용하나, 드물게 사용된다. 

 

반응형

 

<if test = '@com.test.Utils@isEmpty(param)'>
   AND searchVal = #{param}
</if>

@classpath@method(param) 과 같이 사용이 가능

 

보안상 쓸일은 없겠지만 아래와 같이 사용도 가능

SELECT '${@com.test.Utils@isEmpty(param)}' FROM DAUL

 

반응형

'back > Mybatis,Ibatis' 카테고리의 다른 글

[Mybatis] 동적쿼리 (if test) 문자열처리  (4) 2020.03.27
[Ibatis] dtd 경로 문제  (1) 2019.12.30
[Mybatis] $과 # 차이  (0) 2019.12.05
[Mybatis] like 조건시 문자열 처리  (1) 2019.02.13

URL에 직접 접근할 수 없도록 처리

: header 에서 referer 정보를 확인하여 직접 접근 여부 판별이 가능하다.

referer 는 변조가 가능하여 직접 접근을 완벽히 막는 방법이라고 할 순 없을 듯 하나, 보통은 이정도만 처리해도 될 듯 하다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String contextPath = request.getContextPath();
    
    if(handler instanceof HandlerMethod) {
        HandlerMethod handlerMethod = (HandlerMethod)handler;
        
        RefererUncheck lefererUncheck = handlerMethod.getMethodAnnotation(RefererUncheck.class);
        
        logger.info("Header Check. (getRemoteAddr=" + StringUtils.trimToNull(request.getRemoteAddr()) + ")");
        logger.info("Header Check. (getRequestUrl=" + StringUtils.trimToNull(request.getRequestURI().substring(contextPath.length())));
        try {
            // URL 접속정보
            String referer = StringUtils.trimToNull(request.getHeader("Referer"));
            logger.info("referer : " + referer);
            // 리퍼럴 어노테이션이 없고, ajax 통신이 아닌경우만 체크
            if (lefererUncheck == null && !this.isAjaxRequest(request)) {
                logger.debug("Referer Check Start! (Referer=" + StringUtils.trimToNull(request.getHeader("Referer")) + ")");
                logger.debug("Referer Check success! (URI=" + request.getRequestURI() + ")");
                if (StringUtils.isEmpty(referer)) {
                    throw new CustomException("error.referer");
                }
            }
            
        } catch (CustomException be) {
            request.getRequestDispatcher(contextPath+ "/cmm/error.jsp").forward(request, response);
            return false;
        } catch (Exception e) {
            logger.error(e.getMessage());
            return false;
        }
    }
    
    return true;
}
private boolean isAjaxRequest(HttpServletRequest request) {
    final String header = request.getHeader(Constants.AJAX_HEADER);
    if( header != null && header.equals("true") ) {
        return true;
    }
    return false;
}
 
cs

 

referer Mozilla doc

 

 

반응형

Maven Build 시 test 건너뛰기 

Maven Build (install) 시 Maven Test 이후에 Build를 하게 된다.

이때 jUnit 테스트 에서 Exception 발생 및 Assert not Equal 등으로 Test가 실패할 경우 Build 는 실패 (Fail) 하게 된다.

jUnit Test 가 실패해도 Build 는 되게끔 Maven Test 단계를 건너뛰는 방법은 아래와 같다.

 

1. CMD 에서 빌드시

mvn install -DskipTests 

 

2. IDE Run configurations 에서 빌드시

1. Goals 에 다음과 같이 옵션 부여 : install -DskipTests 

2. Skip Tests 체크박스 체크 후 run

3. pom 수정 : surefire plugin 사용 (skipTests 속성 값 true/false 로 지정)

1
2
3
4
5
6
7
8
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M4</version>
    <configuration>
      <skipTests>true</skipTests>
    </configuration>
</plugin>
cs

 

surefire doc:

https://maven.apache.org/surefire/maven-surefire-plugin/examples/skipping-tests.html

반응형

+ Recent posts