Github Security Virtual Meetup Note

깃헙에서 화상으로 시큐리티 밋업을 진행했다. 역시 신청해두고 자느라 라이브로 보지 못했는데 트위치 스트림에 다시보기 기능이 있어 볼 수 있었다. 재밌는 내용을 공유하면 좋을 것 같아 정리해 보았다.

행사 정보: https://securitylab.github.com/events/2020-04-23-github-security-meetup
라이브 스트림: https://www.twitch.tv/videos/600717225

InQL

GraphQL의 자세한 설명은 공식 홈페이지를 참고하자. A Query Language for your API. (https://graphql.org/) Burp Suite Extension과 Standard-alone Python(+Jython) 형태로 제공된다. GraphQL 취약점의 종류는 4가지로 분류 된다.

  • Missing Authentication/Authorization
  • Resource Exhaustion
  • Information Exposure
  • IDOR

GraphQL을 사용하는 API의 보안 취약점 점검을 위해 해당 API가 어떤 Query Set을 지원하는지 알아야 한다. InQL은 해당 API가 Introspection 통해 알아낸 쿼리 Set 정보들을(Mutation / Query / Subscription) Burp Suite Repeater에 옮기거나 직접 Fuzz Testing할 수 있도록 가공해준다. 다만 한가지 아쉬운 점은 Introspection 기능이 꺼져있을 때 wordlist 기반으로 사용할 수 있는 Query가 뭔지 찾아내는 기는은 아직 없다. (매번 손으로 찾거나 스크립트를 만들어 썻는데 누가 범용적으로 사용할 수 있는거 안 만들어 주나? ㅎㅁㅎ) 해당 프로젝트는 https://github.com/doyensec/inql 에서 확인할 수 있다.


Go-ing for an evening stroll

Trail Of bits(ToB) 선생님들의 Talk다. ToB는 티오리와 마찬가지로 golang 기반의 많은 프로젝트(Block Chain/K8S등)를 audit 해왔다. 해당 과정에서 발견된 Common Vulnerabilities 4가지를 공유한다.

  • Integers / Numerics
  • Standard Library Issues
  • Error Checking / type assertions
  • Defer Semantics

Integers/Numerics

golang의 int는 해당 프로그램이 실행되고 있는 아키텍처에 따라 사이즈가 정해진다. 32bit 시스템은 32bits로 처리하고 64bit 시스템은 64bits로 처리한다.

v, err := strconv.Atoi("4294967377") // 0x100000051
g := int32(v)
// 32bits, v and g both are 81
// 64bits, v is 4294967377, g is 81

(WordPress가 golang highlighting기능을 지원하지 않는다는 것을 알았다 ;;) strconv.Atoi, ParseInt/ParseUint의 xref를 찾아 손쉽게 찾을 수 있다. CodeQL Query를 작성했다고 하는데 https://github.com/github/codeql-go 찾아보니깐 없다. 발견하는 로직이 어렵지 않아 금방 작성할 수 있을 것 같다. 해당 취약점은 쿠버네티스나 블록체인 노드처럼 범용적으로 사용되는 프로젝트에는 문제가 크게 발생할 수 있다. (32bit / 64bit 에서 구동할지 모른다.) 하지만 Commercial 하게 회사 혼자 사용하려고 작성한 소프트웨어에서는 보통 64bit 시스템에서 구동을 하니 크게 문제되진 않지만 좋은 Practice는 아니니깐 개선하는 방향이 좋다.

Standard Library Issues

누구나 사용하는 Standard Library에 모두가 Assume하는 방식대로 작동하지 않는다면??? 대게 메뉴얼을 제대로 읽지 않아 발생한다. (대게가 大가 아니라 竹인걸 알고 계셨나요???)

os.MkdirAll("/some/path/i/want/to/make", 0600);
ioutil.WriteFile("/some/file/i/want/to/make", 0600);

위 코드의 동작은 간단하다. 폴더와 파일을 퍼미션과 함께 생성한다. 그럼 이렇게 생각해보면 어떨까?

  1. 만약 해당 폴더와 파일이 이미 존재한다면?
  2. 에러와 경고를 발생시키지도 않고 퍼미션을 Overwrite하지도 않는다.
  3. 0600 퍼미션은 해당 코드를 실행하고 있는 사용자만 접근 가능한 퍼미션이다. 보통 Sensitive한 폴더/파일을 작성하기 위해 해당 퍼미션을 부여하는데 공격자는 해당 폴더와 파일을 0777 퍼미션으로 미리 만들어 놓고 Sensitive한 파일에 접근할 수 있다. (Pre-population attack)
  4. RTFM

Error Checking / type assertions

Error와 Assertion은 다른 언어와 달리 golang이 갖고 있는 재밌는 친구다. 몇 가지 취약점 케이스를 살펴보자.

v, err := SomeFunc(..)
g, err := SomeFunc(..)

h := someval.(int)

err == nil || err != nil

첫번째는 err변수를 중복해서 사용하는 것이다. (v를 assign할 때 error가 발생하였어도 g를 assign 할 때 nil을 리턴한다면 에러 체크가 우회된다.)

두 번째는 type assertion 기능을 ok check없이 사용하는 것이다. https://tour.golang.org/methods/15 를 확인해보면 ok check없이 사용할 경우 panic을 발생시킨다. 블록체인 노드처럼 네트워킹 서비스에서 panic이 발생해 프로그램이 꺼진다면 (DoS) 매우 큰 문제가 된다.

세 번째는 err != nil을 사용하지 않고 err == nil을 사용해 Data Flow 이해에 어려움을 느끼게 되는 안티 패턴이다.

missed error checks와 type assertion panic도 손쉽게 찾아낼 수 있다. (errcheck -asserts / ineffassign / errcheck -assert -blank 사용)

Defer Semantics

defer은 에러 핸들링을 하거나 동작을 끝마칠 때 사용된다. (panic 발생시 recover || resource.Close(), resource.Finish())

func main() {
	ret := hello(3)
	fmt.Println("return from hello:", ret)
}

func hello(x int8) string {
	defer func() string {
		if r:= recover(); r != nil {
			fmt.Println("let's start error handling", r)
		} else {
			fmt.Println("we don't need to recover.")
		}
		return "hi from deferred function!"
	}()

	switch x {
	case 1:
		panic("not hello")
	case 2:
		panic(nil)
	case 3:
	}

	return "hi from hello!"
}

case 1:

let's start error handling not hello
return from hello: 

defer안에서 반환한 값들은 error여도 모두 무시되기 때문에 file.Close()에서 에러가 발생해도 프로그램 실행은 계속된다.

case 2:

we don't need to recover.
return from hello: 

panicnil을 넘기면 recover의 반환 값도 nil이다. 따라서 에러 핸들링 코드로 가지 않는다.

case 3: 정상적인 케이스

defer를 사용할 때 항상 주의해야 한다. 보다 자세한 내용은 https://github.com/lojikil/kyoto-go-nihilism/blob/master/go-nihilism.md 를 참고하면 된다.


그 뒤에 devsecops와 csp/samesite 관련 talk가 진행되었다. devsecops는 좋은 이야기지만 내가 작성하는 것 보다 더 나은 자료들이 많을 것 같고, csp/samesite 이야기는 technical한 이야기 보다 RoR에 어떻게 효율적으로 적용하는지 설명해준다. (SameSite는 재미난 버그 케이스를 발견해 조만간 포스팅하지 않을까 생각된다.) golang의 경우 인터널을 잘 알고있는 사람이 많은 것 같지 않아 정리해보았다. 메뉴얼을 제대로 읽지 않거나 설명해주는 내용이 부실해 개발자들이 자신만의 추측대로 라이브러리나 기능을 사용해 발생하는 edge-case들을 찾는건 언제나 재미있는 것 같다. CTF 문제로도 나오면 재미있을 것 같고.. 다만 문제로 낸다면 방대한 양의 코드나 메뉴얼을 전부다 살펴보지 않게 범위를 줄여주거나 방향을 제시해야 할 것 같다.

ToB에서 진행한 버추얼 밋업도 자느라 못봤다 ㅜ.ㅜ 이번 코로나 사태로 외국에서 밋업들이 활발하게 진행된다는 것을 알게되었고 대부분 on-site 로 진행되어 해당 지역에 사는 사람들만 참가할 수 있었는데 (NY: tob, bay area: fuzzing meetup 등) 화상으로 변경되어 외국에서도 참가할 수 있어 좋은 것 같다. 우리나라도 정기적인 밋업을 통해 정보 공유가 활발하게 일어나면 좋겠는데 역시나 Sponsoring이 없다면 힘들 것 같기도 ㅋ..

독서 기록, 1-5

연관성은 없어 보이지만 theori tv에 올라온 책 추천 영상을 보고 요근래에 어떤 책을 읽었고, 읽고 있는지 내 생각과 함께 정리해두면 좋을 것 같다는 막연한 생각에 작성한다.

역사 속의 소프트웨어 오류

위 영상에서 나온 책 두권을 빌려주셔서 읽어 보았다. 두권 모두전문 지식을 갖고 있는(라고 할 수 있나?) 분야라 재미있게 읽었다. 반올림과 내림 오류부터 표기법 차이로 인해 천문학적 돈이 들어간 프로젝트가 공중 분해된 사건을 독자가 읽기 쉽게 설명했다. 몇 개의 챕터 마지막 부분에는 “어떻게 코딩을 했길래 이런 오류가 발생하지?”를 궁금해 할 컴퓨터 엔지니어들을 위한 부분이 있다. 의사코드|파이썬으로 실제 버그가 있었던 코드를 갖고와 직접 테스트 해보는 시간을 갖는다. https://github.com/rflynn/bugs에 다른 버그들도 확인할 수 있다.

해킹, 침입의 드라마

캐빈 미트닉이 (선의든 악의든) 해킹 사건에 연루돼 연방 감옥에 수감 되었거나 잡히지 않은 해커들을 인터뷰한 책이다. 카지노의 PRNG를 해킹해 달러 채굴기를 만든 일화, 사회 공학 해킹을 통해 회사 내부에 접근 하는 방법, 고도의 APT 작업을 통해 사내 네트워크를 해킹한 일화등 영화에서나 볼 법한 내용들로 채워져있다. 양념이 많이 들어간 내용도 있겠지만 현업에서도 비슷한 일들을 겪고 나니 훨씬 재미있었다. 소설처럼 읽다가 이게 실화였다는 것을 깨닫고 더 신난다 ㅋㅋ. 나도 나중에 주변 사람들의 이야기를 모아 한국판 “해킹, 침입의 드라마”를 쓰고 싶다.

팩트폴니스

한참전에 리디북스를 통해 구매하여 전자책 뷰어로 자기전 3-4분 읽고 자던 책이다. 내가 얼마나 세상에 무지했는가를 다시금 일깨워준다. 세상이 지금 어떻게 돌아가고 있는가를 묻는 사실 문제 11개를 사람들에게 물어봤는데 다들 랜덤으로 찍는 침팬지 보다 못하다는 결론이 나왔다는 것이다. 일상속에 사로잡힌 고정관념과 여러가지 인간의 본능이 만들어낸 결과라 세상을 바라볼 땐 객관적인 시각으로 보자는 내용이다. 내가 일하고 있는 필드에서의 사건이라 함은 “해킹 사고”라고 했을 때 증가하는 추세인지 감소하는 추세인지 확실히 말할 수 없는 내 자신을 다시금 반성하게 된다. 여러번 읽을만한 책.

남산의 부장들

남미 여행을 할 때 읽을 책을 고르다가 그 때 당시 개봉 했던 영화의 원작이라고 해 읽어보았다. 근현대사 지식이 없는 사람들은 읽기 힘들 것 같다. (내가 그랬다.) 등장 인물에 대한 소개가 너무 길어 지쳤다. 이후 영화도 보았는데 배우들의 연기에 감탄을 했다. 아직 책을 읽지 않았다면 영화만 보는 것을 추천.

나는 나를 어떻게 할 것인가

김동조 작가 책에 있는 글귀를 우연히 트위터에서 보고난 후 접하게 되었다. 해당 글귀는 “모두 같은 달을 보지만 서로 다른 꿈을 꾼다.”의 내용인데 쓰신 책이 3권 밖에 없어서 하나씩 읽고 있는 중이다. 마음에 들었던 작가가 마음에 들었던 부분이 두가지 있는데 “300-400 페이지의 책을 한 내용만 갖고 쓴다면 매우 지루할 것, 다른 이야기를 많은 챕터를 나눠 써야겠다” 와 “도덕은 어떻게 사는 것이 가장 이상적인지를 이야기 한다면 경제학은 지금 어떻게 살아가고 있는지를 이야기 한다”는 것이다. 첫 번째는 책 읽을 시간이 얼마 없는 직장인을 생각한 마음이 보이지 않게 드러나 있는 것 같아서 좋았고, 두번째는 새로운 관점이라 좋았다. 현실에 당면한 문제만 해결할 것이 아니라 삶의 이유를 찾아야 한다는 머스크 형님의 말고 비슷한 맥락이겠지만 다시 봐도 즐겁다.

읽고 있는 책들

  • 거의 모든 것의 경제학
  • 모두 같은 달을 보지만 서로 다른 꿈을 꾼다.
  • 좀 이상하지만 재미있는 녀석들

위 두권은 김동조 작가가 쓴 나머지 2권의 책이다. 마지막 책은 종이백이 필요해 서점에 들러 급하게 재밌어 보여 구매 하였는데, 인공지능/기계학습에 대한 기초 지식이 부족한 나도 쉽게 읽을 수 있게 예제와 설명을 잘 해두었다. 빨리 읽어보고 알려주겠다 ㅎㅁㅎ.


주말에 Plaid CTF를 했다. 좋은 퀄리티의 문제를 출제하는 CTF는 항상 내가 아직 많이 부족하다는 것을 느끼게 해준다. 1등하고 데프콘 예선 스킵하려고 하였지만 실패했고, 당장 있을 데프콘 예선을 위해 파이팅 해야겠다.

코로나 때문에 집 밖에 나가질 않으니 컴퓨터를 조금만 해도 목이 저리고 아프다. 빨리 좋은 책상을 놓을 수 있는 집으로 이사해 편안하게 컴퓨터 하고 싶다 ㅜㅡㅜ. 12시간 동안 한 문제만 봤더니 어꺠와 목이 너무 아프다. 😦

Untitled 0307

안녕하세요, 오랜만에 글을 쓰게 되네요. 이 저녁에 치킨 시킨 것을 반성하고자 뭐라도 생산적인 일을 해내야 한다는 압박감 속에 쓰는 것이라 금방 쓸 것 같습니다. 😀

어떤 주제의 글을 쓰지 생각 하다 예전에 찾았던 크롬 버그 설명과 평소에 제가 생각하는 운(Luck)에 관한 주제면 괜찮을 것 같아 보였습니다. 갑자기 이 주제가 떠오른 이유는 매우 간단합니다. 며칠전 용머가 한국 인터넷 진흥원에서 제공하는 보안 모듈에서 찾은 취약점의 PoC 영상을 추억이라며 보내왔습니다. 유튜브 영상이기에 자연스레 업로드 했던 영상이 뭐가 있는지 살펴보다가 48초의 PoC 영상을 찾게되었습니다. 해당 취약점은 운이 좋아서 발견할 수 있었다고 생각하기에 그 당시에도 하지 않았던 (간단한) 기술적 분석과 이런 방식에(얻어 걸리는 = 운에 의한) 대한 제 견해를 공유하고자 합니다.

해당 취약점을 찾게된 과정은 이렇습니다. 🚀

누군가 제게 URL을(자세한 기억은 없지만 모 커뮤니티의 게시글) 보냈습니다. 웹 개발을 하고 있던 터라 마침 개발자도구의 네트워크 탭이 켜져있었습니다. 게시글 페이지에서 불러오는 리소스들 중 특정 Custom Scheme으로 리다이렉션을 시도하는 요청이 빨간 글씨로 취소되었다는 것이 마침 눈에 들어왔습니다. 그때 당시 저는 단순히 “어? 왜지? 그러면 다른 Scheme들은 어떨까?” 하는 생각이 들었습니다. 곧바로 열줄 정도의 코드로 Special URL(data, file), 그 외 chrome, about:blank, javascript등 Scheme을 테스트 해 보았습니다.

몇 개의 Scheme들의 요청이 취소되는 것을 확인할 수 있었습니다. 요청이 취소되면 1) Address Bar의 URL이 원래의 URL로 복원되던가 2) 에러 페이지로 변경되는 것이 일반적인 현상입니다. 하지만 javascript shceme은 다른 것들과 달리 요청이 취소되고 원본 URL로 복구되지 않았습니다. 네, Address Bar Spoofing 취약점입니다.

