React.js로 개발을 하다 절대 경로 설정을 추가하게 되었다. TypeScript의 경우 tsconfig.json 파일을, JavaScript의 경우 jsconfig.json 파일만 추가하면 되었기 때문에 그리 어렵지 않게 설정할 수 있었다.

 

하지만 문제는 절대 경로를 추가하니 eslint에서 문법이 이상하다고 계속 경고를 울렸다.

 

이 이슈도 좀 유명한 이슈였는지 검색하니 여러 가지 방법이 나왔고, 여러 방법을 시도하던 중 eslint에서 'import/no-unresolved' 옵션을 아래와 같이 설정해주면 된다고 하여 이 이슈도 해결할 수 있었다.

"rules": {
   "import/no-unresolved": [
      2, 
      { "caseSensitive": false }
   ],
   // 또는
    "import/no-unresolved": "off",
}

 

나 같은 경우 다른 설정은 작동하지 않아 "off"로 해결할 수 있었는데, 이 문제를 해결하는 글들을 읽어보며 "import/no-unresolved"가 정확히 어떤 옵션인지는 설명해주지 않아 나의 호기심을 자극했다.

 

다행히 GitHub에 이에 관련된 글이 있어, 이 부분을 알 수 있게 되었다. 아래 링크를 첨부하겠다.

https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md

 

원글을 읽는 것이 가장 좋겠지만, 시간이 없거나 영어를 잘 못 읽는 분들을 위해 간단히 정리하자면

 

경로의 파일이 unresolved하는 일이 없도록 하는 옵션인 것 같다. 그래서 이름부터 import/no-unresolved다. 정확히는 import로 가져온 파일 혹은 모듈이 unresolved가 되지 않도록(no)하는 옵션이다.

 

친절한 이 옵션은 import 뿐만 아니라 require, define 등의 CommonJS 혹은 AMD도 지원을 해준다.

심지어 CommonJS 혹은 AMD를 { commonjs: true/false, amd: true/false } 옵션을 통하여 감지할지 말지를 정해줄 수도 있다!

 

그리고 한 가지 옵션을 더 설명하자면 "caseSensitive"라는 옵션이 있는데, 파일 경로가 틀린 것을 감지하는 옵션이다.

당연히 기본적으로는 켜져있어서 true이고, 끄고 싶다면 false로 바꾸어주면 된다.

절대 경로의 경우에는 flie system의 실제 경로와 맞지 않기 때문에 lint에서 빨간 밑줄을 띄우게 되고, 이 옵션을 끄게되면 이제 더이상 실제 경로와 틀리다는 경고성 밑줄이 뜨게 되지 않는 것이다.

 

그리고 또 여러 가지 옵션이 더 있는데, 자세한 사항은 위의 GitHub 링크 들어가서 읽어보면 좋을 것 같다.

 

다시 한번 더 링크

https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md

반응형

의문의 시작

- 개발을 하던 도중, 이 글의 제목과 같은 의문이 생겼다.

- 이 의문이 무엇인지에 대하 간단히 설명하자면 useEffect, useCallback, useMemo, useLayoutoff 같은 hook은 인자로 callback 함수와 deps를 받는다. 이 때 deps에 넣은 값이 변경되면 callback을 다시 실행한다.

- hook의 사용법이나 어떻게 동작하는지 알고 싶다면 관련된 다른 글을 보거나, 아래의 공식 문서를 읽는 것이 도움이 될 것이다.

https://ko.reactjs.org/docs/hooks-reference.html

 

- 다시 본론으로 돌아가, 이런 의문이 생긴 이유는 hook의 deps에 object를 넣는 일이 생겼다. object를 넣었을때는 어떤 경우에 콜백 함수가 실행될까라는 의문이 들었다. object 내부의 프로퍼티가 바뀌었을때도 감지해서 콜백 함수가 실행될까? 혹은 key, value가 같은 object로 바뀌었을때는 콜백함수가 실행될까라는 의문이 들었다.

- 결론적으로 설명하면, objectA !== objectB가 성립되면 콜백 함수가 실행되었다. 즉 내부의 프로퍼티 변경을 감지하는 것이 아닌 단순히 객체의 주소 값만을 비교하고 달라지면 콜백 함수를 실행하는 것이였다.

- 따라서 당연한 이야기겠지만, 테스트를 해 보았을때 objectState의 프로퍼티를 변경하거나, 프로퍼티를 변경한 후 그 객체를 다시 setState 해줘도 콜백함수는 실행되지 않았다.

 

