개발을 하다보면 이미지 리사이징이 필요한 경우가 있습니다.

관련해서 라이브러리, 방법 등 시간될때마다 정리해둘 예정입니다.(계속해서 업데이트)

 

  1. golang으로 만든 라이브러리 imagor
    1. https://github.com/cshum/imagor
  2. imageMgick. 10여년정도 전에 시스템 구축할때 사용했었고 써봤던거라서 지금도 빠르게 필요할때 가끔 사용
    1. https://imagemagick.org/index.php
  3. GraphicsMagick
    1. imagemaginck를 fork해서 만듬
    2. http://www.graphicsmagick.org/
  4. AWS를 서비스를 이용해서 리사이징
    1. https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-s3-tutorial.html
    2. 클라우드 사용하면서 종종 이용(golang과 람다 조합하면 비용 및 빠른 시작의 이점으로 좋음)
      1. https://netflixtechblog.medium.com/netflix-images-enhanced-with-aws-lambda-9eda989249bf
  5. 대규모 이미지 서비스를 개발한다면 스토리지 비용을 무시할 수 없음. 이때 포맷 선택도 중요한 사항
    1. LINE에서 JPEG->HEIF포맷으로 변환
      1. https://engineering.linecorp.com/ko/blog/antman-project-development-story
      2. 콜드 스토리지를 잘 활용해야함
      3. 사실 이정도를 고려해야하는 서비스는 국내에 많지 않아서 개발 조직 규모/유지보수 용이성 등을 잘 고려해야하고 오버 엔지니어링 안되게 해야함
  6. 오픈소스 이미지 프록시 서버
    1. ImageMagick, GraphicsMagick 등 이미지 변환 작업을 빠르게 해줄 수 있는 단독 서버
    2. 외부에 존재하는 많은 이미지들의 리사이징에 최적
    3. https://github.com/imgproxy/imgproxy
  1. 목적/배경
    1. 서비스를 운영하다보면 봇 등의 공격이 있을 수 있습니다.
    2. 특정 IP를 차단해도 IP를 변경해가면서 공격이 들어옵니다. 이때 효과적인 차단 방법 중 하나입니다.
  2. 제한 사항
    1. AWS의 CloudFront를 사용해야합니다.
    2. CloudFront에서 헤더 추가를 활성화해서 nginx에서 JA3헤더를 얻을 수 있어야합니다.(참고 링크)
  3. 참고
    1. 서버에서 tcpdump -s 0 -A 'tcp dst port 80' 등으로 인입되는 헤더의 CloudFront-Viewer-JA3-Fingerprint 를 분석
      1. AWS JA3헤더 관련 참고 링크
        1. 상세 셋팅 방법은 하단 참고
      2. ja3 fingerprint란? 링크
  4. nginx 설정 방법
    1. 확인된 나쁜 JA3 Fingerprint값을 아래 nginx 설정에 추가해서 1(true)로 설정 -> 403리턴
map $http_cloudfront_viewer_ja3_fingerprint $block_fingerprint {
        default 0;
        "차단할 CloudFront-Viewer-JA3-Fingerprint값" 1;
        "차단할 CloudFront-Viewer-JA3-Fingerprint값" 1;
}

server
{
        if ($block_fingerprint) {
           return 403;
        }

        .......

}

 
추가로, API 요청이었고 rate limit 처리해서 429 리턴 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)"}';
}

 


참고- AWS Cloud Front 헤더 셋팅 방법

  1. CloudFront -> Distributions -> 대상 CloudFront -> Edit behavior
    1.  

AWS Cloud Front의 Custom Origin request policy를 추가하는 위치

2. Custom policies 생성

Custom policies 추가하는 방법
샘플 Custom Policy Origin reqeust settings

요즘 가장 관심이 있는 java쪽 기능/피쳐

모든 기존 프로덕트를 재 개발할수도 없고, 리액티브 스타일로 개발시 여러 허들과 트러블 슈팅도 있어서..

java virtual thread의 draft(2023/03/06 created)
https://openjdk.org/jeps/8303683

 

 

노이즈가 좀 있는 내용 같지만 추가 참고 글

 - https://news.hada.io/topic?id=9250

 

 

jjwt를 사용해서 보통 JWT 처리를 하는데 혹시 secretKey 기존에 대충 만들었다면(길이가 짧게) 0.10.0 버전부터 에러가 발생함

 - https://github.com/jwtk/jjwt/issues/334