소스코드를 보지 않고 단 10분만에 Security Issue를 발견했습니다. 90%의 운으로 말이죠. (왜 100%가 아닌지는 뒤에 나옵니다.) 패널들은 해당 취약점을 $1,000 값어치로 인정해주었습니다. 들인 시간에 비하면 매우 높은 금액입니다. 쓰다보니 서론이 너무 길어졌네요 간단하게 리뷰어들이 나눈 대화로 루트커즈를 서술하겠습니다.

문제가 된 라인입니다. 리다이트를 할 수 없는 URL이면 위 로직을 수행합니다. ResetNavigationRequest 를 하는 바람에 알 수 없는 ✌️Side-Effect✌️가 발생해 Address Bar를 복구하지 않는다는 것입니다. 패치는 에러 페이지를 발생시키는 것으로 되었습니다. 여담이지만 javascript 리다이렉션 동작을 데스크탑 앱으로 이동시킬 때 사용하고 있는 사용자가 엄청 많은 확장 플러그인이 있습니다. 해당 패치로 인해 에러 페이지가 발생해 UI (?)에 문제가 생겨 언젠간 에러 페이지가 발생하도록 수정하겠다는 기약 없는 TODO만 남긴채 ERR_ABORTED를 반환 하도록 수정되었습니다. 애플 사파리에서도 동일한 문제가 있어 애플 쪽에 리포트를 진행하였습니다.

