개인적으로 API를 만들어서 AWS EC2에서 서비스 중인 사용처들에게 제공 중인데 이 때 JWT인증을 사용 중. 관련하여 메모


1. JWT토큰 인증이란?

AWS의 인스턴스는 IP가 변경될 수 있기에 기존의 IP인증 방식으로는 API를 사용할 수 없습니다.(Elastic ip)를 사용하면 고정되기는 함)
이처럼 IP인증 방식을 사용하기 어려울 때 사용하는 인증 방식입니다.

2. JWT 토큰의 포맷 및 규약은?

JWT(Json Web Token)이라는 RFC 7519 표준의 토큰방식을 따릅니다.(http://jwt.io/)
Header(알고리즘과 토큰타입), Payload(데이터), Verify signature(변조검증)로 구성되어 있으며
Header와 Payload는 base64로 디코딩시 내용을 확인 가능합니다.

토큰인증 방식을 사용하시려면 HTTP 헤더에 서비스코드와 인증토큰 2가지 값을 전달해주셔야합니다.

3. 디코딩시 내용을 볼 수 있는데 보안 문제는 없는건지?

API 인증 용도의 토큰은 유저정보 등의 노출되면 안되는 정보가 없기에 디코딩되도 무방합니다.
또한, Verify Signature가 존재하여 HMAC로 토큰을 검증하기에 Header와 Payload는 변조가 불가능합니다.
(필요시 토큰 자체를 암호화할 수도 있기는하지만, 필요성이 없는 작업에 암복호화를 위한 서버 리소스를 사용할 필요가 없어서 진행 안함 , 필요시 AES256으로 암복호화 처리 중)

4. 토큰 인증방식의 성능은?
성능 테스트결과 기존 IP인증 방식과 동일한 TPS를 보였으며 경우에 따라서는 더 좋은 결과를 나타냈습니다.

5. 토큰을 발급 받으려면?

"따로 제공하는 인증토큰 발급 API"를 이용해서 발급 받을 수 있습니다.
해당 API는 HTTPS로 통신하며 사전에 전달받은 서비스코드와 토큰발급용 암호 2가지 값이 필요합니다.

6. 사용 중 토큰이 만료되었다고 실패가 발생하면?
토큰을 재 발급 받아서 해당 API를 다시 호출하셔야 합니다.

7. 토큰은 서비스별로 유일한지?
유일하지 않습니다. 여러개일 수 있습니다.

8. 토큰이 여러개일 수 있는 이유는?

API를 호출하는 서버는 여러개일 수 있어서 특정 토큰 1개만 허용하게되면 동시성 이슈가 발생할 수 있습니다. 
또한, 토큰 1개만 유지할 경우 제공 및 사용측에서 글로벌캐쉬 등을 사용해야해서 복잡해집니다.
이를 해결하기 위해 토큰은 여러개 발급 가능하도록 허용해뒀습니다.


/**

 * Spring boot에서 셧다운 이벤트 발생시 리스너 샘플

 * 

 * @author 

 */

@Component

public class StopListener implements ApplicationListener<ContextClosedEvent> {

 

@Override

public void onApplicationEvent(final ContextClosedEvent event) {

System.out.println("셧다운 호출");

}

}

 

 


1. 목적 : 서버가 어떤 웹서버를 사용하는지 감춰서 해킹을 시도하는 유저에게 정보 제공을 줄임

2. 방법

 -  proxy_pass_header Server; 를 추가


* 응답 헤더 server: nginx 가 없어짐

추가

  • AWS CloudFront를 사용할때 http header를 이용해서 특정 국가를 nginx를 이용해서 차단하고 싶을때
if ($http_cloudfront_viewer_country = "CN") {
  return 403;
}

 

rate limit에 해당될때 json으로 리턴하고 싶을때 샘플

error_page 429 /429.json;
    location /429.json {
        add_header 'Content-Type' 'application/json charset=UTF-8';
        return 429 '{"success":false, "errorCd":"RATE_LIMITED","msg":"Too Many Requests(rate limit nginx)"}';
    }

 

중국쪽 봇 등으로 짜증날때 nginx로 전체 인입허용 트래픽을 빠르게 조절할때 사용할 목적으로 간단하게 메모해둡니다.

 - 아래 내용은 추후 복/붙 가능한 형태로 좀 수정해둘 예정

 

http블럭에

limit_req_zone $binary_remote_addr zone=myLimit:10m rate=10r/s;

 

location 블럭안에

limit_req zone=myLimit burst=5 nodelay;


limit_req_zone

예) limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

  • context: http
  • key: 요청량 제한 단위 지정 (예. server_name, remote_addr, uri 등) $server_name을 지정하면 모든 트래픽에 대해 요청량을 제한함
  • zone: 요청량 기록을 위해 사용하는 Key:Value 가 저장될 Shared Memory 크기.
    • 주의: IP 단위로 요청량을 제한 할경우 충분히 큰 값을 설정하지 않으면 메모리 부족 발생할 때 모두 503에러
  • rate: 허용할 request per second 값으로 10r/s를 설정하면 NGINX는 100ms 마다 1개의 요청을 처리

 