https://github.com/jwtk/jjwt/blob/6b980553cfb4435ec14b7842af5b529735acbb2d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L364

 

 

이에 간단히 사용하는 SecretKey 생성 소스

import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;

public class JwtSecretKeyMaker {

	/**
	 * JJWT secretKey를 생성할때 알고리즘에 맞는 length로 만듬
	 *  - https://github.com/jwtk/jjwt#jws-key-create
	 *  - jjwt 0.10.0 부터는 length가 작으면 에러가 발생함: https://github.com/jwtk/jjwt/issues/334
	 *
	 * @param args
	 */
	public static void main(String[] args) {

		//Creating Safe Keys(length: 256bit))
		SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); // HS256: HMAC-SHA256
		String secretString = Encoders.BASE64.encode(key.getEncoded());

		System.out.println(secretString);

	}
}
  1. 사전 필요사항
    1. AWS CloudFront 설정
1. 메뉴
 - AWS 웹 콘솔 -> CloudFront -> 대상 CloudFront ID(도메인에 맵핑된) -> Behaviors -> 해당 Behaviors 선택 -> Edit

2.  Cache key and origin requests 영역 설정
 1) Cache policy and origin request policy (recommended) 선택
 2) Cache policy 를  CachingDisabled 로 설정
  - CloudFront를 동적 컨텐츠 전송 목적과 위치정보 헤더 값등 필요 헤더를 획득할 목적이기 때문에
  - 참고: https://aws.amazon.com/ko/cloudfront/dynamic-content/
  - 참고: https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html
 3) Origin request policy - optional 에 커스텀 policy추가해서 반영
  - 샘플) CloudFront에서 추가되는 헤더를 모두 선택한 경우

설정샘플(주의: 뒷단 was까지 Query Strings와 Cookies를 넘겨줘야하기 때문에 ALL로 설정)

  1. Java 샘플소스
/**
	 * 클라이언트 요청자의 IP를 가져옴(WAS 앞단에 로드밸런서 등이 존재할 수 있음을 감안한 메소드)
	 *  - AWS CloudFront -> ALB(LB) -> Nginx-> 톰캣을 사용하는 케이스를 감안한 메소드
	 *  - AWS CloudFront사용시 해당 헤더의 IP정보를 최우선으로 신뢰함(즉, IP를 얻어오는 순서에 의미가 있음)
	 *  - 주의: Spring webflux는 해당 메소드를 사용불가(대신 ServerWebExchange exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() 같은 메소드를 사용해야함)
	 *
	 * @param request HttpServletRequest
	 * @return
	 */
	public static String getClientIp(HttpServletRequest request) {

		//참고 https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/using-cloudfront-headers.html#cloudfront-headers-viewer-location
		//참고 https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/WhatsNew.html
		final String awsCfAddress = request.getHeader("CloudFront-Viewer-Address"); //ex) 123.45.67.89:46532
		if (StringUtils.isNotBlank(awsCfAddress)) {
			log.trace("\nIP획득 출처: AWS CloudFront-Viewer-Address\n\t요청 http header => {}", HttpRequestUtil.getRequestHeaderToMap(request));
			return awsCfAddress.split(":")[0].trim(); //구분자 :
		}

		//프록시 레이어를 감안한 XFF값
		//TODO: XFF는 spoofed(속일 수 있음)가 가능하기 때문에 오른쪽부터 IP를 가져오도록 수정해야함. 이때 신뢰하는 프록시IP들은 제외하는 로직 작업도 필요 https://news.hada.io/topic?id=6098
		//https://en.wikipedia.org/wiki/X-Forwarded-For
		//https://blog.lael.be/post/8989
		final String xForwardedFor = request.getHeader("X-Forwarded-For"); //ex) 123.456.78.99,15.162.1.11
		if (StringUtils.isNotBlank(xForwardedFor)) {
			log.trace("\nIP획득 출처: X-Forwarded-For\n\t요청 http header => {}", HttpRequestUtil.getRequestHeaderToMap(request));
			return xForwardedFor.split(",")[0].trim(); //구분자 ,
		}

		final String realIp = request.getHeader("X-Real-IP"); //일반적으로는 인프라(프록시) 설정 들이 잘되어 있다면 다른 언어 및 프레임웤에서는 보안문제 때문에 Real IP가 XFF보다 우선순위 높음
		if (StringUtils.isNotBlank(realIp)) {
			log.trace("\nIP획득 출처: X-Real-IP\n\t요청 http header => {}", HttpRequestUtil.getRequestHeaderToMap(request));
			return realIp;
		}

		log.trace("\nIP획득 출처: request.getRemoteAddr\n\t요청 http header => {}", HttpRequestUtil.getRequestHeaderToMap(request));
		return request.getRemoteAddr();
	}