위 취약점은 CVE-2019-5794을 부여 받았습니다. 사용된 PoC는 위 URL에 있으니 https://commondatastorage.googleapis.com/chromium-browser-asan/index.html 에서 2019년 01월 빌드를 받아 테스트 할 수 있습니다. (M71)

자, 이제 운에 관한 이야기를 해봅시다. 운에 의한 버그헌팅은 단기적으로 금전적 보상이 있어 좋아 보이지만 장기적으로 실력의 발전에는 별 도움이 되지 못합니다. 저는 어떤 행위나 의사 결정의 결과에 운의 비중이 얼마나 들어가 있느냐가 실력의 척도라고 생각합니다. 어떤 행위는 버그 바운티, 주식 투자, 아키텍처 설계등이 있습니다. 누가 결과에 대해 “어떻게 했어?” 라고 물었을 때 “그냥”, “누가 좋다던데?”, “이 값을 넣으니 저렇게 나오더라..” 등의 대답이 아닌 논리적 사고의 과정을 설명할 수 있어야 한다고 믿고 있습니다.

그러한 과정이 없다면 다음번에는 더욱 발전된 형태의 사고를 통해 더 나은 결과를 얻지 못하고 또 한번 운에 의지할 수 밖에 없을 것입니다.

가장 쉬운 예를 들어보겠습니다. 어떤 사람이 A회사의 (회사 이름이 마음에 들어서, 누구 추천으로, 꿈에 나왔다)주식을 샀는데 어느날 주가가 30%가 올랐습니다. 운이 매우 좋은 사람인가 봅니다. 이런식으로 매매를 계속하다 보면 어떻게 될까요? 매매를 할 때 논리적인 사고 없이 단순히 운에 의지 했기 때문에 잔고는 0원에 수렴할 것입니다.