동작 원리

- 물론 여기까지만 봐도 짐작으로 deps의 변화를 어떻게 감지하는지 유추가 되지만, 정확히 어떻게 돌아가는지 확인하고 싶어서 찾아보기 시작했다. 처음에는 TypeScript에 정의된 deps의 타입을 찾아보았다. deps의 타입은 dependencyList라고 나오고 배열 안에 값이 들어가는 것만 확인할 수 있었다.

- 그 다음으로 찾아본 것은 React의 GitHub 코드를 찾아보았지만 너무 방대한 나머지 처음에는 찾다 포기를 하였다.

- 이에 관련된 글이 있을까 싶어 찾아보다가 믿음직하고 설명도 잘 되어 있는 글을 찾았다. 바로 netlify의 기술 블로그?였다.

https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/

 

- 또한 이 글을 읽고 다시 React 공식 GitHub를 찾아보니 deps의 동작 부분을 확인하고 이해할 수 있었다.

 

- 결론적으로 얻은 결론은 단순히 새로운 deps 배열과 기존 deps 배열을 for문으로 돌면서 값을 하나하나 비교해서 값이 하나라도 다르다면 콜백 함수를 실행시켜주는 식이였다.

- 그 비교는 단순히 a===b를 통한 비교였고, 따라서 오브젝트의 프로퍼티가 달라지면 그 부분은 확인할 수 없었다.

- 물론 React에서는 불변성을 지키기 위해 오브젝트의 프로퍼티를 바꿀 때는 새로운 오브젝트를 생성하기 때문에 대부분의 경우 이 부분이 문제가 되지는 않을 것이다.

 

- React 공식 GitHub에서 이러한 동작을 여러 부분에서 확인할 수 있지만, 가장 쉽게 이해할 수 있는 부분은 아마 이 부분인 것 같다.

https://github.com/facebook/react/blob/149b420f63903bcfb99455337a376c75384f86af/packages/react-devtools-shared/src/backend/renderer.js#L1378

반응형

<읽기 전 주의> 이 글은 외국 블로그를 퍼온 문익점 글입니다. 읽은 블로그가 틀린 내용을 담고 있다면 이 내용도 틀릴 수 있습니다!

- 출처

https://hackernoon.com/why-import-react-from-react-in-a-functional-component-657aed821f7a

글쓰면서 공식 문서도 참고했으니 틀릴 가능성은 낮을 것 같다... 물론 영어를 잘못 읽었거나 내용을 잘못 이해했다면 틀렸을 가능성도 있으니 출처도 한 번씩 들어가 읽는 걸 추천한다.

 

궁금해진 이유

- 토이프로젝트를 하기 위해 lint 설정을 처음부터 다시 할 일이 있었는데, lint 설정을 마치니  'React' must be in scope when using JSX 라는 오류가 떴다.

- 이 오류의 원인을 찾아보니 컴포넌트 파일(.jsx) 안에 import React from 'react' 가 빠져있어서 발생하는 오류라고 했다.

- 오류를 보니, 저 줄을 왜 함수형 컴포넌트에는 항상 넣을까라는 궁금증이 들었다. 심지어 이 줄이 없어도 문제 없이 돌아가기는 한다.

- 그래서 이유를 찾아봤고, 이에 대해 정리된 블로그가 있어 번역 및 정리해보았다.

 

이슈의 원인

- 원인은 바로 BABEL과 JSX이다.

 

- JSX 엘리먼트는 단지 React.createElement()를 호출하는 편리한 문법에 불과하다.