limit_req 

예) limit_req zone=mylimit burst=10 nodelay;

  • context: http > server > location
  • burst: key에 설정한 요청량보다 초과된 요청량을 수용하는 크기로 대기큐.
    • rate를 10 rps 로 설정했을 때 100ms 안에 10개의 요청이 들어오면 1개만 처리되고 나머지 9개의 요청은 503 에러가 발생하는 데 이 때 해당 에러를 완화하기 위해서 burst옵션을 사용
    • nodelay: 요청이 rps 에 지정된 시간보다 빨리 처리되었을 때 rps에서 지정한 시간을 기다리지 않고 burst queue에 있는 다음 요청을 바로 처리. 해당 옵션을 사용하지 않는다면 burst queue가 비워질 때까지 새로운 요청은 모두 503 응답

limit_req_dry_run 

  • on: 실제로 제한은 하지 않고 로그를 남김
    • 꼭 해당 기능을 이용해서 라이브 환경의 적절한 수치를 확인하고 적용하는게 좋음
      • 로그에 $limit_req_status 설정 추가 필요

 

기타

 - 제한에서 제외할 IP설정 방법

geo $apply_limit {
    default         $binary_remote_addr;
    10.10.0.0/16    '';                   # 내부 네트워크 대역 10.10.*.* 은 access limit 사용안함
    211.33.188.246  '';                   # 외부의 특정 IP 211.33.188.246 는 access limit 사용안함
}

...
...

limit_req_zone $apply_limit zone=depend_rate_limit:10m rate=10r/s;

...

 

geo 모듈을 사용해서 client ip 를 확인해서 $apply_limit 이라는 변수를 새롭게 할당했다. 10.10.. 대역 이거나, (내부 네트워크 대역인 경우), 외부의 특정 211.33.188.246 인 경우에는 빈값이 지정된다.

 

이렇게 하고 나서 limit_req_zone 에 정의한 $apply_limit 변수를 사용하면, 예외로한 IP 에 대해서는 접속제한이 동작하지 않는다.


참고 링크

 - https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-proxied-http/

 - https://bactoria.github.io/2020/01/19/Nginx%EC%9D%98-limit_req-%EB%AA%A8%EB%93%88-%EC%82%AC%EC%9A%A9%EA%B8%B0/

 - https://findstar.pe.kr/2018/06/24/nginx-rate-limiting/

 - https://serverfault.com/questions/177461/how-to-rate-limit-in-nginx-but-including-excluding-certain-ip-addresses

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

if kakao day 2 후기  (0) 2019.09.02
메모 - 아파치 OFBIZ  (0) 2019.05.23
SNS 공유시 캐시 처리 및 validataor 등  (0) 2018.09.14
웹 취약점 진단도구 메모  (0) 2018.07.09
좋은 코드 작성하기 참고  (0) 2018.06.29

+ Recent posts