위 취약점을 찾는 과정속에서 여러가지 Scheme을 테스트할 수 있던 것은 웹 개발을 하면서 쌓았던 지식이 우연히 논리적 사고에 영향을 주었을 것입니다. 그 외적인 요소는 (실제로 취약점으로 귀결 되었다던지, anchor 태그로 클릭하는 것이 아닌 Address Bar에 C&P 했다 던지) 모두 운에 의지한 사고였다고 생각합니다.

운의 비중을 낮추면서 취약점을 찾으려면 어떻게 할지 생각해 보았습니다. 제 결론은 간단합니다. 컴퓨터 보안은 컴퓨터 사이언스 지식의 응용에 불과합니다. 따라서 기반 지식이 수반되지 않으면 결국 많은 운을 필요로 할 것입니다. 저 또한 항상 자각하며 공부를 게을리 하지 않으려고 합니다.

30살에 은퇴하겠단 큰 꿈을 갖고 대학을 안(못)가고 산업계에 들어와 컴퓨터 사이언스 지식 부족에 의해 허우적 거렸던 저는 좋은 학교의 커리큘럼을 많이 참고했습니다. 물론 지금도 많은 도움을 받고 있습니다. https://csd.cs.cmu.edu/academic/undergraduate/bachelors-curriculum-admitted-2018 를 살펴보시면 됩니다.

