Repository: im-d-team/Dev-Docs Branch: master Commit: 785fb0814164 Files: 248 Total size: 1.4 MB Directory structure: gitextract_vbaffuo6/ ├── .github/ │ └── workflows/ │ └── action.yml ├── .mergify.yml ├── Android/ │ └── application fundamentals.md ├── Browser/ │ ├── BrowserXY.md │ ├── Cookie.md │ ├── Cookie_Store.md │ ├── FOUC.md │ ├── HTTP2_Websocket.md │ ├── IndexedDB_WebSQL.md │ ├── Layer_Model.md │ ├── WebWorker.md │ ├── Worklet.md │ ├── 웹 브라우저의 작동 원리.md │ └── 최신_브라우저의_내부_살펴보기.md ├── CS/ │ ├── Binding.md │ ├── Bomb-Lab(1).md │ ├── Call-By-Sharing.md │ ├── Counting-sort.md │ ├── Graph.md │ ├── Memory.md │ ├── Radix-sort.md │ ├── aspect-oriented-programming.md │ ├── cohension&coupling.md │ ├── compression.md │ ├── dependency-inversion-principle.md │ ├── grasp.md │ ├── information_theory.md │ ├── integer_representation.md │ ├── interface-segregation-principle.md │ ├── liskov_substitution_principle.md │ ├── methods_in_IPC.md │ ├── non-blocking.md │ ├── non-linear-search.md │ ├── open-closed-principle.md │ ├── soc.md │ ├── srp.md │ ├── union-find.md │ ├── 페이징과 세그먼테이션.md │ └── 플로이드-와샬-알고리즘.md ├── CSS/ │ ├── CJK.md │ ├── WebToMobile.md │ └── safe-area.md ├── Database/ │ ├── DB Connection Pool.md │ ├── Query Builder ( Knex.js).md │ └── Types of Databases.md ├── Deprecated/ │ ├── AMD와 CommonJS.md │ ├── Async-Await.md │ ├── B_EventLoop.md │ ├── B_Module.md │ ├── CORS(Cross-Origin Resource Sharing).md │ ├── CSS 애니메이션 vs JS 애니메이션.md │ ├── CallByReference.md │ ├── EventLoop.md │ ├── EventLoop_Advanced.md │ ├── Funtional.md │ ├── Higher_Order_Functions.md │ ├── Javascript_BuildTool.md │ ├── Module.md │ ├── Promise1.md │ ├── Promise2.md │ ├── Reactive.md │ ├── Repaint와 Reflow.md │ ├── WebWorker.md │ ├── animation.md │ ├── setState.md │ ├── 기본적인 렌더링 최적화 방법.md │ ├── 웹 브라우저의 작동 원리.md │ └── 점진적향상_우아한하향.md ├── Design_Pattern/ │ ├── Composite.md │ ├── JSP model.md │ ├── MSA.md │ ├── MVC1, MVC2.md │ ├── MVC_MVP_MVVM.md │ ├── Memoization.md │ ├── RxJS.md │ ├── Singleton.md │ └── Throttle and Debounce.md ├── ECMAScript/ │ ├── ArrowFunction.md │ ├── Destructuring_Assignment.md │ ├── ECMA2019.md │ ├── ES6-module-in-Browser.md │ ├── Generator와 async-await.md │ ├── Includes_IndexOf.md │ ├── Iteration_Protocol.md │ ├── ModulePattern_class.md │ ├── Number_isNaN.md │ ├── Spread_Operator.md │ └── Tagged_Template_Literals.md ├── Git/ │ └── gitBy_.git.md ├── HTML/ │ ├── ARIA.md │ ├── DOM API.md │ ├── DOM.md │ ├── HTML-Templating.md │ ├── Head_Meta.md │ ├── Standard&QuirksMode.md │ ├── WebM&WebP.md │ ├── input태그의_value바꾸기(input태그의_dirty flag).md │ ├── preload&prefetch.md │ └── 웹 컴포넌트(Web Component).md ├── Java/ │ ├── ArrayList vs LinkedList 그리고 Vector.md │ ├── Comparable vs Comparator.md │ ├── Dependency Injection(DI).md │ ├── JSP와 Servlet처리.md │ ├── JVM(Java Virtual Machine).md │ ├── Java Garbage Collection(GC).md │ ├── Mybatis.md │ ├── Set.md │ ├── String, StringBuilder, StringBuffer.md │ ├── String,StringBuilder, StringBuffer차이.md │ ├── Upcasting과 Downcasting.md │ ├── WAS.md │ ├── copy-object.md │ ├── date-api-in-java.md │ └── junit-setup.md ├── Javascript/ │ ├── Ajax.md │ ├── Animation.md │ ├── B_Async.md │ ├── B_Call_Apply_Bind.md │ ├── B_Callback.md │ ├── B_Class.md │ ├── B_Function.md │ ├── B_Type.md │ ├── Build Tool.md │ ├── CallStack.md │ ├── Closure.md │ ├── Control_CSSOM.md │ ├── DocumentFragment.md │ ├── Event Delegation.md │ ├── InsertAdjacentHTML.md │ ├── JavaScript의 this.md │ ├── Javascript_Engine.md │ ├── Javascript_메모리관리.md │ ├── Javascript의_동작원리-변수객체(VariableObject).md │ ├── Javascript의_동작원리-실행컨텍스트(Execution Contexts).md │ ├── Jest.md │ ├── Learning_more_about_this.md │ ├── Module.md │ ├── MouseEvent.md │ ├── Object.create&Object.assign.md │ ├── Observer.md │ ├── Optional_Chaining.md │ ├── PromisePattern.md │ ├── Prototype_Chain.md │ ├── Proxy.md │ ├── Reduce.md │ ├── Redux State 정규화.md │ ├── Regular_Expressions.md │ ├── Scope.md │ ├── Some_Every.md │ ├── Storybook.md │ ├── Sync&Async_Multi&Single_Thread.md │ ├── TimeInJS.md │ ├── Variable.md │ ├── WebRTC.md │ ├── Web_Storage_API.md │ ├── ajax(2).md │ ├── bind.md │ ├── object.md │ ├── object_create_pattern-constructor.md │ ├── object_생성패턴.md │ ├── prototype(2).md │ ├── prototype.md │ ├── scope_this.md │ ├── throttling과 rAF.md │ ├── tricks_of_js.md │ ├── underscore와 lodash그리고 Native.md │ ├── window.history.md │ ├── 논리연산자.md │ ├── 렉시컬_속이기(eval).md │ ├── 배열 내장함수.md │ ├── 상태관리 라이브러리.md │ ├── 이벤트 루프(Event Loop).md │ ├── 클래스(class).md │ ├── 클로저.md │ └── 함수 선언.md ├── LICENSE ├── Language/ │ ├── Currying.md │ ├── Lamda.md │ ├── Reactive.md │ ├── XML_JSON.md │ ├── 고차함수(High Order Function).md │ └── 함수형 프로그래밍.md ├── ML/ │ └── 머신러닝이란.md ├── Network/ │ ├── 3-way handshaking & 4-way handshaking.md │ ├── CORS.md │ ├── DHCP&DNS.md │ ├── Flow control.md │ ├── HTTP3.md │ ├── IP.md │ ├── JSend.md │ ├── OSI7 Layer.md │ ├── REST API.md │ ├── REST.md │ ├── SOAP API.md │ ├── Subnetmask.md │ ├── Switch.md │ ├── TCP & UDP.md │ ├── TypesOfIP.md │ ├── comet.md │ ├── congestion control.md │ ├── get&post.md │ ├── http-caching.md │ ├── 로드밸런싱 & 클러스터링.md │ └── 사용자 인증 방식(Cookie, Session & oAuth 2.0 & JWT).md ├── Node.js/ │ ├── make_meta_file.md │ └── nodejs의_특징.md ├── OpenCV/ │ └── 이미지전처리.md ├── Performance/ │ ├── DeadLock(교착상태).md │ ├── HTTP2.0의 필요성.md │ ├── Reflow Repaint.md │ ├── Throttling vs Debouncing.md │ ├── requestAnimationFram(rAF).md │ ├── 기본적인 렌더링 최적화 방법.md │ ├── 서버 사이드 렌더링(SSR).md │ └── 점진적향상_우아한하향.md ├── README.md ├── React/ │ ├── Component, Props, State.md │ ├── Composition.md │ ├── Element와 Component.md │ ├── ImmutableState.md │ ├── React Server Components.md │ ├── React.memo.md │ ├── React의 Lifecycle Event.md │ ├── SWR.md │ ├── Virtual DOM.md │ └── props와 state.md ├── Rules/ │ ├── Commit.md │ └── Markdown.md ├── Security/ │ ├── HTTPS와 SSL.md │ ├── Response_Header_Security.md │ ├── SQL_Injection.md │ └── 리만가설과 소수정리.md ├── Tool/ │ ├── Chrome_80_DevTool.md │ ├── Framework vs Library.md │ └── Package Manager.md ├── Typescript/ │ ├── 인터페이스(Interface).md │ ├── 정적 타이핑.md │ ├── 제네릭(Generic).md │ └── 클래스(class).md ├── Vue/ │ └── Vue_LifeCycle.md ├── WPF/ │ └── wpf.md └── assets/ ├── IndexDB/ │ ├── TodoList/ │ │ ├── index.html │ │ ├── js/ │ │ │ ├── indexDB.js │ │ │ └── todo.js │ │ └── todoStyle.css │ └── index2.html └── TEST/ ├── bigfile.html └── window.history.demo.html ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/action.yml ================================================ name: "Pull Request Action" on: pull_request: types: [opened] jobs: test: runs-on: ubuntu-latest steps: - name: Create link uses: Im-D/Im-Bot/packages/pr-supporter@master with: myToken: ${{ secrets.GITHUB_TOKEN }} - name: Create reviewRequest uses: Im-D/Im-Bot/packages/pr-reviewer@master with: myToken: ${{ secrets.GITHUB_TOKEN }} - name: Create Link at README file uses: Im-D/Im-Bot/packages/update-readme@master with: myToken: ${{ secrets.GITHUB_TOKEN}} linkLocTarget: '### 📅 History' ================================================ FILE: .mergify.yml ================================================ pull_request_rules: - name: Automatic merge on review # https://doc.mergify.io/examples.html#require-all-requested-reviews-to-be-approved conditions: - "#approved-reviews-by>=4" - "#changes-requested-reviews-by=0" - base=master - label=approval + 3 actions: merge: method: merge delete_head_branch: {} - name: Add Label needs author response conditions: - "#changes-requested-reviews-by>=1" actions: label: add: ["needs author response"] remove: ["needs review"] - name: Remove Label needs author response conditions: - "#changes-requested-reviews-by=0" actions: label: add: ["needs review"] remove: ["needs author response"] - name: Add Label approval + 1 conditions: - "#approved-reviews-by=1" actions: label: add: ["approval + 1"] - name: Add Label approval + 2 conditions: - "#approved-reviews-by=2" actions: label: add: ["approval + 2"] remove: ["approval + 1"] - name: Add Label approval + 3 conditions: - "#approved-reviews-by=3" actions: label: add: ["approval + 3"] remove: ["approval + 2"] ================================================ FILE: Android/application fundamentals.md ================================================ # 안드로이드 (Android) Android 앱은 Kotlin, Java, C++ 언어를 사용하여 작성할 수 있습니다. Android SDK(Software Development Kit) 도구는 모든 데이터 및 리소스 파일과 함께 코드를 컴파일하여 하나의 **APK(Android PacKage)** 를 만듭니다. Android Package는 접미사가 .apk인 아카이브 파일입니다. 한 개의 APK 파일에는 Android 앱의 모든 콘텐츠가 들어 있으며, Android로 구동하는 기기가 앱을 설치할 때 바로 이 파일을 사용합니다. Android 시스템은 **최소 권한의 원리( Principle of least privilege )** 를 구현합니다. 다시 말해, 각 앱은 기본적으로 자신의 작업을 수행하기 위해 **필요한 구성 요소에만 액세스 권한을 가지고 그 이상은 허용되지 않습니다.** 이렇게 하면 대단히 안전한 환경이 구성되어 앱이 시스템에서 권한을 부여받지 못한 부분에는 액세스할 수 없게 됩니다. 앱이 다른 앱과 데이터를 공유하고 시스템 서비스에 액세스하는 방법은 여러 가지가 있습니다. 그 중에서 '권한'을 살펴보도록 하겠습니다. 앱은 사용자의 연락처, SMS 메시지, 마운트 가능한 저장소(SD 카드), 카메라, 블루투스를 비롯한 여러 가지 기기 데이터에 액세스할 '권한'을 요청할 수 있습니다. 사용자는 이러한 **권한(Permission)** 을 명시적으로 부여해야 합니다. > 권한(Permission) 부여하는 방법 앱은 앱 매니페스트에 태그를 포함하여 필요한 권한을 추가해야 합니다. 예를 들어 **SMS 메시지를 보내야 하는 앱** 은 [매니페스트(manifest)](https://developer.android.com/guide/topics/manifest/manifest-intro?hl=ko)에 다음 줄이 있어야 합니다. ```xml ... ``` # 앱 기본요소 (Application Fundamentals) - **Manifests**: 구성 요소를 선언하고 앱에 필수적인 기기 특징을 선언할 수 있는 매니페스트 파일. - **App components**: 앱을 정의하는 핵심 프레임워크 구성 요소. - **Resource**: 앱 코드로부터 별도로 분리되어 있으며 앱이 다양한 기기 구성에 맞게 자신의 동작을 안정적으로 최적화할 수 있도록 하는 리소스. ## 1. Manifests 모든 앱 프로젝트는 프로젝트 소스 세트의 루트에 **AndroidManifest.xml** 파일(정확히 이 이름)이 있어야 합니다. 매니페스트 파일은 Android 앱에서 필요한 모든 구성요소, Android 빌드 도구, Android 운영체제 및 Google Play에 앱에 관한 필수 정보를 설명합니다. 정리하면 다음과 같습니다. - Package: 앱의 패키지 이름(일반적으로 코드의 네임스페이스와 일치) - App Components: 앱의 구성 요소(모든 Activity, Service, Broadcast Receiver, Content Provider 포함) - Permission: 앱이 시스템 또는 다른 앱의 보호된 부분에 액세스하기 위해 필요한 권한 - 앱에 필요한 하드웨어 및 소프트웨어 기능 매니페스트 파일의 추가적인 역할은 다음을 참고해주세요. - [매니페스트 파일](https://developer.android.com/guide/components/fundamentals?hl=ko#Manifest) - [앱 매니페스트 개요](https://developer.android.com/guide/topics/manifest/manifest-intro?hl=ko) ## 2. App components 앱 구성 요소(App components)는 Android 앱의 필수적인 기본 구성 요소입니다. 각 구성 요소는 **시스템이나 사용자가 앱에 들어올 수 있는 진입점**입니다. **다른 구성 요소에 종속되는 구성 요소**도 있습니다. 각 유형은 **뚜렷한 목적**을 수행하고 **각자 나름의 수명 주기**가 있어 구성 요소의 생성 및 소멸 방식을 정의합니다. ### 1) Activities 액티비티는 사용자와 상호작용하기 위한 진입점입니다. 이것은 **사용자 인터페이스를 포함한 화면 하나**를 나타냅니다. 여러 액티비티가 함께 작동하여 앱에서 짜임새 있는 사용자 환경을 구성하는 것은 사실이지만, **각자 서로 독립**되어 있습니다. 액티비티 하나를 `Activity` 클래스의 하위 클래스로 구현합니다. #### Activity Stack 구조 #### Activity Life Cycle ### 2) Services Service는 **백그라운드**에서 오래 실행되는 작업을 수행할 수 있는 애플리케이션 구성 요소이며 **사용자 인터페이스를 제공하지 않습니다.** - [포그라운드] 사용자가 다른 앱에 있는 동안에 *백그라운드에서 음악을 재생*한다. - [백그라운드] 사용자와 액티비티 간의 상호작용을 차단하지 않고 *네트워크를 통해 데이터를 가져온다*. - [바인드] 다른 구성 요소(예: 액티비티)가 서비스를 시작한 다음 실행되도록 두거나 자신에게 *바인딩*하여 상호작용한다. (라이브 배경화면, 알림 리스너, 화면 보호기, 입력 메서드, 접근성 서비스 및 여러 가지 기타 핵심 서비스 기능) 시작된 서비스는 작업이 완료될 때까지 해당 서비스를 계속 실행하라고 **시스템**에 지시합니다. ```xml ... ... ``` ##### 서비스는 Service 하위 클래스로 구현됩니다. ##### 참고: Android 5.0(API 레벨 21) 이상을 대상으로 하는 앱의 경우 `JobScheduler` 클래스를 사용하여 작업을 예약하세요. ### 3) Broadcast receivers Broadcast Receiver는 **시스템이 정기적인 사용자 플로우 밖에서 이벤트를 앱에 전달하도록 지원하는 구성 요소**로, 앱이 시스템 전체의 브로드캐스트 알림에 응답할 수 있게 합니다. ### 4) Content providers 콘텐츠 제공자는 파일 시스템, SQLite 데이터베이스, 웹상이나 앱이 액세스할 수 있는 다른 모든 영구 저장 위치에 저장 가능한 앱 데이터의 공유형 집합을 관리합니다. 다른 앱은 콘텐츠 제공자를 통해 해당 데이터를 쿼리하거나, 콘텐츠 제공자가 허용할 경우에는 수정도 가능합니다. 구성 요소 유형 네 가지 중 세 가지 **(Activities, Services, Broadcast Receiver)** 는 **인텐트라는 비동기식 메시지로 활성화**됩니다. 인텐트는 런타임에서 각 구성 요소를 서로 바인딩합니다. 이것은 일종의 메신저라고 생각하면 됩니다. 즉 구성 요소가 어느 앱에 속하든 관계없이 다른 구성 요소로부터 작업을 요청하는 역할을 합니다. ## 3. Resource 리소스는 코드에서 사용하는 추가 파일과 정적인 콘텐츠입니다. 예를 들어 비트맵, 레이아웃 정의, 사용자 인터페이스 문자열, 애니메이션 지침 등이 있습니다. 이미지나 문자열과 같은 앱 리소스는 항상 코드에서 외부화해야 합니다. 그래야 이들을 독립적으로 유지관리할 수 있습니다. 특정 기기 구성에 대한 대체 리소스도 제공해야 합니다. 이것은 특별하게 명명한 리소스 디렉토리에 그룹화하는 방법을 씁니다. Android는 런타임에 현재 구성을 근거로 적절한 리소스를 사용합니다. 예를 들어 여러 가지 화면 크기에 따라 여러 가지 UI 레이아웃을 제공하거나 언어 설정에 따라 각기 다른 문자열을 제공하고자 할 수 있습니다. 앱 리소스를 외부화하면 프로젝트 R 클래스에서 발생하는 리소스 ID로 액세스할 수 있습니다. 자세한 내용은 다음을 참고해주세요. - [앱 리소스 개요](https://developer.android.com/guide/topics/resources/providing-resources?hl=ko#top_of_page) ## 4. Intent Intent는 **메시징 객체**로, **다른 앱 구성 요소로부터 작업을 요청하는 데 사용**할 수 있습니다. 기본적인 사용 사례는 크게 세 가지로 나눌 수 있습니다. - Starting an activity - Starting a service - Delivering a broadcast ### 유형 - **명시적 인텐트**는 인텐트를 충족하는 애플리케이션이 무엇인지 지정합니다. 이를 위해 대상 앱의 패키지 이름 또는 완전히 자격을 갖춘 구성 요소 클래스 이름을 제공합니다. 명시적 인텐트는 일반적으로 앱 안에서 구성 요소를 시작할 때 씁니다. 시작하고자 하는 액티비티 또는 서비스의 클래스 이름을 알고 있기 때문입니다. 예를 들어, 사용자 작업에 응답하여 새로운 액티비티를 시작하거나 백그라운드에서 파일을 다운로드하기 위해 서비스를 시작하는 것 등이 여기에 해당됩니다. - **암시적 인텐트**는 특정 구성 요소의 이름을 대지 않지만, 그 대신 수행할 일반적인 작업을 선언하여 다른 앱의 구성 요소가 이를 처리할 수 있도록 해줍니다. 예를 들어 사용자에게 지도에 있는 한 위치를 표시하고자 하는 경우, 암시적 인텐트를 사용하여 해당 기능을 갖춘 다른 앱이 지정된 위치를 지도에 표시하도록 요청할 수 있습니다. #### 암시적 인텐트 수신하기 앱이 수신할 수 있는 암시적 인텐트가 어느 것인지 알리려면, 요소를 사용하여 각 앱 구성 요소에 대해 하나 이상의 인텐트 필터를 매니페스트 파일에 선언합니다. 각 인텐트 필터는 인텐트의 작업, 데이터 및 카테고리를 기반으로 어느 유형의 인텐트를 수락하는지 지정합니다. **시스템은 인텐트가 인텐트 필터 중 하나를 통과한 경우에만 암시적 인텐트를 앱 구성 요소에 전달합니다.** > 예를 들어 데이터 유형이 텍스트인 경우 ACTION_SEND 인텐트를 수신할 인텐트 필터가 있는 액티비티 선언은 다음과 같습니다. ```xml ``` > 소셜 공유 앱의 매니페스트 파일 예시 ```xml ``` ### Reference * [애플리케이션 기본 항목](https://developer.android.com/guide/components/fundamentals?hl=ko) ================================================ FILE: Browser/BrowserXY.md ================================================ # 브라우저의 XY 브라우저에 event가 발생했을 때에 x, y 좌표 값을 얻는 방법에는 크게 4가지가 있다. - clientX / clientY - pageX / pageY - screenX / screenY - offsetX / offsetY 이렇게 4가지가 존재하는데 어떤 차이가 있는지 알아보았다. ## clientX / clientY client는 viewport와 매칭된다고 생각하면 쉽다. 브라우저의 화면인 viewport를 기준으로 좌표를 계산한다. 브라우저의 현재 보이는 화면을 기준으로 어느 곳을 선택했는지 반환한다. 스크롤을 하게 되어도 화면의 같은 곳을 클릭하면 같은 값이 반환된다. 브라우저의 크기가 달라져도 화면의 같은 곳에서는 같은 값이 변경된다. 어느 정도 절대값이라고 할 수 있다. ## pageX / pageY page는 html문서와 매칭된다. client는 현재 브라우저에 보여지는 부분이다. page는 그것과 상관없이 렌더된 html문서가 기준이다. 스크롤을 하게 되면 값이 달라진다. 브라우저의 크기를 줄여도 값과는 상관없다. ## screenX / screenY screen은 user device의 모니터를 기준으로 한다. 모니터의 어느 부분을 클릭했는지 물리적인 값을 반환한다. 따라서 브라우저 상단의 tab, bookmark와 같은 정보들의 높이도 포함한다. 스크롤을 해도 달라지지 않는다. 브라우저의 크기가 달라지는 것은 관계가 없다. 다만 브라우저를 작게하여 모니터상의 브라우저 위치를 이동하면 값이 달라질 수 있다. ## offsetX / offsetY offset은 이벤트가 걸린 DOM기준이다. 예를들어 div를 클릭했다면 div의 왼쪽 상단 모서리가 0, 0이 된다. 스크롤을 해도 달라지지 않는다. 브라우저가 달라져도 값은 달라지지 않는다. 다만 event.target의 크기가 변경된다면 달라질 수 있다. ## 사진으로 보기 글로만 보면 상당히 헷갈린 개념이다. 여러 링크에서 사진들을 모아봤으니 눈으로 확인하자. ![](https://user-images.githubusercontent.com/24724691/59552616-4970c500-8fc4-11e9-93ae-a15ebd27b2cb.png) ![](https://user-images.githubusercontent.com/24724691/59552615-4970c500-8fc4-11e9-9995-fb8bbbcc6cf3.jpg) ![](https://user-images.githubusercontent.com/24724691/59552617-4a095b80-8fc4-11e9-9a39-c56ce0d2baf1.png) 마지막 사진은 - yellow : screen - blue : client - red : page 로 매칭된다. 사진의 출처는 아래에 링크로 대체한다. ## 예제로 확인하기 헷갈린 개념은 직접 디버깅하는 것이 좋다. ```html Document
target
``` --- ### 참고자료 - [screen, client, page, offset compare](https://m.blog.naver.com/PostView.nhn?blogId=sung487&logNo=220418825028&proxyReferer=https%3A%2F%2Fwww.google.com%2F) - [clientX, offsetX, pageX, screenX의 차이](http://megaton111.cafe24.com/2016/11/29/clientx-offsetx-pagex-screenx%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90/) - [What is the difference between screenX/Y, clientX/Y and pageX/Y?](https://stackoverflow.com/questions/6073505/what-is-the-difference-between-screenx-y-clientx-y-and-pagex-y) - [What is the difference between pageX/Y clientX/Y screenX/Y in Javascript?](https://stackoverflow.com/questions/9262741/what-is-the-difference-between-pagex-y-clientx-y-screenx-y-in-javascript/17705548) ================================================ FILE: Browser/Cookie.md ================================================ 브라우저에는 다양한 저장소가 있다.

Storage

> [참고] Chrome 개발자 도구 - Application Tab 위 사진은 Chrome 개발자 도구에 들어가서 Application Tab을 누르게 되면 왼쪽 메뉴에 보이는 Storage로 총 **5개**가 있다. 그 중 가장 아래에 있는 Cookie에 대해서 알아보자 # Cookie 쿠키는 브라우저에 저장되는 작은 크기의 문자열로, **RFC 6265** 명세에서 정의한 HTTP 프로토콜의 일부이다. 서버가 HTTP 응답 헤더(header)의 `Set-Cookie`에 내용을 넣어 전달하면, 브라우저는 이 내용을 자체적으로 브라우저에 저장하는데 이것이 쿠키이다. 브라우저는 사용자가 쿠키를 생성하도록 동일 서버(사이트)에 접속할 때마다 쿠키 내용을 Cookie 요청 헤더에 넣어서 함께 전달한다. 이를 사용하여 쿠키는 클라이언트 식별 같은 인증에 가장 많이 쓰인다. 1. 사용자가 로그인하면 서버는 HTTP 응답 헤더의 `Set-Cookie`에 담긴 세션 식별자(session identifier) 정보를 사용해 쿠키를 설정한다. 2. 사용자가 동일 도메인에 접속하려고 하면 브라우저는 HTTP Cookie 헤더에 인증 정보가 담긴 고유값(세션 식별자)을 함께 서버에 요청으로 보낸다. 3. 서버는 브라우저가 보낸 요청 헤더의 세션 식별자를 읽어 사용자를 식별한다. `document.cookie` 프로퍼티를 이용하면 브라우저에서도 쿠키에 접근할 수 있다. ```js console.log(document.cookie); ``` `document.cookie`는 `name=value` 쌍으로 구성되어 있으며, 쌍은 `;`로 구분된다. 쌍 하나는 하나의 독립된 쿠키이다. `document.cookie`에 직접 값을 쓸 수 있다. cookie는 데이터 프로퍼티가 아닌 접근자(accessor) 프로퍼티이다. ```js // getter document.cookie = "user=SeonHyungJo"; console.log(document.cookie); ``` `document.cookie`에 값을 할당하면, 브라우저는 이 값을 받아 해당 쿠키를 갱신한다. 다른 쿠키의 값은 변경되지 않는다. ```js document.cookie = "user=SeonHyungJo"; console.log(document.cookie); // user=SeonHyungJo document.cookie = "newuser=SeonHyungJo"; console.log(document.cookie); // user=SeonHyungJo; newuser=SeonHyungJo ``` 쿠키의 이름과 값엔 특별한 제약이 없다. 하지만 형식의 유효성을 일관성 있게 유지하기 위해 반드시 내장 함수 `encodeURIComponent`를 사용하여 이름과 값을 이스케이프 처리를 해주는 것이 좋다. ```js let name = 'origin'; let value = "github/SeonHyungJo"; document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value); console.log(document.cookie); // origin=github%2FSeonHyungJo ``` ## 단점 - 용량 : **4kb**로 매우 작은 용량이다. - 속도 : 요청 때마다 포함되어서 간다. 작은 용량이라고 하지만 필요 없는 데이터가 전달되는 낭비가 발생한다. - 보안 : 위험성이 크다. ## 옵션 ### path - `path=/mypath` URL path(경로)의 접두사로, 경로나 경로의 하위 경로에 있는 페이지만 쿠키에 접근할 수 있다. 절대 경로이어야 하고, 기본값은 현재 경로이다. `path=/user` 옵션을 사용하여 설정한 쿠키는 `/user`과 `/user/something`에선 볼 수 있지만, `/partner` 이나 `/adminpage`에선 볼 수 없다. 특별한 경우가 아니라면, path 옵션을 `path=/`같이 루트로 설정해 웹사이트의 모든 페이지에서 쿠키에 접근할 수 있도록 한다. ### domain - `domain=imdev.com` 쿠키에 접근 가능한 domain(도메인)을 지정한다. 다만, 몇 가지 제약이 있어서 아무 도메인이나 지정할 수 없다. domain 옵션에 아무 값도 넣지 않았다면, 쿠키를 설정한 도메인에서만 쿠키에 접근할 수 있다. `imdev.com`에서 설정한 쿠키는 `other.com`에서 얻을 수 없다. 서브 도메인(subdomain)인 `forum.imdev.com`에서도 쿠키 정보를 얻을 수 없다. ```js // imdev.com에서 쿠키를 설정함 document.cookie = "user=SeonHyungJo" // imdev.com의 서브도메인인 forum.imdev.com에서 user 쿠키에 접근하려 함 alert(document.cookie); // 찾을 수 없음 ``` 서브 도메인이나 다른 도메인에서 쿠키에 접속할 방법은 없다. `imdev.com`에서 생성한 쿠키를 `other.com`에선 절대 전송받을 수 없다. 이런 제약사항은 안정성을 높이기 위해 만들어졌는데, 민감한 데이터가 저장된 쿠키는 관련 페이지에서만 볼 수 있도록 하기 위해서다. 정말 `forum.imdev.com`과 같은 서브 도메인에서 `imdev.com`에서 생성한 쿠키 정보를 얻을 방법이 없는 걸까? `imdev.com`에서 쿠키를 설정할 때 domain 옵션에 루트 도메인인 `domain=imdev.com`을 명시적으로 설정해 주면 된다. ```js // imdev.com에서 // 서브 도메인(*.imdev.com) 어디서든 쿠키에 접속하게 설정할 수 있다. document.cookie = "user=SeonHyungJo; domain=imdev.com" // 이렇게 설정하면 // forum.imdev.com와 같은 서브도메인에서도 쿠키 정보를 얻을 수 있다. alert(document.cookie); // user=SeonHyungJo 쿠키를 확인할 수 있다. ``` 하위 호환성 유지를 위해 (imdev.com 앞에 점을 붙인) `domain=.imdev.com`도 `domain=imdev.com`과 같이 작동한다. 오래된 표기법이긴 하지만 구식 브라우저를 지원하려면 이 표기법을 사용하는 것이 좋다. 이렇게 domain 옵션값을 적절히 사용하면 서브 도메인에서도 쿠키에 접근할 수 있다. > 테스트 해보기(도메인 설정을 한 경우, 안 한 경우) ### expires와 max-age expires(유효 일자)나 max-age(만료 기간) 옵션이 지정되어있지 않으면, 브라우저가 닫힐 때 쿠키도 함께 삭제된다. 이런 쿠키를 **세션 쿠키(session cookie)** 라 부른다. expires 나 max-age 옵션을 설정하면 브라우저를 닫아도 쿠키가 삭제되지 않는다. - `expires=Tue, 19 Jan 2038 03:14:07 GMT` 브라우저는 설정된 유효 일자까지 쿠키를 유지하다가, 해당 일자가 도달하면 쿠키를 자동으로 삭제한다. 쿠키의 유효 일자는 반드시 GMT(Greenwich Mean Time) 포맷으로 설정해야 한다. `date.toGMTString` (`toUTCString`) 을 사용하면 해당 포맷으로 쉽게 변경할 수 있다. ```js // 지금으로부터 하루 뒤 let date = new Date(Date.now() + 86400e3); date = date.toGMTString(); document.cookie = "user=SeonHyungJo; expires=" + date; ``` expires 옵션값을 과거로 설정하면 삭제된다. - `max-age=3600` max-age는 expires 옵션의 대안으로, 쿠키 만료 기간을 설정할 수 있다. 현재부터 설정하고자 하는 만료일시까지의 시간을 초로 환산한 값을 설정한다. 0이나 음수값을 설정하면 쿠키는 바로 삭제된다. ```js // 1시간 뒤에 쿠키가 삭제된다. document.cookie = "user=SeonHyungJo; max-age=3600"; // 만료 기간을 0으로 지정하여 쿠키를 바로 삭제한다 document.cookie = "user=SeonHyungJo; max-age=0"; ``` ### secure - `secure` 이 옵션을 설정하면 HTTPS로 통신하는 경우에만 쿠키가 전송된다. secure 옵션이 없으면 기본 설정이 적용되어 `http://imdev.com`에서 설정(생성)한 쿠키를 `https://imdev.com`에서 읽을 수 있고, `https://imdev.com`에서 설정(생성)한 쿠키도 `http://imdev.com`에서 읽을 수 있다. 쿠키는 기본적으로 도메인만 확인하지 프로토콜을 확인하지 않는다. 하지만 secure 옵션이 설정된 경우, `https://imdev.com`에서 설정한 쿠키는 `http://imdev.com`에서 접근할 수 없다. 쿠키에 민감한 내용이 저장되어 있어 암호화되지 않은 HTTP 연결을 통해 전달되는 걸 원치 않는다면 이 옵션을 사용하면 된다. ```js // (https:// 로 통신하고 있다고 가정 중) // 설정한 쿠키는 HTTPS 통신시에만 접근할 수 있음 document.cookie = "user=SeonHyungJo; secure"; ``` ## samesite 다른 보안 속성인 samesite 옵션은 크로스 사이트 요청 위조(cross-site request forgery, XSRF) 공격을 막기 위해 만들어진 옵션이다. 아래 XSRF 공격 시나리오를 통해 이 속성의 동작 방식과 언제 이 속성을 유용하게 사용할 수 있는지 알아보자. ### XSRF 공격 현재 bank.com에 로그인되어 있을 때. 해당 사이트에서 사용되는 인증 쿠키가 브라우저에 저장되고, 브라우저는 bank.com에 요청을 보낼 때마다 인증 쿠키를 함께 전송한다. 서버는 전송받은 쿠키를 이용해 사용자를 식별하고, 보안이 필요한 재정 거래를 처리한다. 이제 (로그아웃하지 않고) 다른 창을 띄워서 웹 서핑을 하던 도중에 뜻하지 않게 evil.com이라는 사이트에 접속했다 가정하면, 이 사이트엔 해커에게 송금을 요청하는 폼(form) `
`이 있고, 이 폼은 자동으로 제출되도록 설정되어 있다. 폼이 evil.com에서 은행 사이트로 바로 전송될 때 인증 쿠키도 함께 전송된다. bank.com에 요청을 보낼 때마다 bank.com에서 설정한 쿠키가 전송되기 때문이다. 은행은 전송받은 쿠키를 읽어 (해커가 아닌) 계정 주인이 접속한 것으로 생각하고 해커에게 돈을 송금한다. 이런 공격을 크로스 사이트 요청 위조라고 부른다. 실제 은행은 당연히 이 공격을 막을 수 있도록 시스템을 설계한다. bank.com에서 사용하는 모든 폼에 **XSRF 보호 토큰(protection token)**이라는 특수 필드를 넣는다. 이 토큰은 악의적인 페이지에서 만들 수 없고, 원격 페이지에서도 훔쳐 올 수 없도록 구현되어 있다. 따라서 악의적인 페이지에서 폼을 전송하더라도 보호 토큰이 없거나 서버에 저장된 값과 일치하지 않기 때문에 요청이 무용지물이 된다. 하지만 이런 절차는 구현에 시간이 걸린다. > 참고 : [CSRF 공격이란? 그리고 CSRF 방어 방법](https://itstory.tk/entry/CSRF-%EA%B3%B5%EA%B2%A9%EC%9D%B4%EB%9E%80-%EA%B7%B8%EB%A6%AC%EA%B3%A0-CSRF-%EB%B0%A9%EC%96%B4-%EB%B0%A9%EB%B2%95) ### samesite 옵션 쿠키의 samesite 옵션을 이용하면 XSRF 보호 토큰 없이도 크로스 사이트 요청 위조를 막을 수 있다. 이 옵션엔 두 가지 값을 설정할 수 있다. - `samesite=strict` 사용자가 사이트 외부에서 요청을 보낼 때, `samesite=strict` 옵션이 있는 쿠키는 절대로 전송되지 않는다. 메일에 있는 링크를 따라 접속하거나 evil.com과 같은 사이트에서 폼을 전송하는 경우 등과 같이 제3의 도메인에서 요청이 이뤄질 땐 쿠키가 전송되지 않는다. 인증 쿠키에 samesite 옵션이 있는 경우, XSRF 공격은 절대로 성공하지 못한다. evil.com에서 전송하는 요청엔 쿠키가 없을 것이고, bank.com은 미인식 사용자에게 지급을 허용하지 않을 것이기 때문이다. 만약 사용자가 메모장 등에 bank.com에 요청을 보낼 수 있는 링크를 기록해 놓았다가 이 링크를 클릭해 접속하면 bank.com이 사용자를 인식하지 못하는 상황이 발생하기 때문이다. 실제로 이런 경우 `samesite=strict` 옵션이 설정된 쿠키는 전송되지 않는다. 이런 문제는 쿠키 두 개를 함께 사용해 해결할 수 있다. "Hello, SeonHyungJo"과 같은 환영 메시지를 출력해주는 "일반 인증(general recognition)"용 쿠키, 데이터 교환 시 사용하는 `samesite=strict` 옵션이 있는 쿠키를 따로 두는 것이다. - `samesite=lax` (Chrome default 값) > [관련 이슈](https://brocess.tistory.com/263) `samesite=lax`는 사용자 경험을 해치지 않으면서 XSRF 공격을 막을 수 있는 느슨한 접근법이다. strict와 마찬가지로 lax도 사이트 외부에서 요청을 보낼 때 브라우저가 쿠키를 보내는 걸 막아준다. 하지만 예외사항이 있다. 아래 두 조건을 동시에 만족할 때는 `samesite=lax` 옵션을 설정한 쿠키가 전송된다. 1. 안전한 HTTP 메서드인 경우(예: GET 방식. POST 방식은 해당하지 않음). > 또는 `a href`, `link href` 안전한 HTTP 메서드 목록은 RFC7231 명세에서 확인할 수 있다. 안전한 메서드는 읽기 작업만 수행하고 쓰기나 데이터 교환 작업은 수행하지 않는다. 참고로, 링크를 따라가는 행위는 항상 GET 방식이기 때문에 안전한 메서드만 쓰인다. 2. 작업이 최상위 레벨 탐색에서 이루어질 때(브라우저 주소창에서 URL을 변경하는 경우). 대다수의 작업은 이 조건을 충족한다. 하지만 `