AWS ALB의 Access log의 파서 프로그램입니다. 파이썬 버전이고 간혹 사용해서 메모 용도르 저장해둡니다.

 

import re

#참고
# 1) https://docs.aws.amazon.com/ko_kr/elasticloadbalancing/latest/application/load-balancer-access-logs.html
# 2) https://stackoverflow.com/questions/68875527/regex-for-python-based-logparser-for-printing-aws-elb-logs

fields = [ "type",
"time",
"elb",
"client_ip",
"client_port",
"target_ip",
"target_port",
"request_processing_time",
"target_processing_time",
"response_processing_time",
"elb_status_code",
"target_status_code",
"received_bytes",
"sent_bytes",
"request_type",
"request_url",
"request_protocol",
"user_agent_browser",
"ssl_cipher",
"ssl_protocol",
"target_group_arn",
"trace_id",
"domain_name",
"chosen_cert_arn",
"matched_rule_priority",
"request_creation_time",
"actions_executed",
"redirect_url",
"lambda_error_reason",
"target_port_list",
"target_status_code_list",
"classification",
"classification_reason" ]



field = str(input("what is the field needed? "))
regex = r'([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*):([0-9]*) ([^ ]*)[:-]([0-9]*) ([-.0-9]*) ([-.0-9]*) ([-.0-9]*) (|[-0-9]*) (-|[-0-9]*) ([-0-9]*) ([-0-9]*) \"([^ ]*) ([^ ]*) (- |[^ ]*)\" \"([^\"]*)\" ([A-Z0-9-]+) ([A-Za-z0-9.-]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\" ([-.0-9]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\" \"([^ ]*)\" \"([^\s]+?)\" \"([^\s]+)\" \"([^ ]*)\" \"([^ ]*)\"'

def ParseLogFile(file):
    resultDict = {}

    with open(file, 'r') as log:
        line = log.readline()
        while line:
            line_split = re.split(regex, line)
            line_split = line_split[1:len(line_split) - 1]
            index = fields.index(field)
            val = line_split[index]
            resultDict.setdefault(val, 0)
            resultDict[val] += 1
            line = log.readline()
        return resultDict
if __name__ == '__main__':
    result=ParseLogFile("C:\\HOME\\2.log")
    print(result)

자주 잊어버려서 메모

 

nginx location 기본 문법
 - https://lahuman.github.io/nginx_location_options/
-----

# 정확하게 일치 
location = / {
    [ configuration A ]
}

# 지정한 패턴으로 시작
location / {
    [ configuration B ]
}

# 지정한 패턴으로 시작
location /documents/ {
    [ configuration C ]
}

# 지정한 패턴으로 시작 패턴이 일치 하면 다른 패턴 탐색 중지( 정규식 아님 )
location ^~ /images/ {
    [ configuration D ]
}

# 정규식 표현 일치 - 대소문자 구분
location ~ \.(gif|jpg|jpeg)$ {
    [ configuration E ]
}

# 정규식 표현 일치 - 대소문자 구분 안함
location ~* \.(gif|jpg|jpeg)$ {
    [ configuration F ]
}

AWS 람다 + SNS조합해서 바운스된 이메일 DB구축 -> 서비스에서는 적절하게 로직/유저 메시지 처리해야함

 

관련해서 참고 링크

 - https://docs.aws.amazon.com/ses/latest/dg/notification-contents.html

 - 바운스되는 종류(bounce type): https://docs.aws.amazon.com/ses/latest/dg/notification-contents.html#bounce-types

  => 케이스별로 적절하게 로직처리(예. MailboxFull이면 유저에게 메일함이  꽉 찾는지 확인해서 조치요청 UI)

 

 

추가글 참고
- https://blog.eomsh.com/199

'AWS > ' 카테고리의 다른 글

CloudWatch 인스턴스의 메모리 및 디스크 Matrix 추가  (0) 2016.08.07

+ Recent posts