어랏😲 치킨이 도착했네요, 하고싶은 말이 더 많지만 다음에 기회가 된다면 써보도록 하겠습니다. 네 그럼 치킨먹으러 도망갑니다, 모두들 화이팅이에요.

고추마요임 ㅋ

Browser based CSRF Mitigation? Yoooh!!!!!! Same-Site-Cookie!

Chrome 76 부터 Same-Site-Cookie 설정이 default로 enabled되었다는 것을 보았다. 사용자의 Privacy와 CSRF를 막기위해 개발되었다. Privacy는 쿠키를 통한 사용자 트래킹 (?)을 막을 수 있게 되었다는데 이 글에선 CSRF를 중점적으로 다룰 것이다.

우선 CSRF가 무엇인지 이해하고 넘어가야 한다. 하나의 예시를 보여주도록 하겠다.

악의적인 공격자의 웹페이지에 아래와 같은 코드가 있다고 생각해보자.

<html>
<body onload=x.submit()>
<form id=x method=post action=http://vic.tim/delete/3>
</form>
</body>
</html>

vic.tim 사이트에 CSRF를 방어할 수 있는 로직이 없다면 피해자는 자신도 모르게 3번 게시글을 삭제할 것이다. 이를 방어하기 위해 지금껏 시큐리티 미들웨어나 프레임워크들이 했던 방식은 크게 2가지이다.

  1. CSRF Token 검증
  2. Referer 헤더 검증