(공식문서 참조 : https://ko.reactjs.org/docs/react-api.html#creating-react-elements)

 

- 따라서 BABEL로 JSX인 함수형 컴포넌트를 트랜스파일링하면 React.createElement를 이용한 코드로 변경된다. 그렇기 때문에 React.createElement를 호출하기 위하여 React가 필요한 것이다.

 

그런데 안써도 된다?

- 하지만 React 17부터는 안써도 된다. 왜냐면 새로운 방법의 JSX 변환을 사용하기 때문이다.

 

관련 내용 블로그 : https://dev.to/titungdup/you-no-longer-need-to-import-react-from-react-3pbj

공식 문서 : https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

 

- 따라서 쓰기 귀찮으신 분은 lint 설정을 변경하여 에러를 무시하도록 한 후 React 17 혹은 그 이후의 버젼을 사용하면 된다.

 

 

 

 

 

마지막으로 다시 한 번 출처

https://hackernoon.com/why-import-react-from-react-in-a-functional-component-657aed821f7a

https://ko.reactjs.org/docs/react-api.html#creating-react-elements

https://dev.to/titungdup/you-no-longer-need-to-import-react-from-react-3pbj

https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

 

 

반응형

입사할 때 추천 + 선물 받은 책인데, 아직까지 못 읽고 있었다. ㅠㅠ

사실 책 표지가 너무 옛날 책 느낌이라 별로 끌리지 않아 미루고 미루고 있었다..

제목도 뭔가 외국 도서인데 한 2003년에 출시되었는데 번역된 느낌이라서 끌리지 않았는데.. 놀랍게도 한국인 저자에 2018년도 초판 발행이었다.

지금부터라도 천천히 읽으려고 펴봤는데, 내용이 정말 좋아서 정리하려고 한다.

뭔가 부캠에서 마스터(멘토)분들이 많이 해주신 말씀이 있는데, 그 때도 와닿는 내용들이었는데, 지금 보니까 더 강하고 새롭게 와닿아서 이 책 내용들을 읽으며 본 내용 및 내 생각들을 정리해보려한다.

 

2021/7/20

 

회고하자.

- 부캠에서 많이 듣고 하던 것들이었는데, 막상 일을 시작하고는 거의 하지 못했다.

- 회고를 하며 내가 하는 일들을 더 개선할 수 있는 방법들을 생각하고 실천해서 다음에 할 땐 실수를 덜 하고, 더 효율적으로 효과적으로 작업을 해야겠다.

 

즐기자.

- 취업 전에는 취미로 개발을 할 정도로 즐겼는데, 이상하게 취업을 하고 나서는 퇴근하고 개발 공부를 예전만큼 하지는 않는 것 같다.

- 입사 후 3개월까지도 열심히 했는데 뭔가 코로나의 여파인지, 아니면 이제 무의식적으로 일이라고 여겨서인지, 예전만큼 즐기지 못하는 것 같다.

- 일이라고 생각하지말고 예전처럼 즐겨야겠다. (근데 출근할 때는 좀 즐거운데), 이상하게 집에서 할 때는 스트레스를 받는 기분이다. 

- 집에서 개발을 하면 뭔가 일과 삶이 섞이고 무너지는 기분이라서 그런 것 같기도 하다.

- 부캠할 때, 개발은 장거리 마라톤이라고, 그리고 일과 일이 아닌 것을 분리해야한다고, 그래서 재택하더라도 출근/퇴근하는 것처럼 밖을 한바퀴 돌고 들어오라고 하셨는데, 이제 그 말의 의미를 알 것 같다. 

- 취미는 취미로 내버려두고, 전업으로 하고 싶지 않다는 사람들의 말을 이제는 조금은 이해할 수 있을 것 같다.

- 그래도 즐겁게 개발을 지속가능하게, 오래오래할 수 있는 방법을 찾아야 할 것 같다.

 

발전하자

- A라는 일을 하기 위한 B라는 일을 하고, B라는 일을 개선하기 위한 C라는 일을 하자

- 이 말의 의미를 부캠할 때는 크게 못 느꼈는데, 요즘은 많이 느끼는 것 같다.

- 더 잘하기 위한 방법을 더 잘하기 위한 방법을 더 잘해보자 ㅎㅎ

- 블로그도 이제 좀 다시 써봐야겠다.

 

 

 

2021/7/22

 

어려운 일을 해라

- 이 말은 어려운 개발을 해라라는 의미보다, 사람들과 소통하는 등의 업무를 하라는 뜻이다. 코파일럿이 나온 지금 더욱더 중요한 말인 것 같은데, 주어진 스펙을 개발하는 개발자가 아니라 요구사항을 분석하고, 요구를 이해하고 오히려 제안하는 등 컴퓨터가 하기 힘든 일을 잘하는게 중요한 것 같다.

- 이말은 간단히 말하면 답이 있는 문제, 측량이 가능한 그런 문제가 아닌, 답이 없는 문제, 측정이 어렵고 당장 눈에는 안 보이지만 어려운 것들을 하라는 말이다.

- 조금은 논점에서 벗어나지만, 이 부분을 읽으면서 예전에 대학생 때 프로젝트하면서 요구하면 '다 해주는 개발자'로 불렸던게 기억난다. 요구사항을 들고오면 다 구현해주었다. 물론 실력이 모자랐기에 아주 깔끔하고 완벽하게 개발해주지는 못했지만...그 때 기억나는게, 돌아가는 예시 사이트를 들고오면 그대로 해주겠다고 했었는데...참 패기로웠던 것 같다.

- 물론 또 다시 생각해보면, 요구사항을 다 들어주지는 않았다. 요구 사항을 들고오고, 예시 사이트를 들고오면, 어떤 부분이 적용되길 바라는지, 왜 이 부분을 넣고 싶은지, 이런 저런 이야기를 해주면서 요구사항을 디벨롭하며 필요 없는 부분은 쳐내고, 필요한 부분은 더 발전시켰던게 생각나서, 나름 잘 살았던 것 같다. 정말로 논점에서 벗어난 이야기인 것 같지만..

 

계속 의식하면서 일해라

- 이 부분은 더 읽어봐야 알겠지만, 간단하게 말하면 양치질 30년한다고 양치 전문가가 되지 않듯이 의식하면서 일을 해야한다!

 

 

2021/10/17

 

사실 이 책을 다 읽은지는 꽤 되었다. 근데 블로그 관리를 하지 않아서...ㅠ

책 내용이 괜찮아서 나중에 생각날때 다시 읽겠지만 기억나는 요점은 간단히 정리하자면

애자일하게, 결과를 짧게 짧게 낼 수 있도록 하고, 그에 대한 회고를 하며 단점을 보완해서 나아지자! 라는게 이 책의 핵심인 것 같다.

 

글이 용두사미가 된 것 같은데, 나중에 시간이 나면 더 정리해보아야겠다.

반응형

'Coding > 읽은 책들' 카테고리의 다른 글

해커와 화가  (0) 2020.07.16
알고리즘 도감 : 그림으로 배우는 알고리즘 26  (1) 2018.07.20

이 글의 시작은 매우 간단했다. JavaScript로 문제를 코딩테스트 풀다가, Map이라는 자료구조를 사용할 일이 생겼다.

 

복잡한? 기능들을 사용하기는 귀찮아서 Object로 문제를 해결하려했는데, 그럼 시간 복잡도에 문제가 없을까?라는 생각이 들었다.

 

Stackoverflow에서 찾아보니, Object도 hash로 이루어져있어서 find에 O(1)의 시간 복잡도를 가진단다.

 

stackoverflow.com/questions/12241676/javascript-objects-as-hashes-is-the-complexity-greater-than-o1

 

JavaScript Objects as Hashes? Is the complexity greater than O(1)?

For some algorithm I was writing recently I thought that a hash would be excellent. I thought that I could probably just use the member variables in an object as key value pairs. I am not sure if t...

stackoverflow.com

 

여기서 의문이 시작됐다. JavaScript에서 Object와 Map은 어떻게 이루어져있을까?? 물론 인터프리터, 컴파일러, 엔진에 따라 다르겠지만,내가 자주 쓰는 Node를 기준으로 어떻게 되어있는지 궁금했다. 이에 대해 개인 Notion에 러프하게 정리했었는데, 블로그에 깔끔히 정리해보려한다.

 

Map과 HashMap

먼저 Map과 HashMap에 대하여 알고 있어야 이해하기가 편할 것 같다.

 

HashMap = unordered Map

  • HashMap은 key 와 value 를 hash 알고리즘에 의해 구현

  • Hash 알고리즘으로 넣으므로 전체가 어떤 특정한 규칙으로 정렬이 되어 있지 않다.
  • hash_map은 find에 이상적으로 O(1)의 시간을 소요한다.

  • 하지만 hash_map은 실제로는 hash table의 크기에 반비례하는 O(n)의 시간을 소요한다.

    • 예를 들어 1000개 저장하는데, 테이블 크기가 100이라면, 시간은 10만큼 걸릴 것이다.

Map ( Tree Map ), Ordered Map

  • Map( Tree Map)은 보통 red-black tree 알고리즘을 이용하여 구현

  • Tree의 규칙대로 들어가므로, Order되어 있다, 즉 정렬되어 있다.
  • Map( Tree Map )을 쓰는 경우, 최악의 경우 O(n), 최상의 경우 O(logn)의 시간복잡도

    • 이진 트리의 원리에 따라 일렬로 이루어졌을 경우 O(n)이 걸리고,
    • 균등하게 나누어져 있다면 O(logN)이 걸릴 것이다.
반응형

서론

프론트앤드와 서버를 분리한 후, Web API를 통하여 통신을 하다보면, 필연적으로 마주치는 것이 CORS 오류이다.

이 오류를 여러 번 마주쳐서, 나는 이 문제를 이해하고, 문제를 해결했다고 생각했지만, 최근에 CORS에 관한 질문을 받고, 대답하는 중, 내가 이해를 제대로 하지 못했구나!라고 생각하며 좀 더 깊게? 공부해보기로 했다.

 

그리고 앞으로는 여러 개념들을 깊게 공부해보며, 개인 Notion에 정리해놓은 것들을 블로그에 깔끔하게 정리해보려 한다.

 

SOP( Same-Origin Policy )란?

MDN에서는 이렇게 설명한다.

 

동일 출처 정책(same-origin policy)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다. 동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여줍니다.

 

간단하게 설명하자면 a.com이라는 사이트에서는 a.com에서만 정보를 가져올 수 있다는 것이다. 즉 프론트 서버는 a.com으로, 백앤드 서버는 b.com으로 분리하면 안되고, 둘 다 a.com에 존재해야 데이터를 주고 받을 수 있다는 것이다.

 

그럼 같은 출처(origin)은 어디까지가 같은 출처인가? 

MDN에서는 다시 이렇게 말한다.

 

두 URL의 프로토콜, 포트(명시한 경우), 호스트가 모두 같아야 동일한 출처라고 말합니다. "스킴/호스트/포트튜플"이나 그냥 "튜플"(2개 이상의 요소가 전체를 구성하는 집합)이라고 하기도 합니다.

 

 URL http://store.company.com/dir/page.html의 출처를 기준으로 친절하게 표까지 작성해주었다.

URL 결과 이유
http://store.company.com/dir2/other.html 성공 경로만 다름
http://store.company.com/dir/inner/another.html 성공 경로만 다름
https://store.company.com/secure.html 실패 프로토콜 다름
http://store.company.com:81/dir/etc.html 실패 포트 다름 (http://는 80이 기본값)
http://news.company.com/dir/other.html 실패 호스트 다름

 

즉 프로토콜 ( http, https ), 포트( :81, :3000 등), 호스트 ( www.tistory.com  )까지 같아야하고, 이 중 하나라도 다르면 같은 출처( Same-Origin) 으로 간주하지 않는다는 것이다.

 

이 문제를 해결하기 위하여 다양한 방법이 있고, MDN에 이 방법들이 적혀있다.

여러 방법이 있지만, 그 중 가장 안전하고 권장하는 방법이 바로 CORS이다.

 

CORS ( Cross-Origin Resource Sharing ) 란?

진리의 MDN에서는 이렇게 설명한다.

 

교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행합니다.

 

즉 간단하게 말하면, HTTP 헤더에 정보를 추가하여, 다른 Origin끼리도 데이터를 주고 받을 수 있게 한다!라는 것이다.

 

a.com에서 b.com의 데이터를 요청한다면,

클라이언트에서 서버로 요청할 때 http header에 { Origin : a.com } 이렇게 요청하는 곳의 출처를 넣고, 

서버에서 클라이언트로 응답할 때는 { Access-Control-Allow-Origin : 허용할 주소 } 이렇게 응답을 보낸다.

 

그리고 만약 내가 요청한 주소가 허용할 주소에 포함되어 있다면, 데이터를 받아서 화면에 뿌려준다.

 

그렇지만 반대로 요청한 주소가 허용할 주소에 포함되어 있지 않다면, CORS 오류가 발생한다.

 

CORS 오류 해결 방법

이 문제를 해결하기 위해서는 서버 측에서 응답할 때 http header 내에 있는 { Access-Control-Allow-Origin : 허용할 주소 }에 a.com을 넣어주면 CORS 오류는 발생하지 않게 된다. 

 

혹은 어느 사이트에서 요청할지 모르니, { Access-Control-Allow-Origin : * } 로, 모든 주소를 허용하면 편하게 해결할 수 있다. 물론 이렇게 된다면 보안상 문제가 생길 수 있다.

만약 내가 서버를 건들일 수 없다면, 이 문제는 브라우저에서 막아서 발생하는 문제이므로, 프록시 서버를 하나 만들어서, 프록시 서버에서 정보를 받아온 후, 클라이언트에  { Access-Control-Allow-Origin : 허용할 주소 }를 허용하여 문제를 해결할 수 있다.

 

이 부분은 시간이 되면 그림과 함께 자세히 다루어보려고 한다.

그리고 클라이언트 쪽에서 문제를 해결하는 방법을 찾아보려한다.

 

CORS의 보안 문제?? 어디가??

사실 이 윗부분은 CORS를 구글에 검색하면 나오는 보편적인 내용이다. CORS를 검색하면 가장 위에 나오는 MDN을 한 번 읽어본기만 해도 이해할 수 있는 내용이다. 만약 이 글이 이해가 안된다면, MDN에는 친절하게 그림과 함께 설명되어 있고, 친절하게 설명되어 있는 블로그들이 많다.

 

하지만 이 글을 적게 된 이유는 나처럼 이 글들을 읽고 이해가 안되는 부분이 있는 사람이 있을 것 같아서이다.

 

내가 이해가 안되는 부분은 보안상 문제라는 부분이었다.

처음에 나는 보안상 문제라고 하여,

허가 받지 않은 클라이언트가 서버의 정보를 몰래 빼오려고 요청하는 것을 막는 것인줄 알았다.

API를 만들어서 내 사이트에만 뿌리고 싶은데, 다른 사용자들이 맘대로 가져가서 사용하려고하는 것을 막으려는 건 줄 알았다.

 

하지만 이렇게 이해를 하면 막히는 부분이 생긴다. 

 

서버에 정보를 요청하면 정보는 보내주지만, 단지 http header에 { Access-Control-Allow-Origin : 허용할 주소 } 를 넣어서 보내고,

이 http header를 클라이언트의 브라우저에서 확인한 후, 자신이 허용할 주소가 아니라면 정보를 클라이언트에게 보여주지 않는 것이다.

 

서버에서 정보는 잘 보내줬는데 클라이언트에서 막을까?라는 생각과 내가 생각한 보안 문제가 아닐 것이라는 의심을 하였다.

그리고 그 이유를 찾아보았고, 맞는지는 모르겠지만 어느 유튜브에서 그 이유를 들을 수 있었다. 유튜브의 출처는 글 맨 하단에 작성하였다.

 

내가 알게된 CORS 정책의 이유를 예시를 들어서 설명하면,

 

내가 서비스를 만들었는데, a.com이라는 사이트를 만들고, b.com이라는 WEB API를 만들었다고 가정하자.

a.com에서는 로그인 한 후, 그 정보를 이용하여 b.com에서 데이터를 가져올 수 있다.

 

이런 상황에서 Trudy라는 정보를 탈취하고 싶은 사람은 t.com이라는 나쁜 사이트를 만들었다.

 

t.com에 사용자가 접속하면, b.com으로 정보를 요청해서 받아온다.

이 때, 클라이언트에 저장되어 있는 쿠키 같은 정보를 이용하여 사용자가 로그인되어 있는 상태로 요청하여 정보를 캐올 수 있다.

 

이 때 b.com에는 a.com만 허용하는 CORS 설정을 해놓았다면,

t.com에서 b.com으로 요청해서 받아오는 정보는 CORS 오류가 발생하게 되어 t.com한테 정보를 탈취당하지 않을 수 있다.

 

맥락과 흐름이 이렇게 이루어져, CORS는 이런 보안을 위하여 존재하는 정책이고,

이 부분도 시간이 난다면 그림과 함께 자세하게 설명하겠다.

 

 

[회고] CORS에 대한 공부를 하고,,, 

CORS에 대해 공부를 하며, 생각보다 보안의 의미가 크고, 글을 읽으며 내가 네트워크 보안이라는 과목을 듣지 않았다면 이해를 한 번에 할 수 없었을 것이라 생각이 들어, 전공에 대한 기초 지식의 중요성을 느꼈다...

 

그리고 문제를 해결할 때, 문제가 해결되었다고 끝내는 것이 아니라, 해결할 때 들었던 의문점들을 제대로 해소해야되겠고, 왜라는 의문을 더 깊게 해야되겠다는 생각이 들었다.

 

 

 

참고한 사이트

developer.mozilla.org/ko/docs/Web/HTTP/CORS

 

교차 출처 리소스 공유 (CORS)

교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라

developer.mozilla.org

developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy

 

동일 출처 정책

동일 출처 정책(same-origin policy)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다. 동일 출처 정책은 잠재적으로

developer.mozilla.org

youtu.be/6QV_JpabO7g

velog.io/@yejinh/CORS-4tk536f0db

 

Same-Origin Policy 동일 출처 정책과 CORS 에러

동일 출처 정책 Same-Origin Policy 동일 출처 정책(same-origin policy)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다.

velog.io

coding-groot.tistory.com/91

 

CORS Error의 올바른 해결법

CORS Error에 대해서 알아보자! * 이 글은 Flask로 예시를 보여주지만 딱히 Flask를 몰라도 이해하는데 아무 상관이 없을 겁니다! Flask 자체가 간결하고 간단하기 때문에 모르는 사람도 어떤 코드인지 �

coding-groot.tistory.com

velog.io/@jmkim87/%EC%A7%80%EA%B8%8B%EC%A7%80%EA%B8%8B%ED%95%9C-CORS-%ED%8C%8C%ED%97%A4%EC%B3%90%EB%B3%B4%EC%9E%90

 

지긋지긋한 CORS 파헤쳐보자

CORS (Cross Domain) 서버와의 통신을 위해 ajax나 XMLHttpRequest를 사용하다보면 CORS 에러가 나오는 경우가 종종 발생합니다. 할때마다 설정 방법이나 우회 방법을 항상 찾다보니 매번 고생하는거 같아 ��

velog.io

 

반응형

문제의 시작은 이렇다.

나는 데이터베이스에 20만개 이상의 데이터를 넣으려했고,

그렇기 위해서 하나하나 Insert를 하면 속도 측면에서 느리고, 반복문으로 넣게 되면 스택이 터지는 문제도 발생하였다.

따라서 데이터들을 CSV 파일로 변경 후, 그에 맞는 쿼리? 문을 날려서 넣는 방법을 택했다.

그 방법은 아래와 같다.

 

LOAD DATA INFILE "파일의 절대경로"

INTO TABLE transactions 
FIELDS TERMINATED BY ',' 
LINES TERMINATED BY '\n'
(transaction_id, user_id, type_id, money, date, category_id, payment_id, content);

 

이렇게 컬럼 명과 경로를 잘 입력해주면, CSV에 입력된 파일이 빠르게 들어간다고 하여, 이 방법을 택했다.

 

하지만 문제가 발생했다.

이 글의 제목처럼 --secure-file-priv 옵션이라 안된다고 한 것이다.

 

이 옵션에 의해서 내가 쓰는 쿼리? 명령? 문이 작동할 수 없다는 것이였다.

 

그리고 

 

SHOW VARIABLES LIKE "secure_file_priv";

혹은
SELECT @@GLOBAL.secure_file_priv;

 

라는 명령어로 어떤 경로에 있는 파일들만 LOAD DATA INFILE을 할 수 있는지 알 수 있다고 하였다.

 

 

구글링을 하니 3가지 경우가 있었다.

1. 저 경로가 특정 경로로 지정되어 있다

2. null

3. ""

 

 

만약 1번의 경우 내가 넣으려는 파일을 저 경로 안에 넣어주어서 해결하면 되고,

2번의 경우에는 아무것도 넣을 수 없고,

3번의 경우가 모든 경로에 있는 파일을 넣을 수 있다는 의미라고 한다.

 

 

그러니까 3번으로 바꾸어주어서 해결할 수 있고, 이건 my.cnf 파일을 수정하여 해결할 수 있다!라고 되어있다.

 

또는 LOAD DATA LOCALE INFILE "파일의 절대경로" 으로 해결 할 수 있다고 한다. 

하지만, 버젼 문제로 안된다고 하였고, 아마 내가 MariaDB를 사용하거나, 아니면 예전 버젼을 설치해서 문제가 되는 것 같았다.

그리고 배포할 서버에서, 최신 버젼을 지원하지 않을 수도 있으니, 나는 my.cnf를 수정하여 해결해보기로했다.

 

여기까지는 구글링하면 맨 위에 뜨는, 정석적인 방법이다. 아마 저 위 두 방법을 사용하면 대부분 문제가 해결될 것이다.

 

하지만 이 글을 쓰게 된 이유는 my.cnf 파일이 없는 경우이다.

 

분명 /etc/mysql/my.cnf 혹은 /etc/my.cnf에 있다고 하는데, 없다... 없다

my.ini

mysqld

 

등등 뭐든 다 찾아봤는데 없다!!!!

그냥 없다...my-small my-big 이런 파일로 있을 수도 있다해서 뒤졌는데 없다...

 

찾아보니 설치하는 방법에 따라 다르다고 한다.

누군가는 brew로 설치했을 것이고, 누구는 .dmg 파일로 설치했을 것인데, 이에 따라 달라지고, my.cnf 파일이 없는 경우가 있다고 한다.

 

그래서 저 위치에 my.cnf를 내가 직접 만들면 되지 않을까?했는데 일단 만들어지지 않는다.

 

sudo 옵션으로 만들어볼까 했지만, mysql이란 폴더가 없는데, 경로 설정이 저길로 안되어 있을 것 같아서 my.cnf를 찾아보기로 했다.

 

 

이걸 위해서 진짜 한참 구글링을 하던 와중 이 글을 보게 되었다.

 

serverfault.com/questions/346647/mysql-wheres-the-my-cnf-path

 

MySQL where's the my.cnf path?

I've managed to locate my install directory for MySQL: /usr/local/mysql/ Where can I find the path to my.cnf to know where I should configure the server? I've tried creating a /etc/my.cnf(as shown

serverfault.com

 

mysql --help | grep "Default options" -A 1

 

이 명령어로 my.cnf 찾을 수 있다고 하는 것이다.

덕분에 찾았다!!! 다른 사람들과는 조금 다른 경로에 있었다

그래서 그 my.cnf 파일을 수정하고 mysql 서버를 껐다 켰지만,, 안된다...

 

이것도 이상한게 사실 mysql 서버 재부팅은 service mysql restart 하면 된다는데, 나는 service라는 명령어를 실행할 수 없다고한다...ㅋㅋㅋ...

디비를 진짜 하나도 모를 때, 설치한 mariaDB라 설치할 때, 정말 많이 잘못 설치한 것 같았다. 아니면 MariaDB라서 그런가...

 

어쨌든 이 방법도 틀렸으니, 이제 다시 문제 탐구를 시작했다.

 

그래서 구글링을 열심히하다가 이 분의 글을 보게 되었다.

 

blog.naver.com/alsdomm/221737364291

 

ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option

MySQL에서 load data(또는 select into outfile, load_file()함수)를 사용할 때, 다음과 같은 오류가 ...

blog.naver.com

 

최근 글인데도(2019년) 네이버 블로그에 작성하신게 신기했고, 구글에 네이버 글이 검색된다는 것도 의아했지만, 덕분에 문제를 해결했다.

 

MacOS 설정 -> MySQL -> Configuration에서 해답을 찾을 수 있었다.

MySQL

현재는 맨 위에 Configuration File의 경로가 지정되어 있었지만, 원래는 되어 있지 않았다.

이 Configuration File 부분을 아까 grep으로 찾은 파일로 설정해주니 해결되었다.

 

왜 맨날 나는 CLI로 먼저 끝장을 보려고 하는지 모르겠다.. 다음부터 이렇게 제공해주는 설정부터 보며 문제를 해결해봐야겠다.

 

그리고 아마 구글링을 하다가 흘러흘러 여길로 왔을거라 생각하여, 중간에 생략했지만, my.cnf 파일에

 

[mysqld]

secure-file-priv=""


이것을 추가해주어야 문제가 해결된다! 이건 구글링하면 바로 나오니, 쉽게 해결하실 수 있을 것이라 생각한다.

혹여나 모르겠으면 댓글 남겨주시면 도와드리겠습니다

진짜 오늘 이 문제 때문에 MariaDB 삭제하고 MySQL 설치할까 고민했었는데 해결해서 너무 행복했다...ㅎㅎ

반응형

자바스크립트에서는 set을 구조분해할당으로 배열로 바꿀 수 있다.

 

set을 배열로 바꿈으로 쉽게 중복을 제거할 수 있는데,

 

예를 들면

 

let a = new Set([1,2,3,1])

let b = [...a]

 

이렇게 하면, 쉽게 중복(예제에서는 1)이 제거된 배열을 구할 수 있다.

 

하지만 타입스크립트에서는 

 

'Set<any>' 형식이 배열 형식 또는 문자열 형식이 아닙니다.

 

라는 오류가 발생한다.

 

구조분해할당은 원래 배열이나 객체, 문자열을 해체하는 것이기 때문에, set은 해당이 안되는 것 같다.

javascript는 유연하여 set도 구조분해할당해주지만, 엄밀하게 타입을 정하는 typescript에서는 오류를 띄운다.

 

따라서 이 문제를 해결하기 위해서는 

 

Array.from(집합) 을 사용해주면 된다.

위의 예제를 예를 들면

 

let a = new Set([1,2,3,1])

let b = [Array.from(a)]

 

이렇게 해결해주면 된다.

set을 문자열로 형변환을 해주기 때문에 문제가 발생하지 않는다.

 

 

반응형

+ Recent posts