위 방법은 CSRF 공격을 막는데 효과적이지만 모든 입력받는 컨트롤러에서 확인을 해줘야 하기 때문에 효율적이지는 못하다.

이제 세션쿠키에 헤더를 추가하는 것만으로도 CSRF를 방어할 수 있는 시대가 왔다. 간단한 예제를 통해 알아보자.

Cookie를 설정할 때 CookieName=foobar; Domain=..; Expires=…; 쿠키 key=value 말고 추가적으로 Domain, Expires와 같은 설정을 추가할 수 있다. 이곳에 Same-Site 라는 설정 값이 추가된 것이다.

SameSite의 값은 Strict, Lax, None을 지원한다. 각각의 기능을 설명해보면,

Strict – 사용자가 직접 주소창에 입력하는 top-level navigation을 제외한 모든 요청에 Cookie가 포함되지 않는다.

<?php
header("Set-Cookie: foo=bar; SameSite=Strict;");
header("Set-Cookie : bob=alice; SameSite=Lax;");
header("Set-Cookie  : juno=im;");
echo '<pre>';
var_dump($_SERVER['HTTP_COOKIE']);
echo '</pre>';
<a href="http://app.imjuno.com/q/">go</a>                                   
<br>
<form method="post" action="http://app.imjuno.com/q/">
    <button type=submit>go</button>
</form>
a tag를 이용한 접속

Lax와 Normal 쿠키만 전송되는 것을 확인할 수 있다.

post action을 통한 접속

FORM을 이용한 POST 요청은 Normal 쿠키만 전송된다. 아래는 요청 타입별로 어떤 Same-Site 쿠키가 전송되는지에 대한 정리표이다. 개발할 때 참고하면 좋을 것 같다.

MDN에는 아직 Experimental 기능이라고 나오지만 현재 모든 브라우저에서 지원하고 있다. Chrome이 가장 먼저 적용한줄 알았는데 이미 다른 브라우저들은 적용했더라 -_-

https://caniuse.com/#search=SameSite

구글에서 이미 서버사이드 프로그래밍에 자주 쓰이는 언어들에서 SameSite 쿠키를 사용하는 방법을 깃헙에 올려두었다.

사용자 세션에 SameSite=Strict를 사용할 경우 CSRF를 완벽하게 막을 순 있겠지만 a href를 통한 접속에 쿠키가 같이 보내지지 않기 때문에 유저 편의성을 해칠 수 있다. 예를 들면 이메일에서 링크를 눌러 접속한다던지….

마지막으로 어떠한 미티게이션을 도입하더라도 Silver Bullet은 없기 때문에 (XSS가 발생하면 무의미 해진다 ㅋㅋ) 서버의 코드를 잘 작성하는게 제일 중요하다는 것을 말하구 싶다~!~!