레이블이 deep인 게시물을 표시합니다. 모든 게시물 표시
레이블이 deep인 게시물을 표시합니다. 모든 게시물 표시

[컴] iOS 보안-시스템 보안

iOS 부팅 절차 / boot time / booting process / enclave


ref. 1 의 System Security 의 일부를 번역했다. 자세한 내용은 ref. 1을 보도록 하자.

iOS 보안-시스템 보안

기기암호화(device encryption) 는 기본적으로 설정되어 있으며, 설정을 변경할 수 없다.

Secure Boot Chain

  1. iOS 켜기
  2. --> AP 가 Boot ROM 의 code실행
    1. the hardware root of trust 라고 알려져 있다.
    2. the chain of trust 의 첫번째 단계(first step) 이다.
    3. 이 code 는 변경불가능(immutable code)
    4. 칩제조(chip fabrication) 때 만들어 진다.
    5. implicitly trusted
    6. Apple Root CA public key 를 가지고 있다.
      1. 이 public key 는 iBoot bootloader 가 load 되기 전에 Apple 에 의해 서명(sign) 됐다는 것을 확인(verify) 하는데 사용된다.(아래 boot-time verification 참고.)
  3. Boot ROM 에 의해 추가적인 Low-Level Bootloader(LLB) stage 가 load 되고, 확인(verify) 된다.
    1. A9를 포함한 A9 이전의 A시리즈 processor 에만 존재.
  4. 만약 Boot ROM 이 LLB 또는 iBoot 을 load 하는 것을 실패하면,  기기는 DFU mode (Device Firmware Upgrade)로 들어가게 된다.
    1. 오래된 기기들에서 LLB 를 load 하는 것을 실패 하거나,
    2. 새로운 기기들에서 iBoot 을 load 하는 것을 실패하는 것
  5. LLB 나 iBoot 이 다음 작업(next step) 을 load 하거나 verify 하는 것을 실패하는 경우
    1. startup 은 멈춰지고(halt) iTunes 에 접속하라는 화면이 보여진다. 
    2. --> recovery mode 이다.
  6. DFU mode 로 가거나, recovery mode 로 들어가면, USB 를 이용해서 iTunes 에 접속해서 "공장 기본 세팅(factory default settings)" 로 복구되어 져야만 한다.
  7. 기기가 Recovery Mode 와 DFU Mode 로 들어가기 전에 The Boot Progress Register (BPR) 가 update 된다. 이 update 된 값을 보고 Secure Enclave 가 user data 에 대한 접근제한을 하게 된다.
    1. Recovery Mode
      1. A10, S2 그리고 최신의 SoCs 를 가진 기기에서 iBoot 에 의해 BPR 이 set.
    2. DFU Mode : A12 SoC 를 가진 기기에서 Boot ROM 에 의해 BPR 이 set.
  8. --> iBoot 이 일들을 마치면
  9. --> iBoot 은 iOS kernel 을 확인(verify) 하고, 실행한다.

baseband subsystem 또한 이것과 비슷한 자신의 secure booting 을 이용한다.
Secure Enclave coprocessor 또한 secure boot process 를 이용하고, 그로인해 그것의 분리되 소프트웨어가 verified and signed by Apple 되었다는 것을 확신시켜준다.
secure boot



시스템 소프트웨어 권한부여(System Software Authorization)

만약 과거버전의 iOS의 설치가 가능하다면 해커는 과거버전의 iOS를 깔고 권한을 가져올 수 있다. 이것을 막기 위해서 iOS는 System Software Authorization 을 이용한다. Secure Enclave 도 이것을 이용한다.


iOS update

iOS update 는 2가지 방식(iTunes, OTA) 으로 가능하다.
  • iTunes 로 업데이트를 할 때
    • iOS image 전체를 download 
    • Content Caching 옵션을 켠 macOS High Sierra 를 돌리는(run) Mac 을 사용한다면, 미리 cache 되어서, iOS 의 update 를 바로 할 수 있게 해준다.
  • OTA 로 할 때: patch 를 할 내용만 다운로드한다. 

installation authorization server

iOS update 할때 기기는 Apple 의 installation authorization server 에 접근한다.
그리고 다음 3가지를 확인 한다.
  1. bundle의 measurements: 설치될 installation bundle들에 대한 암호화된 measurements(측정)
    • installation bundle : iBoot, kernel, iOS Image
  2. nonce : signed data 를 가져다 다른 기기에 쓰는 것을 막아주고, system software 를 변경하지 못하게 막는다.
  3. ECID: 기기의 고유한  ECID(Exclusive Chip Identification) 를 서버로 보내게 된다.

installation authorization server 에서 하는일

서버에서는  이 installation bundle 의 버전들이 맞는 구성인지를 확인한다. 예를 들면 특정버전의 iBoot 은 특정 version 의 kernel 을 써야만 하는식이다. 이렇게 버전이 맞으면 이 measurement 에 ECID 를 더해서 sign 을 하고 이 sign 된 data 를 기기에 보내준다.
sign(measurment + ECID) ---> device

boot-time verification

위에 설명한 startup process 가 "Apple 이 sign 한 code" 만 기기에 설치되는 것을 보장해 준다.
  • Apple 의 signature : boot time 에 일어나는 chain-of-trust evaluation 은 Apple 의 signature 를 verify 한다.
  • disk 에서 load 되는 item 의 measurement: "disk 에서 load 되는 item 의 measurement (기기의 ECID를 이용해서 만들어져 있다.)"와 "signature 에 의해 감싸진 measurement(위의 installation authorization server 에서 받은)"가 맞는지를 verify 한다.
이 절차들이 특정기기에 대한 authorization 을 해주고, 기기에서 옛 iOS버전이 다른 곳으로 copy 안되도록 한다.

Secure Enclave

  • Secure Enclave 는 보조 프로세서이다. 
  • SoC 안에 들어있다.(fabricated)
  • 암호화된 메모리를 사용
  • 하드웨어 난수발생기(random number generator) 를 포함.
  • Secure Enclave Boot ROM
    • application processor Boot ROM 과 비슷하게, Secure Enclave Boot ROM 은 변경이 불가능한 code (immutable code) 이다. Secure Enclave 를 위한 "하드웨어 root of trust" 를 확립한다.(establish)
    • device 가 시작될 때, Secure Enclave Boot ROM 이 수명이 짧은 메모리 보호 키(ephemeral memory protection key)를 만든다. 
  • Secure Enclave 는 데이터 보호 키 관리에게 (Data Protection key management) 모든 암호화 기능(cryptographic operations)들을 제공
  • 심지어 커널이 허락한 상태에도(kernel has been compromised) Data Protection 의 integrity (데이터가 변경, 파괴되지 않은 상태)을 유지.
  • AP(Application processor) 와 Secure Enclave 사이의 통신은 interrupt-driven mailbox 와 shared memory data buffer 들과 분리되어 있다.
  • Secure Enclave OS 를 실행
    • Secure Enclave OS
      • "L4 마이크로 커널의 Apple-customized version" 에 기초해서 만들어진 OS
      • Apple 에 의해 sign 된다.
      • Secure Enclave Boot ROM 가 verify
      • 개인의 소프트웨어 업데이트 프로세스를 통해 update 된다.
  • device 가 시작될 때, Secure Enclave Boot ROM 이 수명이 짧은 메모리 보호 키(ephemeral memory protection key)를 만든다. 
    • 이 키(memory protection key)는 기기의 UID 와 얽히게 만들고(entangle), 기기의 memory space 의 "Secure Enclave 부분"을 암호화 할 때 사용된다.
    • 예외적으로 Apple 의 A7 에선, Secure Enclave memory "memory protection key" 로도 인증(authenticated) 이 가능하다. A11과 A11 이후 그리고 S4 SoC 들에서는 "memory protection key" 와 on-chip SRAM 에 저장된 nonce 들에 의해 인증된다.(authenticated)
    • 그리고, A11과 A11 이후 그리고 S4 SoC 들에서 integrity tree 는 보안이 중요한 Secure Enclave memory 의 replay 를 막기위해 사용되어진다.
    Secure Enclave 에 의해 file system 에 저장된 data 는 UID 와 entangled 된 key와 anti-replay counter 로 암호화되어 진다. anti-replay counter 는 dedicated 비휘발성 메모리 IC 안에 저장되어 있다.

    A12 와 S4 SoC 들이 있는 기기들에서, Secure Enclave 는 anti-replay counter storage 를 위해 secure storage IC 와 짝을 이룬다. secure storage IC 는 immutable ROM code, 하드웨어 random number generator, 암호화엔진들, physical tamper detection(물리적인 조작 감지) 과 함께 디자인됐다. counter 들을 읽고 업데이트 하기 위해서, Secure Enclave 와 storage IC 는 counter 들에게 exclusive access 를 보장하는 '안전한 protocol '를 사용한다.

    Secure Enclave 의 "anti-replay 서비스"들은 event 에 사용된 data 의 철회(revocation of data over events)를 위해 사용되어진다.

    이 이벤트들은 anti-replay 의 경계들(boundaries)을 표시 해 준다.
    이벤트는 다음것들을 포함한다. 하지만 제한되진 않는다.
    • Passcode change
    • Touch ID or Face ID enable/disable
    • Fingerprint add/delete
    • Face ID reset
    • Apple Pay card add/remove
    • Erase All Content and Settings
    Secure Enclave 는 또한 지문을 처리하고, Touch ID 와 Face ID 센서들로 부터 오는 얼굴데이터를 처리하는 책임도 진다. 그리고 맞는지 여부를 결정하고, 그리고나서, 유저를 대신해서 access 또는 구매를 가능하게 한다.

    See Also

      1. Apple T2 보안 칩-Mac 보안

        Reference

        1. https://www.apple.com/business/site/docs/iOS_Security_Guide.pdf

        [컴][웹] AdoniJS at Start up

        아도니스 제이에스 / js


        Adonisjs at startup

        app.js

        _loadPreLoadFiles 이전에 this._registerProviders()와 await this._bootProviders()를 호출한다. 이 때 app.js 에 접근해서 Providers 를 가져오고, 이 Provider 의 register() 와 boot() 을 호출한다.

        preloaded files

        아도니스js 에서 처음에 load 하는 file 들은 다음과 같다.(_loadPreLoadFiles)
        • 'start/routes',
        • 'start/events',
        • 'start/socket',
        • 'start/kernel',
        • 'start/wsKernel'
        이 부분은 Ignitor source 에서 확인할 수 있다.
        new Ignitor(require('@adonisjs/fold'))
          .appRoot(__dirname)
          .fireHttpServer()
          .catch(console.error)
        
        
        
        class Ignitor {
          constructor (fold) {
            this._fold = fold
            this._appRoot = null
            this._modulesRoot = null
            this._loadCommands = false
        
            /**
             * Files to be preloaded
             *
             * @type {Array}
             */
            this._preLoadFiles = [
              'start/routes',
              'start/events',
              'start/socket',
              'start/kernel',
              'start/wsKernel'
            ]
        
            /**
             * Default app file
             *
             * @type {String}
             */
            this._appFile = 'start/app.js'
            ...
          }
          ...
          async fire () {
           ...
           this._registerProviders()
           await this._bootProviders()
           ...
           this._loadPreLoadFiles()
          }
        
          async fireHttpServer (httpServerCallback) {
            try {
              await this.fire()
              await this._startHttpServer(httpServerCallback)
            } catch (error) {
              this._printError(error)
            }
          }
        
          /**
           * Return the exported values from the appFile. Also
           * it will validate the exports object to have all
           * required keys.
           *
           * @method _getAppAttributes
           *
           * @return {Object}
           *
           * @private
           */
          _getAppAttributes () {
            return require(path.join(this._appRoot, this._appFile))
          }
        
          /**
           * Registers an array of providers to the Ioc container. This
           * method will make use of the `appFile` to get the providers
           * list.
           *
           * @method _registerProviders
           *
           * @return {void}
           *
           * @private
           */
          _registerProviders () {
            this._callHooks('before', 'providersRegistered')
        
            /**
             * Getting list of providers and registering them.
             */
            const { providers, aceProviders } = this._getAppAttributes()
            const providersToRegister = this._loadCommands ? providers.concat(aceProviders) : providers
            this._fold.registrar.providers(providersToRegister).register()
        
            debug('registered providers')
            this._callHooks('after', 'providersRegistered')
          }
        
          /**
           * Boot providers
           *
           * @method _bootProviders
           *
           * @return {void}
           *
           * @async
           *
           * @private
           */
          async _bootProviders () {
            this._callHooks('before', 'providersBooted')
        
            /**
             * The providers set set on `registrar` when they were registered. We
             * use the same set to boot the previously registered providers.
             */
            await this._fold.registrar.boot()
        
            debug('booted providers')
            this._callHooks('after', 'providersBooted')
          }
        
          ...
          _loadPreLoadFiles () {
            this._callHooks('before', 'preloading')
            ...
        
            this._preLoadFiles.forEach((file) => {
              const filePath = path.isAbsolute(file) ? file : path.join(this._appRoot, file)
        
              /**
               * Require file when it's not optional or when optional
               * file exists
               */
              if (!this._isOptional(file) || this._fileExists(filePath)) {
                require(filePath)
              }
            })
        
            this._callHooks('after', 'preloading')
          }
        }
        



        [컴][웹] 간단하게 주기적으로 message 를 수신하는 web page

        EventSource / cors / jsonp / different host / subscribe model /


        tornado

        EventSource object | Javascript


        EventSource object 로 server 에 연결(subscribe) 을 해서 주기적으로 event 를 받을 수 있다. 자세한 동작은 일단 생략한다. ref. 2 에서 어느정도 설명을 해준다.


        different domain

        domain 이 다른 곳에 event 를 날려주는 server 가 있어도 무리없이 사용할 수 있다. 보통 html(javascript) 에서 다른 domain 인 경우는 보안을 이유로 ajax 요청이 되지 않는다. 그래서 jsonp 등(일반적으로 Cross-Origin Resource Sharing 이라고 이야기하는 방법)을 이용한다.

        하지만 이 EventSource 는 그런 것의 제약을 받지 않는다. [ref. 1]

        아래처럼 다른 domain 인 경우에는 다른 domain 을 uri 로 적어주면 된다.

        var evtSource = new EventSource("//api.example.com/ssedemo.php", { withCredentials: true } );

        evtSource.addEventListener("ping", function(e) {
          var newElement = document.createElement("li");
         
          var obj = JSON.parse(e.data);
          newElement.innerHTML = "ping at " + obj.time;
          eventList.appendChild(newElement);
        }, false);


        이렇게 다른 domain 에 대한 제약이 없어서 좋은 점은 기존의 web server 와 관계없이 새로운 event 처리를 하는 server 를 사용할 수 있다는 점이다. 그러면 주기적인 push event 등을 처리하는 server 를 따로 둘 수 있다.



        Server side event vs WebSocket

        event driven page 를 만들 땐 SSE 를 사용해도 되고, WebSocket 을 사용해도 된다. 개인적으로는 필요한 부분은 단방향이라서, 양방향 통신이 되는 WebSocket 이 굳이 필요하지 않았다.

        아래는 SSE 와 WebSocket 을 간략하게 정리했다.

        SSE

        1. 2009년 4월 23 일 WHATWG 에서 승인했다. [ref. 7] 
        2. 하지만 SSE 가 좀 더 간편하다. 
        3. 그리고 http protocol 위에서 구현되었다. 
        4. 단방향 통신
        5. client 의 connection 이 종료되었는지 여부를 알 수는 없다.(http 라서 당연한 것일지도.)


        WebSocket

        1. 반면에 WebSocket 은 Tcp/ip 로 다른 port 를 사용한다. 그래서 이 port 가 firewall 에 의해 막혀 있을 수도 있고, 
        2. 이 녀석을 이용하려면, protocol 을 또 정의해야 한다. (ref. 5 에서 좀 더 다양한 의견을 확인할 수 있다.)
        3. 양방향 통신
        from: https://usp.technology/specification/mtp/websocket/websocket-session-handshake.png


        See Also

        1. WebSockets vs Server-Sent-Events vs Long-Polling vs WebRTC vs WebTransport | RxDB - JavaScript Database

        Reference

        1. Using server-sent events - Web APIs | MDN
        2. Stream Updates with Server-Sent Events - HTML5 Rocks
        3. Asynchronous connections - RethinkDB
        4. Build a real time data push engine using Python and Rethinkdb | IMPYTHONIST
        5. SSE vs Websockets - Streamdata.io
        6. Lessons Learned Architecting Realtime Applications | Lincoln Loop
        7. Python and Real-time Web | Eat at Joe's
        8. Tornado server-sent events · GitHub : tornado 로 SSE 구현 예제.
        9. Building RESTful APIs with Tornado | Dr Dobb's

        [컴][웹] V8 에서 JavaScript 의 pipeline

        v8 engine 의 동작 / 동작원리 / 크롬 자바스크립트 엔진 / 크롬 엔진 / 크롬 렌더링 엔진 /



        V8 에서 JavaScript 의 pipeline

        v5.9 이전의 pipeline

        from: https://v8.dev/blog/ignition-interpreter

        원래는 baseline compiler(위의 그림에서 Ignition 과 Full codegen 의 위치에 있는 것이라 여기면 될 듯 하다.) 가 machine code 를 빠르게 만들고, 이 code 가 실행되는 동안에 이 code를 분석하고 일부를 optimizing compiler 가 optimized code 로 다시 compile 한다.

        이 때 사용되는 2개의 optimizing compiler 가 crankshaft, turbofan 이다.

        • TurboFan : Ignition의 bytecode를 바로 최적화된 machine code 로 바꿀 수 있다.[ref. 4]
        • Crankshaft: 소스코드를 다시 컴파일을 해서 최적화된 machine code 를 만든다.[ref. 4]
        참고로, v5.9 부터 Full-codegen 과 Crankshaft 는 사용하지 않는다.[ref. 4]

        Ignition 의 등장

        그런데 이 상황에서 Ignition 을 만들어서 "baseline compiler 가 machine code 를 만드는 것"을 대신해서 Bytecode 를 만들게 했다.

        Ignition 는 처음에 모바일에서 사용하기 위해서 만들었다.[ref. 4]  JIT 가 만든 machine code 의 size 가 커서 메모리를 너무 잡아먹었기 때문이다.  Ignition 에 의해서 chrome tab 마다 메모리를 약 5% 정도 아꼈다.

        Ignition 은 bytecode 를 생성하는 compiler 이고, 이녀석은 이전의 baseline compiler 를 대체한다.  Ignition 이 bytecode 를 만들때도 당연히 최적화를 한다.

        이 Ignition 은 register machine 이다. 이것은 stack machine 과 다르다. 이건 내 생각이지만, 안드로이드의 경험이 덕을 본듯 하다. (stack-based vs register-based)

        Ignition 이 생기면서 고성능의 interpreter 가 생겼고 이 녀석이 Ignition 이 만든 bytecode 를 실행해주는데, 실제웹사이트에서 속도가 이전의 baseline compiler 가  만든 code 의 속도에 근접한다.

        See Also

        1. V8 관련 글들

        References

        1. Ignition · V8 : ignition 에 대한 여러자세한 설명들의 link 들이 있다.
        2. Firing up the Ignition interpreter · V8
        3. Home · v8/v8 Wiki · GitHub
        4. Launching Ignition and TurboFan · V8
        5. TurboFan · V8 : turbofan 에 대한 정보들이 모여 있다.


        [웹][컴] Digging into the TurboFan JIT 번역




        TurboFan JIT

        TurboFan JIT 은 이름에서 알 수 있듯이 Just In Time interpreter(runtime, vm 뭐라고 부르든 상관없을듯) 라고 보면 될 듯 하다.

        ref. 1 은 TurboFan 의 design 에 대한 이야기이다. 여기서는 ref. 1 의 이야기를 정리하는 수준으로 작성할 것이다. 자세한 이야기는 ref. 1을 확인하자.

        이전에 쓰던 JIT 이 CrankShft JIT 이다.
        • CrankShaft JIT --> TurboFan JIT

        TurboFan 의 장점-layered architecture

        • 아래 3개를 좀 더 명확하게 분리 시켰다. --> 좀 더 명확하고, 견고한 code 를 가능하게 한다.
          • source-level language (JavaScript)
          • the VM's capabilities (V8)
          • the architecture's intricacies (from x86 to ARM to MIPS)
        • 최적화기능들(optimizations)과 기능(feature)들을 구현시 효과적으로 할 수 있다.
          • code 가 architecture-dependent backend 들과 분리돼서, 새롭게 추가되는 Javascript 의 기능들을 추가하기 수월해 졌다.
        • 좀 더 효과적인 unit test 를 작성할 수 있다.
        • code 도 줄여준다.(CrankShaft 에서 13,000~16,000 라인이던 부분이 3,000 라인 미만)
        • 여러 architecture 의 engineer 가 좀 더 효율적으로 작업할 수 있게 해준다.

        좀 더 수준높은 최적화 방법들

        TurboFan JIT 은 이전의 CrankShaft 보다 좀 더 발전된 기술을 이용해서 좀 더 공격적인 optimization 들을 한다.
        • Sea of Nodes IR: 디자인의 핵심은 코드의 "좀 더 유연해진 Sea of Nodes IR(internal representation)" 이다. 이것이 좀 더 효과적인 "reordering" 과 "최적화(optimization)" 을 가능하게 해준다.
        • TurboFan 은 범위 분석(Numerical range analysis) 을 통해 number-crunching code 를 이해하는 것을 돕는다.
        • The graph-based IR : graph 의 기반한 IR 은 대부분의 최적화기능들이 "simple local reductions" 들로 표현되는 것을 가능하게 해준다. simple local reductions 은 독립적으로 작성하고 테스트하기 좀 더 쉽다. 최적화 엔진은 이 local rules 들을 체계적이고, 빈틈없이 적용한다.
        • graphical representation  을 벗어나는 것은  코드를 loop 에서 덜 자주 사용되는 path들로 옮기기 위해 "혁신적은 scheduling 알고리즘"을 사용한다.
        • 이 알고리즘은 reordering freedom 을 이용한다.
        • architecture-specific optimizations: 최종적으로, 복잡한 "instruction selection" 같은 architecture-specific 최적화 기능들은 좋은 품질의 code 를 위해 각 target platform 의 기능들(features)을 이용한다.

        See Also

        [컴][웹] V8 컴파일 하기

        v8 engine compilation / v8 chrome engine / 브라우저 엔진 컴파일 / javascript engine / js engine v8


        v8 compilation

        컴퓨터환경

        • CPU : i3-2100 CPU@3.10GHz
        • RAM : 8GB
        • DISK : SATA3(6Gb/s), 7200RPM, 16MB

        windows 에서 빌드

        절차

        1. python 설치
        2. python 경로를 PATH 환경변수에 추가
        3. Visual Studio 설치(약 40분)
        4. Windows 10 SDK 설치
        5. depot_tools 설치
        6. path 설정
        7. gclient
        8. fetch v8(약 10분)
          1. 만약 update 한다면, gclient sync
        9. gn gen --ide=vs out/MyV8

        python 2.7.15

        python 을 설치하고 환경변수 PATH 에 path 를 추가하자.

        pip install pypiwin32

        win32 module 을 third-party toolchain 에서 사용한다. 그래서 필요하다.

        Visual Studio 설치

        windows 에서 v8 를 build 하려면 compiler 가 설치되어 있어야 한다. 여기서는 Visual Studio 2017 Community version 을 사용할 것이다.
        • 버전: Visual Studio 2017 (>=15.7.2) 또는 2019 (>=16.0.0) 가 필요[ref. 1]
        "C++를 사용한 데스크톱 개발" 을 선택하고, 설치 세부정보 에서 "x86 및 x64용 Visual C++ MFC" 를 추가한다. 아래 command line 으로 바로 설치할 수 있다.
        vs_community.exe --add Microsoft.VisualStudio.Workload.NativeDesktop --add Microsoft.VisualStudio.Component.VC.ATLMFC --includeRecommended
        

        Windows 10 SDK 설치 - Debugging Tools

        version 10.0.17134 이상의 Windows 10 SDK 가 설치되어 있어야 한다.
        아래에서 setup 을 download 하고, "Debugging Tools for Windows" 를 선택하자.
        그러면 아래 경로에서 .msi 를 찾을 수 있다. 이녀석을 실행해서 Debugging Tools 를 설치하자.
        • 64bit용 : <Windows Kits>\10\WindowsSDK\Installers\X86 Debuggers And Tools-x64_en-us.msi

        depot_tools

        depot_tools 를 설치하자. 참고로 python 은 이미 설치되어 있었다.
        1. depot_tools.zip 를 다운받아서 압축을 풀자. 여기서는 c:\v8\depot_tools\ 에 풀었다.
        2. 이 경로를 PATH 환경변수에 추가하자.
        3. DEPOT_TOOLS_WIN_TOOLCHAIN 변수를 설정하고, 0으로 set 하자. 0 으로 set 하면 이미설치된 Visual Studio 를 사용한다는 뜻이다.
        4. gclient 를 실행하자. metrics.cfg 를 만들어준다.
          c:\v8\depot_tools\>gclient

        windows defender 에 '제외'(exclusion) 추가

        빌드 속도의 향상을 위해 v8 src directory 를 '제외' 항목에 추가하자. (참고)

        fetch v8

        이 명령어로 checkout 을 하게 된다. 처음에 git source 를 받을 때 사용한다.
        > cd c:\v8\v8_chromium
        > fetch v8

        참고로, fetch chromium 은 desktop chromium 의 소스를 가져온다.  잘 못 알아서, fetch chromium 을 했는데, master 소스를 가져오는데에만 2시간 55분 정도 소요됐다. 그 후에 다른 관련 소스를 또 받아오는데 25분정도가 더 소요됐다.

        HDD는 최소 25GB 는 사용된 듯 하다. ref. 1 을 보면 build 에 최소 100GB 가 필요하다고 한다.

        v8 은 그래서 아래 경로에 fetch 가 됐다. v8 source code 의 크기만 1.8GB 정도가 된다.
        • c:\v8_chromium\src\v8
        그 다음 nacl(Google Native Client) tools 를 download 한다.

        마지막으로 아래처럼 username 을 물어본다. 그냥 enter 를 치면, build 를 시도하다 실패한다.

        Username for 'https://chrome-internal.googlesource.com':
        
        ________ running 'C:\Python27\python.exe v8/build/vs_toolchain.py update' in 'c:\v8\v8_engine'
        
        
        
        No downloadable toolchain found. In order to use your locally installed version of Visual Studio to build Chrome please set DEPOT_TOOLS_WIN_TOOLCHAIN=0.
        For details search for DEPOT_TOOLS_WIN_TOOLCHAIN in the instructions at https://chromium.googlesource.com/chromium/src/+/master/docs/windows_build_instructions.md
        
        
        Traceback (most recent call last):
          File "v8/build/vs_toolchain.py", line 502, in <module>
            sys.exit(main())
          File "v8/build/vs_toolchain.py", line 498, in main
            return commands[sys.argv[1]](*sys.argv[2:])
          File "v8/build/vs_toolchain.py", line 444, in Update
            subprocess.check_call(get_toolchain_args)
          File "C:\Python27\lib\subprocess.py", line 190, in check_call
            raise CalledProcessError(retcode, cmd)
        subprocess.CalledProcessError: Command '['C:\\Python27\\python.exe', 'c:\\v8\\v8_engine\\v8\\third_party\\depot_tools\\win_toolchain\\get_toolchain_if_necessary.py', '--output-json', 'c:\\v8\\v8_engine\\v8\\build\\win_toolchain.json', '3bc0ec615cf20ee342f3bc29bc991b5ad66d8d2c']' returned non-zero exit status 1
        Error: Command 'C:\\Python27\\python.exe v8/build/vs_toolchain.py update' returned non-zero exit status 1 in c:\v8\v8_engine
        Hook ''C:\Python27\python.exe' v8/build/vs_toolchain.py update' took 601.97 secs
        Traceback (most recent call last):
          File "c:\v8\depot_tools\\fetch.py", line 306, in <module>
            sys.exit(main())
          File "c:\v8\depot_tools\\fetch.py", line 301, in main
            return run(options, spec, root)
          File "c:\v8\depot_tools\\fetch.py", line 295, in run
            return checkout.init()
          File "c:\v8\depot_tools\\fetch.py", line 137, in init
            self.run_gclient(*sync_cmd)
          File "c:\v8\depot_tools\\fetch.py", line 82, in run_gclient
            return self.run(cmd_prefix + cmd, **kwargs)
          File "c:\v8\depot_tools\\fetch.py", line 71, in run
            subprocess.check_call(cmd, **kwargs)
          File "C:\Python27\lib\subprocess.py", line 190, in check_call
            raise CalledProcessError(retcode, cmd)
        subprocess.CalledProcessError: Command '('C:\\Python27\\python.exe', 'c:\\v8\\depot_tools\\gclient.py', 'sync', '--with_branch_heads')' returned non-zero exit status 2
        
        c:\v8\v8_engine>

        gclient sync

        추후에 source 를 최신으로 update 할 때 사용하면 된다.
        c:\v8\v8_engine\v8>gclient sync
        Syncing projects: 100% (24/24), done.
        Running hooks:  75% (21/28) clang
        ________ running 'C:\Python27\python.exe v8/tools/clang/scripts/update.py' in 'c:\v8\v8_engine'
        Downloading https://commondatastorage.googleapis.com/chromium-browser-clang/Win/clang-349417-2.tgz .......... Done.
        Copying C:\Program Files (x86)/Microsoft Visual Studio/2017/Community\DIA SDK\bin\amd64\msdia140.dll to c:\v8\v8_engine\v8\third_party\llvm-build\Release+Asserts\bin
        Hook ''C:\Python27\python.exe' v8/tools/clang/scripts/update.py' took 19.46 secs
        Running hooks: 100% (28/28), done.
        
        c:\v8\v8_engine\v8>

        gn gen --ide=vs out/MyV8

        chromium 은 ninja 를 사용한다. depot_tools 를 설치하면 같이 설치된다. gn 을 실행하면 .ninja 를 만들어준다. (자세한 내용은 여기 를 참고하자.)

        여기서는 Visual Studio 에서 build 를 할 것이라서 --ide=vs 를 추가해 줬다.
        c:\v8\v8_engine\v8>gn gen --ide=vs out\MyV8
        Generating Visual Studio projects took 277ms
        Done. Made 132 targets from 76 files in 9360ms
        
        c:\v8\v8_engine\v8>

        이제 아래 경로에 .sln file 이 생성됐다.
        • c:\v8\v8_engine\v8\out\MyV8\all.sln
        몇몇 관련 project 를 filetering 하려면 아래 처럼 하면 된다. 하지만 이 option 은 chromium 같이 큰 프로젝트를 열때나 필요할 듯 하다. v8 project 만 열때는 필요치 않았다.
        gn gen --ide=vs --filters=//third_party/v8/* --no-deps out\Default

        open .sln(약 60분)

        이제 위에서 생성된 all.sln 파일을 더블클릭해서 Visual Studio 를 열자. 그리고 build 를 하면 된다. build 를 하면 내부적으로 ninja 를 호출해서 build 를 하게 된다.

        여기서는 v8_hello_world 를 build 했다. 대략 60분 정도가 소요됐다.

        error case : visual studio 2015 --> visual studio 2017

        v8 build 를 위해서 visual studio 의 version 을 upgrade 한 경우는 stdio.h 등의 header files 가 include 가 안되는 경우가 있다. 이때는 Windows SDK 버전을 재설정 해주자.

        v8_hello_world.exe 실행

        이제 아래 path 에 v8_hello_world.exe 가 생성됐다. 이 녀석을 실행하면 아래처럼 결과가 나온다.
        c:\a\programming\v8\v8_engine\v8\out\MyV8>v8_hello_world.exe
        Hello, World!
        3 + 4 = 7

        debug mode

        당영한 이야기지만, 만약 이 v8_hello_world 를 디버그 모드로 실행하고 싶다면, solution explorer 에서 v8_hello_world project 에서 context menu(마우스 오른쪽 버튼) 을 눌러서 debug 를 해야 한다.

        See Also

        1.  V8 에서 JavaScript 의 pipeline
        2. V8 관련 글들

        References

        1. Checking out and Building Chromium for Windows
        2. v8/v8.git - Git at Google

        [컴][OS] ELF file format

        리눅스 파일포맷 / 실행 파일 포맷 / 규격 / 파일 규격

        ELF format

        ELF file format 에 관한 얘기를 해보자.

        elf header 관련 정보들

        일단 여기서 이야기하는 것은 아주 첫 부분이다. 자세한 정보들은 아래 링크를 참고하자.

        ELF type

        ELF file 은 여러가지 모양(type)이 가능한데,
        그 중에 주요한 3가지 type 이 있다.
        1. relocatable file
        2. executable file
        3. shared object file

        일단 다른것은 생각하지 말고, 흔히 windows 에서 얘기하는 .exe 같은 executable file 에 대해서 살펴보자.

        ELF executable

        ELF file 안에는 아래같은 요소가 들어간다.
        1. ELF header : 언제나 ELF file 의 가장 처음에 위치
        2. Program header table
        3. Segment
        4. Section
        5. Section header table.

        ELF header 는 항상 처음에 위치하지만, 하지만 다른 것들의 위치는 고정되어 있지 않다.

        <그림필요>

        ELF header

        먼저 이 ELF header 에 대해 얘기 해보자.

        역시 위치가 고정되어 있기 때문에 elf file 를 까봐도 찾기가 가장 편할 것이다. 일단 코드상으로는 아래와 같다.

        code

        e_ident[] Identification indexes
        Name Value Purpose
        EI_MAG0 0 File identification
        EI_MAG1 1 File identification
        EI_MAG2 2 File identification
        EI_MAG3 3 File identification
        EI_CLASS 4 File class
        EI_DATA 5 Data encoding
        EI_VERSION 6 File Version
        EI_PAD 7 Start of padding bytes
        EI_NIDENT 16 e_ident[]

        struct
        #define EI_NIDENT    16
        typedef struct{
            unsigned char    e_ident[EI_NIDENT];      /*Magic number and other info */
            ElfN_Half       e_type;                         /*Object file type */
            ElfN_Half       e_machine;                   /* Architecture */
            ElfN_Word       e_version;                     /* Object file version */
            ElfN_Addr       e_entry;                       /* Entry point virtual address */
            ElfN_Off        e_phoff;                       /* Program header table file offset */
            ElfN_Off        e_shoff;                        /* Section headr table file offset */
            ElfN_Word       e_flags;                        /* Processor-specific flags */
            ElfN_Half       e_ehsize;                      /* ELF header size in bytes */
            ElfN_Half       e_phentsize;                 /* Program header table entry size */
            ElfN_Half       e_phnum;                    /* Program header entry count */
            ElfN_Half       e_shentsize;                  /* Section header table entry size */
            ElfN_Half       e_shnum;                      /* Sectino header table entry count */
            ElfN_Half       shstrndx;                      /* Sectino header string table index */
        } Elf32_Ehdr


        binaries

        실제로는 어떻게 이 값이 hex 로 저장되어 있는지 살펴보자.

        <그림>

        확대


        당연한 이야기지만 이 구조체 structure 를 보면 header에 어떤 것들이 들어있는지 알 수 있다.


        아래와 같은 elf file 이 있다고 하자.
        0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x28, 0x00, ...
        
        e_ident
        처음 16개의 byte 들(e_ident[EI_NIENT])을 살펴보자.

        • EI_MAG*
          • 0x7f, 0x45, 0x4c, 0x46
          • 처음 4개는 이 파일이 ELF object file 인 것을 알려주는 magic number 이다.
        • EI_CLASS
          • 그 다음 byte, 즉 5번째 byte 는 file 의 class 를 나타낸다.
          • ELF file 이 다양한 사이즈의 머신에서 가져다 쓸 수 있게 하기 위해서 이 ELF file 이 어떤 machine 에서 작동하는 놈이다라는 것을 알려줄 필요가 있다.
            • '1'은 32-bit objects 라는 것(ELFCLASS32)을 알려주며,
            • '2'는 64-bit objects 라는 것(ELFCLASS64)을 알려준다.
        • EI_DATA
          • 6번째 BYTE는 encoding type 을 알려준다.
            • '1'(ELFDATA2LSB) : little-endian
            • '2'(ELFDATA2MSB) : big-endian
        • EI_VERSION
          • 7번째 byte 는 ELF header version 을 알려준다.
          • 보통 '1'(EV_CURRENT) 를 사용한다.
        • EI_PAD
          • 8번째 byte 부터  끝까지 '0'으로 채워져 있는데, 그냥 의미없이 채워넣은 것이다, 즉 padding 이다. 흔히 하는 말로 reserved, 예약되어 있는 것이다.
          • (EI_PAD 이 값이 현재 '7'인데, 만약 header에 들어갈 값이 더 생긴다면 당연히 EI_PAD 값을 큰 수로 변경해야 한다.)
        e_type
        17번째 byte 와 18번째 byte 는 지금 ELF file 의 format 을 알려준다.
        자세한 사항은 놔두고, 일단 여기서는 executable file 이기 때문에 '2' 가 된다.


        [컴][웹] Launching Ignition and TurboFan 번역


        Launching Ignition and TurboFan

        Launching Ignition and TurboFan 의 내용을 대략적으로 번역했다.

        JavaScript execution pipeline

        새로운 자바스크립트 수행 파이프라인
        • - Ignition : V8’s interpreter
        • - TurboFan : compiler
        v5.9 부터 2010년부터 사용해온 Full-codegen 와 Crankshaft 를 더이상 사용하지 않가로 함.

        TurboFan

        TurboFan 은 처음 디자인할 때부터 ES2015 이후의 기능(feature) 에 대한 최적화도 고려했다.

        터보팬은 layered compiler design 을 도입했다.
        high-level 과 low-level compiler optimizations 을 분리해서 새로운 언어기능(language features) 을 추가하기 쉽게

        명확한 명령어 선택 컴파일 phase(explicit instruction selection compilation phase)를 추가해서
        구조와 덜 연관된 코드를 만들 수 있게 해준다.

        Ignition

        Ignition interpreter 의 최초의도는 모바일기기에서의 메모리 사용을 줄이기 위함이었다.

        이전에 Full-codegen baseline compiler가 생성한 코드는 크롬에서  평균 javascript heap 의 1/3을 차지했다.

        그래서 어플리케이션의 실제 데이터가 사용할 수 있는 공간이 적었다.

        후에 V8팀은 TurboFan 을 이용해서 Ignition의 bytecode를 바로 최적화된 machine code 로 바꿀 수 있는 사실을 이용했다.

        소스코드를 다시 컴파일을 해야만 했던 Crankshaft

        Ignition의 bytecode는 v8에서 좀 더 깔끔하고 덜 error-prone 한 기준선(baseline)을 제공한다.
         Full-codegen의 baseline compiled code를 생성하는 것보단 bytecode 를 생성하는 것이 더 빠르다.

        그래서 ignition을 사용하게 되면 script startup 시간과 웹페이지 로드 속도가 빨라진다.

        See Also

        1. Digging into the TurboFan JIT 번역
        2. Firing up the Ignition interpreter
        3. V8 에서 JavaScript 의 pipeline
        4. V8 관련 글들

        References

        1. Launching Ignition and TurboFan

        [컴][웹] 정부의 https 접속문제 원인

        왜 정부사이트는 https 가 안되나 / 보안접속이 안되는 이유 / 정부사이트의 문제 / 정부사이트가 욕을 먹는 이유/ 정부 사이트에서 https 가 안되는 이유


        정부의 https 접속문제 원인


        현재 정부 사이트들을 https 로 접속하면 문제가 있다. 이것은 보통 브라우저가 신뢰할 만한 기관이라고 인정하는 녀석들의 리스트를 가지고 있는데, 그 리스트에 한국정부가 들어가지 못해서이다.


        처음에 나는 이것이 단순히 인지를 못해서 추가를 못한 수준인줄 알았다. 하지만 기사가 더 자세한 내용을 알려줬다. 기사를 차라리 몰랐으면 할 정도로 정부의 IT 인식 수준(특히 보안)이 참담했다. 여기서는 그 기사의 내용을 좀 더 정리해 보도록 하겠다.



        문제점

        인증받지 못한 행정안전부가 발급하는 'G-SSL 인증서'

        인증서는 누구나 발행할 수 있다. 하지만, 누가발행했느냐를 보고, 브라우저는 이 인증서가 믿을만한 인증서인지 아닌지 여부를 판단한다. 브라우저는 믿을만한 발행 업체에 대한 리스트를 가지고 있다.

        즉, 많은 브라우저 업체(구글, 모질라, 애플)들이 한국 정부의 CA (Certificate authority)자격을  인정하지 않는다는 뜻이다.

        하지만 그래도 되는 브라우저들이 있다. 이것은 브라우저가 자신의 CA 리스트를 사용하는 대신 OS가 가지고 있는 CA list 를 사용하기 때문이다.


        모질라의 CA 인증서 프로그램에서 탈락

        2015년 11월


        • 2015년말부터 행정안전부(당시 '행정자치부') 가 CA 자격을 얻기 위해 노력.
        • --> 그 일환으로 모질라의 CA인증서프로그램(CA Certificate Root Program, 이하 '프로그램')을 신청(관련자료)
        • --> 이 검증이 대체로 아무문제가 없다면 2년이 소요된다고 한다.

        모질라의 검증


        • 검증 작업: 2016년 초부터 2018년 초까지 약 2년간 진행
        • 행정안전부 산하기관인 "한국지역정보개발원(KLID)"의 담당자가 실무를 맡음
        • KLID가 실질적인 G-SSL 인증서 발급 및 관리체계 운영 조직

        모질라의 최종판단


        • 한국 정부의 G-SSL 인증서 발급 및 관리 체계가 프로그램 검증을 위해 내걸고 있는 '루트저장소정책(Root Store Policy)' 등 준칙의 기준에 맞지 않는다고 판단


        왜 탈락했는가?

        ref. 1 에 따르면, 모질라의 최종판단은 아래 3개의 사건에 근거한다고 한다. 아래는 대략적인 정리이다. 조금 더 자세한 사건 내용은 ref. 1 을 참고하자.

        • 사건1: 2016년 2월 모든 GPKI 인증기관 인증서 검증 신청 기각
          • 처음에는 행정자치부를 Root CA 로 해서 행정자치부만 검증을 받으려 함.
          • 행정자치부는 GPKI 기반의 인증서 / 교육부는 EPKI라는 인증체계 기반의 인증서를 발급
          • 모질라는 수퍼 CA 하나만이 아니라 실질적인 Root CA 역할을 하는 모든 기관이 개별적으로 검증을 받던지, GPKI 를 재설계 해야 한다고 지적.
          • 결국 행자부와 교육부는 개별적으로 인증서 검증을 받기로 함.
          • 또한 행자부 밑에 sub CA 로 있던  대법원, 대검찰청, 병무청도 빠짐. 이들은 원래 검증기관에 CP 및 CPS 문서를 제출하지 않고, 외부기관 감사도 받지 않는 것을 전제로 sub CA 에 들어있었는데, 모질라가 인증서를 발급하는 주체는 모두 검증대상이라고 했기 때문이다.
        • 사건2: 2018년 3월 행정안전부·교육부 인증서 부실관리 실태 노출
          • 2018년 4월초 행정안전부와 교육부, 두 정부부처의 인증서 발급이 이상했다.
            • 구글 포럼 제보
            • 1. 행정안전부 행정전자서명인증센터 사이트 인증서 :  유효한 '온라인인증서상태프로토콜(OCSP)' response을 제공하지 않는다
            • 2. 교육부 행정전자서명인증센터 사이트 인증서 : HTTP 인증서해지목록(CRL) endpoint 및 OCSP HTTP endpoint 정보가 없다.
          • 모질라 측은 4월 중순 한국 정부에 해명을 요구
          • 결국 8월 검증 절차를 중단
        • 사건3: 2018년 4월 인증서 부정발급 실태 노출
          • 2018년 4월초 모질라의 온라인 포럼인 '버그질라'에는 또다른 두 가지 인증서 관련 문제가 추가로 제보(1451235 - Distrust the WebTrust Audit of Deloitte Anjin South Korea)
            • 1. 행정안전부와 교육부가 도메인검증을 하지 않은 인증서를 발급
            • 2. 교육부가 교육기관용으로 각 기관별 도메인이 아닌 최상위도메인(TLD) 범주를 지정한 '와일드카드' 인증서를 발급. 
              • 교육부가 웹트러스트 인증을 받은 시점에 발생
              • 교육부는 웹트러스트 인증을 위해 '딜로이트안진'에게 외부감사를 받았었다. 교육부가 외부감사를 통과했는데, 문제가 발생해서 '딜로이트안진'의 감사 신뢰성이 무너졌다.
              • 행정안전부의 감사도 '딜로이트안진' 이 맡았었기에, 행정안전부의 감사결과도 신뢰를 잃게 되었다.
          • 당시 문제가 된 인증서들은 곧 폐기



        사건3 이 문제가 되는 이유는 우리가 https 를 사용하기 위해 인증서를 신청하고, 발급받는 과정을 생각해 보면 이해가 간다.




        References


        1. 정부, 공공사이트 HTTPS '보안경고' 못 없앴다 - 지디넷코리아




        [컴][알고리즘] AES 암호화 설명






        •  key expansion 은  key 를 4-byte 씩 쪼개어서 array 에 담는것
        • 16-byte 씩 작업을 하게 된다. 4 x 4 의 matrix 이다. 이 하나의 matrix을 state 라 부른다. 아래그림 참조
        • 각 정해진 bit 마다 round 가 정해져 있다.(128bit 은 10round, 256bit 는 14 round)
          • 각 bit 의 암호마다 "key-length/block-size/rounds" 수가 정해져 있다.
        • 이 (round-1)수 만큼 loop 을 돈다. 그리고 마지막 round 만 따로 한다.
        • 마지막 round 는 mix-columns 작업을 하지 않는다.

        AES encryption process

        1. SubBytes

        sub 가 substitute 라고 보면 된다. State 에 있는 각 위치의 byte 에 해당하는 값을 "특정 table" 의 값과 교환하게 된다. 이 table 은 아래처럼 정해져있다.

        여기 를 보면 어떻게 SubBytes 를 하는지 알 수 있다.

        S = [ 
        0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01,
        0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d,
        0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4,
        0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
        0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7,
        0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
        0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e,
        0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
        0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb,
        0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb,
        0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c,
        0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
        0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c,
        0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d,
        0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a,
        0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
        0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3,
        0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
        0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a,
        0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
        0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e,
        0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9,
        0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9,
        0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
        0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99,
        0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ]
        
        from: https://www.youtube.com/watch?v=gP4PqVGudtg

        2. Shift Rows

        아래처럼 각 row 를 shift 한다. 0번째 열은 '0'번, 1번째 열은 '1'번 ...
        from: https://www.youtube.com/watch?v=2y_tidbY-Lw

        3. MixColumns

        여기 를 보면 animation 을 볼 수 있다.

        state 의 각 column 을 Galois field 와 곱하기(matrix 곱하기) 를 하게 된다. 만약 GF(255) 라면 0~255 사이의 숫자로만 구성된 field(matrix) 가 만들어진다.



        4. Add Round Key

        "State 의 각 byte" 와 "Round key 의 각 byte" 을 XOR 한다.
        from: https://www.youtube.com/watch?v=2y_tidbY-Lw



        CTR mode 사용시 유의할 점

        • PHP data encryption primer > Encryption algorithm / mode of operation / nonce (initializing vector)
          • single key 를 사용하는 경우는 nonce 가 unique 해야만 안전함을 보장한다.
          • ...



        [컴][go] golang 의 interface{}(interface type) 의 itable 이 어떻게 생성될까.

        golang itable  / how to generate itable in go / go virtual function table /

        Go의 itable 의 생성

        interface{}(interface type) 에 대한 itable 이 어떻게 생성되는지에 대한 설명이다.

        Go 의 dynamic type conversion 들은 compiler 또는 linker 가 미리 모든 가능한 itable 들을 미리계산하는 것이 합리적이지 않다는 뜻이다.

        너무 많은 (interface type, concrete type) pair 들이 존재한다. 그리고 대다수는 필요하지 않을 것이다. 대신에, 컴파일러는 위의 예제의 Binary, int 또는 func(map[int]string) 같은 각 concrete type 에 대해서 type description structure 를 생성한다.

        비슷하게, 컴파일러는 interface type 에 대해 다른 type description structure 를 하나 생성한다. 그것 또한 method list 를 갖고 있다. interface runtime 은 interface type 의 method table 에 있는 모든 method를 concrete type의 method table 에서 찾아서 itable 을 계산한다.

        runtime 은 itable 을 생성한 후에, 이것을 caching 한다. 그래서 이 것은 한번의 계산만 필요하다.


        Computing the Itable

        Now we know what the itables look like, but where do they come from? Go's dynamic type conversions mean that it isn't reasonable for the compiler or linker to precompute all possible itables: there are too many (interface type, concrete type) pairs, and most won't be needed. Instead, the compiler generates a type description structure for each concrete type like Binary or int or func(map[int]string). Among other metadata, the type description structure contains a list of the methods implemented by that type. Similarly, the compiler generates a (different) type description structure for each interface type like Stringer; it too contains a method list. The interface runtime computes the itable by looking for each method listed in the interface type's method table in the concrete type's method table. The runtime caches the itable after generating it, so that this correspondence need only be computed once. [ref. 1]

        References

        1. research!rsc: Go Data Structures: Interfaces
        2. How to use interfaces in Go by jordan orelli

        [컴] cpu가 그래픽처리를 위해 GPU를 사용하는 과정



        그래픽카드와 함께 CPU 가 좋아야 하는 이유

        내용에 틀린부분이 있을 수 있다. 그러니 의심이 가면 관련 부분을 찾아보기 바란다.

        일단 단순하게 표현하면, 던전으로 들어가기 전과 후의 장면은 크게 달라진다. 그런데 캐릭터가 던전으로 들어갔는지, 아니면 그 앞까지 왔는지를 결정하는 것은 graphic 부분이 아닌 다른 code 부분이다. GPU 가 graphic 부분의 일을 처리하겠지만, 그 이외의 logic 을 계산하는 것은 cpu 이다. 그러므로 cpu 가 느리다면, 결국 gpu 가 아무리 빨라도 끊김(흔히 버벅임)을 방지하기는 어렵다.


        cpu가 그래픽처리를 위해 GPU를 사용하는 과정

        The_CUDA_Handbook.pdf 에서 좋은 설명을 확인할 수 있다. 여기선 일부를 정리해 놓았다.

        cpu 와 bus



        현재까지, 보드의 south bridge가 대부분의 주변기기들을 담당하고, north bridge 가 memory controller 를 가지고 있다. 그래서 이 north bridge 의 memory controller 를 이용해서 cpu 는 memory 와 통신한다.(이 통신이 이뤄지는 interface 가 front-side bus 이다.)

        그리고 north bridge 는 gpu 와 PCI Express interface 를 이용해서 통신한다.(물론 pci express 이전에는 AGP 같은 것이 있었다.)

        gpu 안에는 gpu memory controller 가 들어가 있다. 그래서 이 memory controller 를 통해 gpu memory 와 통신한다.

        Memory controller 가 CPU 안으로

        이러다가 cpu 가 memory controller 를 내장했다.(AMD의 Opteron 과 Intel의 Nehalem (i7) ) 그래서 north bridge 없이 바로 memory 와 통신하게 된다.

        그리고 I/O Hub 를 통해 PCI express interface 를 사용해서 GPU 에 접근한다.

        HyperTransport (HT) / QuickPath Interconnect (QPI) interface

        이 상황에서 cpu 를 여러개 사용하기 위해 cpu 간의 통신이 필요했다.(Multiple CPUs (NUMA)) 그래서 생긴것이 HyperTransport (HT) / QuickPath Interconnect (QPI) 이다. 이 interface 로 cpu core 끼리의 통신과 cpu 와 I/O hub 와의 통신을 하게 된다.

        • cpu core <---> cpu core
        • cpu <---> I/O hub

        I/O hub 가 CPU 안으로

        인텔의 Sandy Bridge 부터 I/O hub 를 cpu 안에 내장하게 된다.




        CPU/GPU 연동

        The_CUDA_Handbook.pdf 의 2.5 부분의 내용이다.

        GPU 는 직접적으로 page-lock 된 CPU memory 에 DMA 를 통해 접근할 수 있다.

        Page-locking 은 주변 하드웨어가 CPU Memory 에 직접적으로 접근할 수 있도록 해주기 위해 OS가 사용하는 기능이다.

        locked page 들은 OS 에 의해 퇴출(eviction) 에 적합하지 않다고 표시된 상태이다. 그래서 device driver들은 이 주변기기들이 메모리에 직접적으로 접근하기 위해 페이지들의 물리적인 주소들을 이용하라고 프로그램할 수 있다.

        CPU 는 여전히 불확실한 상태에서 memory 에 접근할 수 있다. 그러나 메모리는 옮겨지거나, disk 로 paged out 되지 않는다.

        DMA 는 GPU 가 CPU memory 를 "cpu 의 실행"에 대해 독립적으로 그리고 병력적으로 read/write 할 수 있게 해줬다. 다만 여기선 race condition 들을 피하기 위해 CPU 와 GPU 사이의 싱크를 맞추는 것을 고려해야 한다.
        • Pinned host memory(pinned buffer): GPU 가 직접 접근할 수 있는 CPU memory 부분
        • Command buffers: GPU 실행을 통제하기 위해 CUDA driver 에 의해 write되고, GPU에 의해 read 되는 buffer. 

        pinned buffer

        pinned buffer 는 direct access 를 위해 GUP 에 의해 mapping 된다. CUDA 에서는 API cudaMallocHost() 를 통해 allocate 할 수 있다.

        pinned buffer 가 주로 사용되는 방법중 하나는 GPU 에 command 를 보내는 용도이다. CPU 가 command 를 buffer 에 write 하고, 동시에 이것을 GPU 가 이전에 write된 command 를 read 하고 execute 한다.

        이 buffer 의 앞부분(leading edge) 에 CPU 가 command 를 write 한다. 그래서 GPU 가 이때는 이 녀석을 읽을 수 없다.

        GPU 는 buffer 의 끝부분(trailing edge) 에서부터 command 를 읽어드려서 실행한다.

        이 command buffer 는 circular queue 라고 보면 된다. 그래서 한번 command 처리를 다한 부분은 다시 CPU 가 command 를 write 하기 위해 사용된다.

        cpu-bound / gpu-bound

        이 상황에서 2가지 case 가 있는데 CPU-bound 와 GPU-bound 다. bound 는 "경계" 의 뜻이니, CPU bound 는 CPU 가 경계가 되는 경우라고 보면 되고, GPU-bound 는 GPU 가 경계가 되는 것으로 보면 된다.
        • 하나는 CPU 의 command 를 write  < GPU 의 처리 속도(CPU-bound)
        • 하나는 CPU 의 command 를 write  > GPU 의 처리 속도(GPU-bound)


        References

        [컴][웹] Server-Side Event(SSE)

        서버 사이드 이벤트 / 폴링 / 푸쉬 메시지 / notification / noti



        Server-Side Event(SSE)

        여기서는 ref. 2 에 있는 이야기의 일부를 다룬다. 되도록 ref. 2 내용 전체를 보는 것이 더 도움이 될 듯 하다.

        대략적으로 이야기하면, 이녀석은 기본적으로 ajax 로 했던 polling 을 browser 가 대신해준다고 생각하면 된다. 즉, polling 을 사용했어야 하는 모든 경우에 사용할 수 있다. 그리고 polling 이 끊겼을때등에 대한 처리에 관한 설정(id 같은, ref. 2를 참고) 도 가능하기 때문에 훨씬 편리하고 좋다.

        그리고 ref.2 에 보면 SSE 는 http protocol 로 만들어졌다고 한다. 그래서 이것을 실행하는 주체는 browser 안에서 layer 가 좀 다를 수는 있지만, js script 내에서 polling 을 구현한 것이랑 거의 다를 바가 없을 듯 하다. 여하튼 ref. 2 에서는 이것을 event streaming 이라고 부른다.


        event streaming 을 close 하는 법


        이렇게 주기적으로 browser 가 server로 부터 event 를 받아오는데, 이것을 close 하는 방법이 2가지 있다.
        • 서버에서 close 하는 법 : 
          • Content-Type 이 text/event-stream 가 아닌 response 를 보내거나
          • 200 이외의 HTTP status 를 보낸다.
        • client 에서 close 하는 법
          • source.close();
        다만 이런 방법으로 Event streaming 을 끝내지 않고, 만약 network 가 끊어진 상황, 즉 browser 가 아예통신을 못하거나 한 상황에 의해 event streaming 이 끊긴 경우라면, browser 가 알아서 주기적으로 연결을 위해 시도를 한다.


        message event

        기본적으로 발생시키는 event 는 message event 이다. 하지만, server 의 응답에 "event" 를 정의해서 browser 로 하여금 새로운 event 를 발생시키도록 할 수 있다.
        event: servertime
        data: The server time...

        source.addEventListener('servertime', function(event) {
            document.getElementById("result").innerHTML += event.data + "<br>";
        });



        Response

        header 조건

        1. Content-Type: text/event-stream
        2. Cache-Control: no-cache

        body

        • data: data_you_want_to_put
        reponse body 이 딱 data 만 있으면 된다. 다른 option 들도 존재한다.(ref. 2 참고)
        data: The server time...




        Security 

        보안상의 이슈로 client 에서 event handler 를 구현할 때 event 의 origin 을 check 하라고 한다.[ref. 2]
        source.addEventListener('message', function(e) {
          if (e.origin != 'http://example.com') {
            alert('Origin was not http://example.com');
            return;
          }
          ...
        }, false);
        
        

        References

        1. HTML5 Server-Sent Events
        2. Stream Updates with Server-Sent Events - HTML5 Rocks

        [컴][DB] MySQL 에서 transaction 과 isolation level

        mysql / mysql race condition / read shadow read /lock

        MySQL 에서 transaction 과 isolation level

        아래는 정리되지 않은 글이다. 정리는 추후에...

        mysql 의 default isolation level

        MySql 의 InnoDB 는 Repeatable-read 가 기본 isolation level 이다.

        기본 sql standard

        sql에서 Repeatable-read 는 아래 3가지를 만족한다.

        • dirty reads (non committed data)
        • non repeatable reads (executing the same query twice should return the same values)
        • allows phantom reads (new rows are visible).

        MY SQL 의 default isolation 변경법

        실행시에 --transaction-isolation=level option 을 사용하면 된다.(참고)

        현재 isolation level 확인방법

        -- to check the current isolation level
        SHOW variables like 'tx_isolation'

        isolation levels

        • SQL Server 트랜잭션 잠금 및 행 버전 관리 지침 | Microsoft Docs
        • SERIALIZABLE : REPEATABLE READ 보다 더 엄격 하다. XA transactions 이나 concurrency 와 deadlocks의 troubleshooting 을 위해서
        • REPEATABLE READ : 가장 높은 수준의 consistency(일관성)
        • READ COMMITTED : locking 에 대한 overhead 가 더 중요해서 precise consistency 와 반복적인 결과들이 덜 중요할때 사용할 수 있다.
        • READ UNCOMMITTED : READ COMMITTED 와 같다. 단 dirty read(select 가 nonlocking 된 상태로 수행된다.) 가 허용된다.(consistency 를 보장하지 않는다.)
        격리 수준 커밋되지 않은 읽기 반복되지 않는 읽기 가상
        READ UNCOMMITTED
        READ COMMITTED 아니요
        REPEATABLE READ 아니요 아니요
        스냅숏 아니요 아니요 아니요
        직렬화 가능 아니요 아니요 아니요

        가상읽기(Phantom read)가 가능하기 때문에 만약 아래와 같은 2개의 transaction 이 동시에 실행되는 경우 transaction 1 의 첫 SELECT 와 두번째 SELECT 가 다른 결과를 같게 된다. (두번째 select 의 결과 row 가 더 많을 것이다.)

        -- Transaction 1
        SELECT * FROM table1
        SELECT * FROM table1
        
        -- Transaction 2
        INSERT INTO table1 ...

        아래와 같은 transaction 이 동시에 일어나는 경우, INSERT 가 2번 된다. 이를 막기 위해 insert 시에 index 를 지정해서 넣어주면, 같은 index 에 insert 를 피할 수 있다. 하지만 문제는 끝부분에서 중복이슈는 없지만, 중복 이슈와 상관없는 경우에도 insert 가 실패하기 때문에 문제가 될 수 있다.

        그리고 상품이 2개이상이 동시에 열리는 경우 2개의 상품의 마지막투자가 같은 순간에 이뤄지면, 둘다 같은 index 를 next 로 잡아서 insert 를 할 것이고, 그것이 충돌을 일으킬 수 있다.

        해결책

        결국 queue 를 두는 방식으로, 즉 worker 로 넘기는 방식을 쓰기로 했다. 아무래도 그래야만 consistency 가 유지될 수 있다고 본다.

        -- Transaction 3
        SELECT * FROM table1 ...
        -- insert depending on the result of the select
        INSERT INTO table1 ... 

        See Also

        1. 쿠…sal: [컴][db] RDBMS 내부를 설명한 자료

        References

        1. Understanding MySQL Isolation Levels: Repeatable-read | Official Pythian® Blog
        2. MySQL :: MySQL 8.0 Reference Manual :: 15.5.2.1 Transaction Isolation Levels

        [컴][하드웨어] GPU 의 memory bandwidth 와 VRAM



        GPU 의 memory bandwidth 와 VRAM

        다음은 ref. 1 의 "Memory Bandwidth, Memory Capacity" 부분을 의역한 내용이다.

        ----

        메모리 대역폭(memory bandwidth) 는 GPU 의 VRAM 에 한번에 얼마나 많은 양을 넣고(copy to), 뺄수(copy from) 있는 지를 알려준다. 당연한 이야기지만, 같은 해상도(resolution)에서 시각효과(visual effects) 가 많을 수록 더 높은 memory bandwidth 가 필요하다.(더 많은 data 를 한 번에 옮겨야 하니.)

        VRAM 의 총용량은 GPU 의 다른 중요한 요소다. 필요한 VRAM 의 양이 현재 가능한 리소스를 넘어선다면, 게임은 계속 돌겠지만, 이 부족한 memory 부분만큼 CPU 의 main memory 를 이용하게 된다.

        이것은 GPU 가 DRAM 에서 data 를 가져오게 돼서, GPU 의 VRAM 에서 가져오는 시간보다 더 오래 걸리게 된다. 결국 이것이 게임화면의 버벅임을 만들게 된다.

        그래서 VRAM 의 양이 중요하긴 하지만, 일부 low-end 그래픽카드는 쓸데없이 VRAM 이 많은 경우가 있다. 즉, VRAM 이 부족해 지기 전에 다른 부분에서 bottleneck 이 걸릴 수가 있다. 그러므로 이런 경우를 방지하기 위해 benchmark 결과등을 잘 살펴서 구매를 할 필요가 있다.

        ---

        Memory Bandwidth Specification


        GPU 와 VRAM 간의 memory bandwidth 는 GDDR 의 spec. 을 확인해 보면 된다. GDDR6가 요즘 나오고 있다. 고대역폭을 위해 새롭게 만든 HBM(High bandwidth memory) 이라는 스펙도 있다. 이녀석은 GDDR6가 나오고는 경쟁력이 확실히 많이 떨어졌다.

        GDDR6의 데이터 전송 속도는 최대 18Gbps로 고성능 GPU의 384비트 메모리 버스에선 864GB/s의 대역폭((18Gbps * 384bit )/ 8bit = 864GB/s)이 나온다.



        References

        [컴][HDD] Degaussing (디가우징) 이후에 HDD 를 재사용할 수 있나?

        하드디스크 디가우징후 다시 하드를 사용할 수 있나? / 하드 재사용 / 디가우징 하드 재사용


        Degaussing 이후에 HDD 를 재사용할 수 있나?


        요즘 디가우징(degaussing) 이 이슈이다. 그래서 관련해서 HDD 드라이브에 대해 좀 더 알아보기로 했다.

        디가우징을 하면 데이터가 사라진다는 것은 알고 있다. 그럼 이 degaussing 을 한 HDD 를 다시 사용할 수 있을까??

        degaussing tool 에 따라 다르다

        결론은 degaussing tool 에 달려있다. degaussing 을 할 때 servo mark (또는 servo sector 라고 함) 를 지우느냐 그렇지 않느냐에 달려있다. ref. 3을 보면 servo mark 를 살리는 degaussing tool 도 존재하는 듯 하다.


        servo mark, servo sector


        그럼 이 servo sector 가 무엇이길래 이것에 따라 HDD 를 다시 사용할 수 있기도 하고 없기도 할까?

        HDD 는 아래와 같이 만들어져 있다. 여기서 HDD 의 head arm 이 disk platter 위를 움직이면서 read/write 를 하게 된다. 이때 이 head arm 이 움직이는 길을 만들어주는 것이 servo sector 이다.
        출처 : https://ayende.com/blog/174561/the-guts-n-glory-of-database-internals-managing-records

        일단 HDD 를 구성하는 flatter 내부를 보자. 보다시피 servo mark 가 존재하고, servo mark 사이에 data 를 write 하게 된다.(좀 더 자세한 내용은 ref. 4를 참고하자)

        ser




        servowriter

        servowriter 는 HDD 를 만드는 공장에서 platter 를 묶어서 HDD 로 만들기 전에 platter(raw media)위에 servo track 들을 그려준다.

        그러니 만약 degaussing 으로 servo sector 가 사라졌다면, platter 를 빼서, servowriter 로 다시 servo sector 를 그려줘야 한다.


        Servo(Servomechanism)

        서보메카니즘은 "피드백 제어 시스템" 이다. ref. 1 의 설명에 나와 있지만, 자전거타기를 생각하면 이해하기 쉽다.

        우리는 자전거를 타면서 넘어지지 않기 위해서 페달을 돌리고, 핸들을 좌우로 꺾는다. 그리고 돌부리가 보이면 핸들을 꺾어서 피하고, 다시 원위치로 돌아오는 등 상황에 따라서 자전거를 제어한다.

        이렇게 상황(output) 에서 오는 결과(feedback) 을 보고, 다음 동작(input) 을 하는 것을 이야기한다.




        References


        1. 서보 메커니즘 : 김상진
        2. Servowriter - Wikipedia
        3. Secure erase 9840 and 9940 data cartridges
        4. HDD from inside: Tracks and Zones. How hard it can be?
        5. 대통령 하드디스크도 통째 보관…근거없는 양승태 컴퓨터 '디가우징' - 노컷뉴스, 2018-06-28

        [컴][스크랩] 그래픽 관련 이야기

        graphics /  그래픽 이론 / GTA 관련 그래픽


        그래픽 관련 이야기



        [컴] EV, OV, DV 인증서의 차이

        인증서 종류 , ssl certificate 종류


        EV, OV, DV 인증서

        EV, OV, DV 인증서의 차이

        간단하게 이야기 하면, 인증서의 동작에 차이는 없다. 다만 인증서를 발급해 주는 기관(흔히 CA라고 한다.) 에서 얼마나 인증서를 발행 해 주기전에 check 를 하느냐의 차이다.

        그래서 EV, OV 에는 인증서(certificate)의 Subject field 에 'O'(organization) 가 추가된다. 그리고 Certificate policy 의 값도 다르다.



        EV, OV, DV 확인법[ref. 3]

        2012년의 ref. 3 에서는 현재로서는 DV(Domain validated)와 OV(Organization Validated) 를 구분할 수 없다.고 했다. 이때는 CA/Browser Forum 에서 제시한 Baseline Requirements 가 막 나왔을 때였어서, 각 CA(Certificate Authority)마다 어떤 식으로 OV인지, DV인지 표시하는 방법이 달랐다고 한다.

        하지만 현재는 2018년이니 훨씬 더 많은 CA가 Baseline Requirements 를 따르고 있을 것이라 생각한다.

        Certificate policy 에 기록

        RFC 5280

        X.509 에서는 RFC 5280 에 정의된 것처럼 Certificate policy 에 어떤 종류의 certificate 인지 적는다.

        CA가 자신의 OID(object identifier) 를 적는다. 이 OID 는 발급한 certificate과 관련된 practices 를 적어놓은 문서를 가리킨다.
        • http://oidref.com : 여기서 oid 번호가 어떤 의미인지 파악할 수 있다.

        CA/Browser Forum

        Baseline Requirements 에서도 같은 방법을 사용한다.

        google 의 인증서, OV
        GlobalSign 의 EV 인증서
        DV 인증서 예제


        DV, OV, EV 발급방법의 차이

        DV(Domain Validated)

        • 회사정보를 확인하지 않고, 인증서에 보이지도 않는다.[ref. 4]

        OV(Organization Validated)

        An Organization Validation (OV) SSL certificate is considered to be suitable SSL certificate for medium to large size business. This is because it offers higher validation as compared with DV certificate and displays domain name, organization name on the certificate. The encryption offered is up to 256-bit that enhances user’s confidence in the website they are transacting on.
        On the other hand, for the issuance of EV SSL certificate, you need to submit quite a lot of documents to the certificate authority as per their need and requirement. This stringent verification process ensures strong encryption with a green padlock sign in the address bar ensuring protection against hackers.


        Read more https://thebroodle.com/web/ssl/how-ev-ssl-certficate-works/
        • An Organization Validation (OV) SSL certificate
        • OV 를 발급받을 때는
          • 도메인 소유권을 확인하고,
          • "기관(organization)과 "인증서를 신청한 개인"에 대한 조사

        EV(Extended Validation)

        • CA/B forum 에서 제안했다.
        • CA가 "기관(organization)" 과 "인증서를 신청한 개인"에 대해 훨씬 엄격한 검사
        • ref. 5를 보면 EV 인증서는 발급에 대략 1개월 정도 소요되는 듯 하다. 참고로 ref. 5 에서 이야기한 저렴한 곳은 여기 같다.

        See Also

        References

        1. What is an EV (Extended Validation) SSL Certificate and How it Works?
        2. What Are the Types of SSL?
        3. How to tell DV and OV certificates apart | UNMITIGATED RISK, 2012년 9월
        4. DV, OV or EV? How to offer the right SSL Certificate - OpenSRS, 2015. 5. 22
        5. EV SSL 인증서 발급 과정에서 알게된 것들 - 리디주식회사 RIDI Corporation, 2017년 3월 5일

        [컴][보안] 로그인 관련 보안 2

        로그인과 보안 / secure login / 로그인 고민




        목차
        1. 로그인 관련 보안 - 1
        2. 로그인 관련 보안 - 2










        handshake - exchange the symmetric key

        여기서 관건은 MitM 공격이 ssl 을 해놨을 때 틀린 CA 에 대해서 volley (정확히는 HttpsConnection) 가 verification 을 해서 error 을 내뿜으면, 굳이 이 작업을 하지 않아도 될 듯 하다. 그러나 이것은 실제 test 를 해보기 전에 아직 확신할 수 없다.


        client <-------------> server
        request key   ---->
                      <---- public key
        symmetric key ----> 


        public key 를 server 에서 받지 않는다.

        ssl/https 에서는 public key 를server 에서 받은 후 그 public key 를 이용해서 symmetric key 를 주고 받게 된다. 이 경우에 인증서를 인증할 수 있기에 이렇게 한다. 하지만 나는 보내주는 public key 가 누가 보냈는지 알 수 가 없다. 중간에서 공격자가 보내도 그냥 맞는 거구나 하고 보내 버릴 것이다.



        server 가 client 로 부터 symmetric key 를 받고나서 server 는 해당 key 를 어떤 user 의 key 라고 알고 있어야 한다. 그래야 해당 user 의 request 가 오면 그 key 를 사용해서 복호화(decryption) 을 할 수 있다. 이를 위해서 DB 에 저장이 필요하다.


        이 때 token 이 있는 경우라면, token 을 보고 user 를 구분할 수 있다. 하지만, token 이 없는 경우라면, 임시로 저장을 해 놓아야 하는데, 이를 위해서 phone number 를 public key 로 암호화 해서 보낸다.

        하지만 여기서 "폰번호" 는 임시 token 으로 사용하는 것이라, 실제 id 와 연관된 db 에 저장하지 말자. 실제 id 로 사용되는 폰번호와 관련해서 사용하면 공격자가 이상한 값이나 존재하는 값과 비슷한 값을 보내는 경우 다른 사람이 사용하는 record 에 저장하는 문제가 생길 수 있다.

        • token 을 가지고 있는 경우 : token 을 보고 판별한다.
        • token 이 없는 경우 : 폰번호를 public key 로 key 를 주고받을 때 같이 보낸다.
          • 가입이 이미 되어 있는 경우
          • 가입이 안된 경우



        Hacking

         아래와 같은 공격이 가능하다. 하지만 아래와 같이 할 것이라면, 차라리 가짜 app 을 하나 만들어서 비밀번호를 입력하게 하는 것이 훨씬 간단하다. 그래서 그나마 공격자가 선택하는 방법은 public key 를 바꿔 놓는 수준이 될 듯 하다.

        공격자가 자신의 server 로 접속하게 해서 비밀번호를 알아낸다.


        이상황에서 고려할 수 있는 hacking 은 누군가(여기서는 A라고 칭하자.) 의 핸드폰을 몰래 가져다가 public key 를 공격자의 public key 로 교체하고 A 에게 다시 돌려주는 것이다.

        이 상황은 ssl 인증서로 무력화 될 수 있지만, 폰을 훔쳤을 때 인증서도 조작할 수 있다.

        그러면 A 는 이 public key 를 가지고 통신을 하겠지만, 직접 server 와 통신할 수 없다. key 가 틀려서. 그래서 domain 을 공격자의 server 로 변경해 놓는다.
        1. public key 변경
        2. domain 변경(or DNS 조작)
         이 상황에서 공격자의 server 와 통신을 하면서 A 가 실제로 송금을 한다면, 송금은 안되지만, 공격자는 A 의 auth token 과 비밀번호를 알 수 있다.
        1. auth-token
        2. 비밀번호
        이러면 공격자는 A 의 폰을 훔치고, 이 auth-token 과 비밀번호를 가지고 자신의 계좌로 송금할 수 있다.

        대처

        이 상황을 막고자, public key 를 쉽게 바꿀 수 없도록 한다. 그 방법으로 public key 를 file 자체로 놔두지 않고, xor 등의 연산을 통해 만들어 사용한다. 그리고, crc 등의 방법을 사용해서 변경되지 않음을 확인한다?

        이글  이 도움을 준다.
        1. public key 를 xor 등의 연산을 통해 획득
        2. CRC 등의 방법을 이용해서 public key 내용이 변하지 않음을 확인.(이부분도 공격자가 변경 해 놓을 수 있다. 하지만 이런 식으로 힘을 드리는 것보단 차라리 app 을 교체해 놓는 것이 낫다.)
        3. 이체 후 서버에서 고객의 email 등(또는 GMS 등, 실제 서버만이 가능한 것)으로 알림을 준다. (폰으로 주는 것은 안된다. 공격자가 이미 전화번호를 알고 있어서 sms 를 흉내내서 보낼 수 있다.)
          이것은 고객이 자신의 송금 명령이 제대로 된 서버에게 보내졌는지를 확인하는데에 도움을 준다.












        [컴][보안] 로그인 관련 보안 1



        2015년10월에 정리한 글을 다시 옮겨왔다.




        Toss 의 로그인

        Toss 가 본인 명의의 휴대폰 1대에서만 사용가능하다고 한다.
        송금이 사용자의 휴대폰에서만 가능하다.

        그래서 자신이 직접 전화번호(phone number) 를 입력할 수 없다.

        폰번호, 기기 ID 확인은 어디서?

        폰번호 + 기기 ID (IMEI) 가 일치해야 할 듯 하다. 이것을 통신사에서 확인할 수 있나? 아니면 server 에 가지고 있어야 하는가?


        1. 사용자의 비밀번호를 아는 경우 : 사용자의 폰이 아니라서 불가능
        2. 사용자의 폰에서 시도하는 경우 (훔친 경우) : 사용자의 비밀번호를 몰라서 불가능
        3. 사용자의 폰을 복제하는 경우 : 새롭게 login 을 하면 문자가 날라온다. 그러므로 걸릴 듯 하다.
        4. 사용자의 폰을 훔친경우 + 비밀번호를 아는 경우 : 어쩔 수 없다?

        처음에 등록하는 암호가 이들이 사용하는 Login password 인 듯 하다.
        이 값을 받아서 hash 해서 저장하고, local 에도 hash value 로 저장 해 놓는다.
        그리고, 전화번호와 pw 를 보내서 인증을 받는다?

        toss 가 local 에 가지고 있는 값, TOSS.xml

        <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
        <map>
            <string name="gaCode">9WOv+FvTQXaaU2+aNj1DTw==
            </string>
            <string name="seqNo">zeYYBd62OnqMld4PxW64h++T+yhxeq3wA+Cb3BTBJWM=
            </string>
            <string name="aesKey">xOolFn/09ZO1boBpzGsMw3sWQ3AnlstqHfqPc9k+PJUhksJN0aRU7J631l2oLcme
            </string>
            <string name="pKey">Dw0tPa4Nm58Dt7UxfEuk7tOs7VSQ9pZPOMQ+VGthUU1HKDwTxcjeULVdwdIzQZkh
            </string>
            <string name="timestamp">RNZp58Zh16VZs4IKulvXtQ==
            </string>
            <string name="promotion"></string>
            <string name="privateKey">...
            </string>
            <string name="initData">...
            </string>
            <string name="pNumber">5bEKGSs6BbE2lE4vAt32lQ==
            </string>
            <string name="hasSetTossAlarm">9zV6TSbGJjPn0EnPdHkCxA==
            </string>
            <string name="birthDate">y/6msagccRolTPjekUgFCg==
            </string>
            <string name="name">4Ta03cJDFgrqcAT0RUgdJA==
            </string>
            <string name="faultCount">xfjOGX+ONgBoI7KVMAD40g==
            </string>
            <string name="INIT">9zV6TSbGJjPn0EnPdHkCxA==
            </string>
        </map> 



        SSL에서 Main-In-The-Middel Attack 





        Login 2


        여기 글 처럼 auth token 을 쓰자. 그리고 비밀번호를 수정할 때 마다 auth token 이 다시 만들어지게 된다. 이러면 아래의 고민 중 credential 을 stolen 당할 때 client 에 암호화 과정이 들어가 있어서 hacker 들이 추측할 수 있는 여지가 줄어든다.

        조금 다른 점은 새롭게 로그인할 때마다 시간을 기록하고, auth token 을 다시 만든다? time 을 더해서?
        그러면 한 앱에서 한개만 가능할 것이다.

        이건 처음에 생각한 것과 비슷한데, 처음 생각은 auth token 처럼 고정적인 token 을 만들생각을 안하고, expired token 만 고려했는데, 이번엔 2개의 token 을 사용하자.

        이 Auth Token 을 가지고 있고, 이녀석을 가지고 다시 expired 가 있는 token 을 얻어오도록 하자.


        https sniff, MITM

        MITM 의 공격에서는 보통 인증서가 잘못 되었다고 뜬다. (참고) 이것이 volley 에서 어떻게 동작하는지 확인이 필요하다. 만약 error 가 된다면, 굳이 https 가 공격 당할 걱정을 안해도 될까?? 일단 가능할 듯 하다.

        MITM 공격에 대비해서 https 위에 다시 한번 https 를 얹어놓자. 정확히 비슷하지는 않지만, sniffing 을 대비해서 한 번 더 encryption 을 해 놓는다. 이부분은 https 와 비슷하게, asymmetric encryption 으로 symmetric 의 key 를 주고 받고, 이 key 를 이용해서 encrypt 해서 보내면, server 에서 decrypt 를 한다.
        symmetric encryption 의 key 는 주기적으로 server 에서 교체하면 된다.
        client 의 public key 는 client 에 대한 인증역할도 같이 할 수 있다. 그러기 위해서 각 user 의 private key 를 저장하고 있는다.


        auth token, expired token

        expired token 이 csrf 공격의 방어 기능을 할 수 있다. 그렇다면 expired token 의 generation 을 절대적으로 핸드폰에서만 가능하도록 해야만 한다. phone number 를 가져와서 expired token 의 hash 를 만들때 사용한다.



        auth token , no expired token

        auth token 만을 이용하자. 이러면, rooting 된 폰에 의해서 auth token 을 stolen 되고, data/data 내용을 그대로 가져가서 새로운 폰에서 toss 를 시작한다고 하면, 여기서 다 잘 된다고해도, 송금할 때 결국 비밀번호를 다시 입력해야 한다. 그래서 괜찮다.

        폰정보를 가지고 있을 필요는 없어 보인다. 이 또한 복제될 수 있어서.

        expired token 이 필요치 않은 이유

        expired token 은 sniffing 때문에 필요하다고 생각했는데, expired token 대신에 auth token 을 사용하다가 sniffing 을 당한다고 해도, 결국 비밀번호를 다시 입력 하는 부분 때문에 사용할 수 없을 듯 하다.

        sniffing 에 대한 대비

        위의 <https sniff, MITM> 를 참고하자.
        expired token 등 sniffing 될 요소들을 사용할 때 한번 더 암호화 하고, ssl 을 사용한다. 이것은 hacked 된 https line 에서 해킹이 어렵게 해준다.

        그러면 비밀번호를 보내는 순간에 sniffing 을 당하지 않아야 하는데.... https 같은 경우 secured line 이 아닌 상황이라면, 비밀번호가 노출되는데, 이때를 위해 public key 로 암호화를 걸어놓자.? 하지만 이경우도 brute force 로 알아낼 것이다. 왜냐하면 toss 의 경우는 "숫자4+문자" 의 형태라, 경우의 수가 작은 편이다. public key 가 노출된 상황이라면, 모든 case 에 대한 table 을 가지고 있게 되고, 이런 상태라면 암호화를 한 비밀번호도 손쉽게 노출된다.

        그러면 주기적으로 public key 를 갱신해준다. ? 그러면 public key 를 저장하지 말고, network 로 받는다. 하지만 이 경우에 xor 등으로 난독화 하려는 계획이 어려워 질 수 있다. 물론 2개를 받아서 xor 후에 사용할 수도 있을 듯 하다.

        송금 수신자 정보 암호화

        만약 phone 을 hacking 하지 않고, sniffing 만 하는 경우에, token 을 알고 있다면, 송금이 가능해 진다. 이때 비밀번호가 같이 가기에 괜찮은데, 이렇게 되기 위해서는
        비밀번호와 수신자 정보를 같이 암호화 해야 한다. 따로 암호화 하면, 비밀번호 부분을 가져다 이용할 수 있다.
        그래서 encrypt("비밀번호","수신자정보") 형식등으로 암호화를 해서 보내야 한다. 그러면 비밀번호를 모르기에 암호화 키를 알아도 적절한 값을 만들 수 없다.
        그런데, 비밀번호가 간단하니, 여기에 "hashed 폰번호" 또는 "hashed timestamp" 를 추가로 이용한다.?



        rooting 에 대한 대비

        그리고 auth-token 은 rooting 등으로 쉽게 가져갈 수 있다. 이것은 다른 app 들에서 하듯이 rooting 인 phone 에서 실행이 안되도록 하는 방법이 있다. 하지만 이것도 우회하는 법들이 생겨났기에, 임시방편밖에 안된다.
        rooting 을 하고, token 을 가져간 공격자는 이것을 가지고, 시도를 할 수 있지만, 다행히 비밀번호를 몰라서 바로 hacking 당하지 않는다. 그러므로 잘못 시도된 비밀번호에 대해 user 에게 알려줄 필요가 있다.



        처음 등록시 password 전달

        처음에 public/private key pair 를 가지고 있는 상태가 된다. public key 를 client 가 가지고 있는다. 이 key 는 처음 password 를 등록할 때 쓰이게 된다.
        client 에서는 public key 로 암호화 한다. 이 때 random 값을 같이 준다.
        • public_key_encrypt(pw, random)
        password 와 public key 가 모두 노출되어도 유추할 수 없다. random 값이 없으면 rainbow table attack 이 가능할 수 있다.

        key 교체시

        key version 관리가 필요하다. 서버에서 key 를 바꾸고 새롭게 key 를 장착할 때 기존의 모든 client 가 새로 등록을 할 수 없게 된다. 이 경우에 새로운 버전을 설치하라고 알려줄 필요도 있을 듯 하다.


        default public/private key pair

        1. 처음에 접속하면 받도록 하자. 어차피 공개된 녀석이라 굳이 가지고 있을 필요는 없을 듯 하다.
        2. 이녀석은 client 에서 server 로 보내기만 하는 경우이면서
        3. 크기가 작은 녀석을 암호화 할 때 사용가능 하다.(asym 은 암호화 속도가 느려서 큰 것은 힘들다.) 

        symmetric 암호 key

        • public_key_decrypt<유저 입력 password  + 랜덤 값+ 폰 넘버>
        client 에서 결정하자. 이 시도가 좋지 않을 수 있다. 대부분 서버에서 결정하고 내려준다.(여기를 확인하면 이것이 일반적인 결정인 것을 알 수 있다.)

         임시 key 등은. 하지만 여기서는 public key 를 가지고 있는 쪽이 client 여서 client 가 결정을 내린다. public key 로 암호화 해서 보내면, private key 를 가진 server 만 알 것이다.


        client 에서 보낸 암호를 가지고 symmetric 암호화를 하면 된다. 이 때 symmetric 암호키는 랜덤한 값이며, 항상 password 를 보내는 순간에 password 와 같이 보낸다. 그리고 symmetric key 를 받자마자 서버가 symmetric 암호화로 data 를 보낸다. 이러면, sniffing 을 당해도 rainbow attack 등을 피할 수 있다. 그리고 매번 변경돼서, token 을 가져가도 크게 의미가 없다. 누군가 token 을 가지고 key 를 시도한다해도, 암호를 같이 encrypt 하지 않았다면 인정받지 못하게 된다.

        세션이 없기에, db 에 임시 저장이 필요하다? 이렇게 되면, 암호가 invalidate 되는 시점도 정확히 정해져야 한다. random 한 값이 사용되므로, 항상 db 에 저장해야 할 필요가 있다.TokenAuthentication 도 token 을 가지고, 이녀석에 해당하는 user 를 가져오는데, 이것처럼 TokenAuthentication 일 때 symmetric key 도 같이 가져오도록 한다.

        이 상황은 하지만,처음 로그인에서는 가능하지만, 이후에 token 으로 login 을 하는 경우에는 적합하지 않다. 송금을 누르고 송금정보가 날라갈 때 암호화할 key 가 이미 있어야 한다. 그렇지 않다면, 2번 왔다갔다 해야 한다.


        만약 client 가 random 하게 값을 정해서 server 로 보냈다고 하자. 그렇다면, 누구나 그렇게 random 하게 만들어서 server 로 보낼 수 있다. 공개키는 얻을 수 있으니. 그러면 server 는 아무하고 encrypted 통신을 하게 된다. client 가 공격자인 경우도 생긴다.



        Login

        • 전화번호 : 노출
        • public key : 해킹에 의해 노출
        • 비밀번호 : 입력
          • 비밀번호를 key logger 를 사용하지 않는한 안전하다고 가정.

        여기서 문제는 rainbow table 로 경우의 수를 만들어서 던져볼 수 있다. 그래서 local 에서 credential 을 만들 때 hashing 을 한 번 하고, 그 값을 가지고 credential 을 만들어야 한다. 그러나 그래도 source 를 decompile 한다면, hashing 횟수나 salt 를 쉽게 파악할 수 있을 듯.

        time delta

        time delta 를 쓰지 않으면, 결국 client 를 hacking 해서 보안이 문제될 수 있다.
        그래서 본인 휴대폰 인증받는 순간(문자, ARS 등)  의 시간을 기준으로 한 time 를 만들어서 보내자.
        그러고 인증이 통과되면,(로그인 완료후) 이 시간을 server db 에 저장 해 놓고,
        time(sec.) 이 이 시간에서 멀지 않은 시간(약 30분?) 으로 setting 된다면,
        ok 로 받아드린다.

        • 공격 유형 : 이것은 해커가 public key, id, pw 를 모두 알고 있는 상태에서 해 볼 가능성이 있는 공격이다. 근데 pw 가 노출될 확률이 낮다.



        폰을 도난 당한 경우

        누군가 폰을 훔쳐갔을 경우, 도둑이 rooting 을 할 수 있다. 그러면, SharedPreference 등에 접근할 수도 있고, 그대로 app 을 사용할 수 있다.

        정지방법
        이 경우에 외부에서 정지시킬 수 있어야 한다.
        1. 다른 폰에서 앱을 새롭게 login 을 하거나, : time-delta 로 이전 로그인을 차단한다.  / 비밀번호를 변경한다.?
        2. web 을 통해 정지 명령 : server db 에서 time 을 조작해서 time-delta 를 이용할 수 있다.
        이 가능하다.

        공격

        • 해킹을 통해, credential 을 얻은 경우 : 이 경우 시도해도, 위의 "정지방법" 에 의해 time-delta 가 맞지 않아서 걸린다. 그래서 setCurTime 을 이용한 time 대한 수정을 하려고 할 것이다.(아래 참고)
        • public key, id, pw, 얻은 경우 : time delta 를 알아내기 위해, 다양한 time 을 넣고, credential 을 만들고 사용하려 할 것이다. 이런 접근이 있는 경우 서버에서 감지해서 처리해야 한다. -> 패스워드 변경유도



        setCurTime 에 대한 공격

        만약 이 request 를 외부에서 해 온다면? 이걸 어떻게 app 에서만 하도록 할 수 있나?

        첫 인증시만 사용가능 하도록 : 이것은 ARS 인증? 등을 할 때, 인증이 성공한 경우에만(로그인을 하듯이) time 을 저장한다. 그 외의 경우에는 setCurTime 을 요청하지 않는다.

        본인인증 확인 가운데에 설정을 하는 것이라, 노출되지 않는다?
        credential 을 만들 때 전해준다.? : 이건 다른 쪽에서 비슷하게 흉내낼 수 있다. rainbow attack 이 들어올 것이다.

        공격 상황

        • 해커가 credential 을 가지고 있다.(public key (비밀번호 + id + timedelta )) 그래서 이 credential 에 time-delta 가 들어가는 것을 알고, 이 time-delta 를 맞추기 위해 setCurTime 을 특정 시간으로 조정하려 할 때(무자비하게 여러번 시도 할 것이다.), 
        • credential 을 새롭게 만드는 것도 시도할 수 있지만, 비밀번호를 모를 확률이 크다.













        본인인증

        • 한국 모바일 인증 > 개인정보취급방침 : 여기에 보면, toss 가 처음에 인증을 위해 필요한 항목을 입력하는 것과 일치하는 것을 알 수 있다. 아래 2가지 항목을 확인하자.
          • 본인확인기관(이동통신사, 공인인증기관 등)을 통한 본인확인 정보의 일치여부 확인 : 휴대폰번호, 통신사, 성명, 성별, 생년월일, 내/외국인 구분
          • 휴대폰 사용자 확인을 위한 SMS인증번호 전송

        위의 인증을 위해서라도, server 에서는 "전화번호"를 가지고 있어야 한다.


        OAuth 등의 로그인을 고려해 보자. facebook 같은 녀석으로 한번 login 을 하고 나면, 그 이후로 access token 으로 이녀석을 접근한다. 이것도 어쩔 수 없이 한번의 노출을 만들지만, 그 이후에 id/pw 는 노출되지 않으므로, 항상 id/pw 가 노출되는 것보다 현저하게 노출위험을 줄일 수 있다.

        같은 의미로, app 이 처음 실행할 때만 id/pw 를 입력받도록 한다. 그리고 나서 access token 을 발급하자. 그러면, 이 access token 을 저장하고 있다가, 다시 app 을 실행하게 되면, 이 access token 을 보내고,


        JWT vs Django login


        Using JSON Web Tokens as API Keys 를 참고해서 login 을 위해 JWT 를 사용하기로 했다.
        Redirecting Our Django Website to Our Ember App - Shippo

        장점

        • 위의 글을 참고한다면, 다양한 방법으로 token 을 이용할 수 있을 듯 하다.
        • Django Rest Framewrok jwt 를 이용하면, permission_class 등의 방법을 그대로 사용할 수 있다.


        Django login 도 같은 기능을 제공하긴 한다. csrftoken 을 이용해서, 그런데 문제는 site 에 접근하지 않고, csrftoken 을 받아오는 방법을 찾기가 시간이 걸린다. 그리고 확장성도 떨어진다. Django 자체의 login 과 연동하긴 좋을 수 있다.




        client 가입 알고리즘

        서버

        1. IMEI 와 전화번호를 서버에 저장한다.
          처음 인증할 때 "통신업체"를 통해 폰이 본인인 것을 확인한다.(아무래도 handset 자체에 대한 검증은 하지 않는 듯 하다.)
        2. public key 를 client에 넘겨준다.
        3. 이때의 datetime 을 기록한다.

        client

        1. public key 를 저장한다. 저장시 여기를 참고 
        2. IMEI 와 timestamp 를 public key 를 이용해서 암호화해서 저장하고, 이것을 사용한다.
          • 이것이 결국 password 역할을 할 것이다.
          • 해커는 이 날짜의 존재를 모르기에 만들기 어려울 것이다.
          • 만약 decompile 로 날짜와 함께 만들어진다는 것을 안다고 해도, 이 날짜가 특정시간에 맞춰야 하기에 그 특정시간을 알 수 없다.
        3. public key 를 가지고 있어도 되고, 버려도 된다.
        4. 이 암호화된 IMEI 와 phone number 를 server 로 날려서 token 을 받는다.

        서버

        1. 서버에서는 client 에서 온 암호화된 text 를 private key 로 decrypt 한다.
        2. 그리고 날짜를 public key를 넘겨준 날과 비교한다. 시간상 10분(?) 이내라면 허락한다.
        3. 그 이외의 날짜가 같이 IMEI 와 encrypt 된 경우에는 허락하지 않는다.




        asynch algo 를 사용한다. timestamp 를 넣어서 암호화된 text 가 steal 되어도 안전하게 만든다.





        client 에서 자동 로그인

        1. phone number SIM 에서 읽기
        2. device id 가져오기
        3. phone_number + device id 를 가지고 encryption or hashing
        4. 이 값을 server 로 전송해서 login

        pw 암호화

        device id 를 phone number 를 key 로 해서 암호화 한다. 이 때 key 는 phone number 를 4자리 단위로 shift 해서 만든다.
        • 01023026616 --->  66160102302 



        JWT

        djangorestframework-jwt  사용

        • 접속시에 token 을 만든다. 
        • 이 token 은 expiration time 을 갖는데, 이 expiration time 이 끝나기 전에 refresh 를 하면 계속 유지된다. (JWT_EXPIRATION_DELTA)
        • 하지만 이런식으로 같은 token 이 유지되는 시간도 한계를 정할 수 있다.(JWT_REFRESH_EXPIRATION_DELTA)
        • 어느정도 시간 유지가 적절한가?
        • 계속 화면을 띄워놓고 있는 경우에 계속 refresh 를 하기는 부담스럽다. 차라리 refresh 를 못하게 하고, expiration time 을 1일 정도로 가져가는 것이 나은가?






        IMEI 를 확인하지 않는경우

        SIM의 MSISDN + IMSI 를 복제된 경우

        여기서 toss 처럼 인증을 하면, 문자를 받거나, 전화인증에서 양쪽에 전화가 걸려올 수 있다. 그래서 노출될 수 있다. 하지만 그 순간에 본인이 핸드폰을 못봐서 넘어갔을 확률이 있으므로, 이를 대비해서 로그인 후 "로그인했다" 는 정보를 시간과 함께 sms 로 전달해 준다.

        그러므로 굳이 IMEI 정보를 알고 있지 않아도 될 듯 하다.



        로그인

        1번째 로그인

        폰에서 app 을 깔고, 처음 로그인 할 때 (전화번호, 이름, 기기 id ) 를 server에 저장
        그리고 계속 이 번호로 로그인한다.
        처음에 비밀번호를 등록할 때,


        이 때 특정 public key 를 보내준다. ???
        그럼 public key 로 특정 값을 암호화 해서 server 로 보내게 되면 server 는 그 값에 해당하는 private key 를 가지고 그녀석이 맞다는 것을 확인한다. 그런데 이것은 결국 https 라서, 전체적으로 이런 일을 중복해서 할 이유는 없다.


        2번째 로그인

        2번째 부터는 phone number 와 기기의 id 를 가지고 로그인한다?
        여기서 jwt 를 얻어온다. 그리고 이 값으로 통신한다.


        phone number 의 저장

        phone number 는 서버의 db 에 저장된다. 서버에서 직접적으로 sms 를 보내는 등의 일을 해야 하기 때문에 어쩔 수 없이 노출된 값을 가지게 된다.

        다만 DB에 암호화된 값으로 저장하고, decode 해서 사용할 수는 있다. 이 경우는 key 를 어떻게 가지고 있어야 할 지 고민해야 한다. 장고의 SECRET_KEY 를 이용할 수도 있다.


        패스워드, hash(phone_number + Device ID)

        송금할 때 사용하는 패스워드 이외에는 패스워드가 따로 없다. 대신에 기기의 ID(Device ID) 를 이용한다. 이 녀석을 직접적으로 pw 로 사용해서 확인할 필요는 없고, 이 ID 를 seed (또는 salt) 로 이용해서 나온 값(hash 값이면 될 듯 하다.)을 이용한다.

        이 값을 server 의 DB 에 저장하고, 매 로그인할 때 client 에서 (phone-number, device id) 로 hash 값(또는 암호화한 값)을 만들어 보낸다.?

        client 에 암호화, 해시함수를 두는 경우

        이것이 server db 를 해킹한 사람들이 client 의 library 에 대한 decompile 을 시도할 것이다.

        그러면 시간이 걸리겠지만 가능해 진다. (사실 암호화나, hash 함수나, 이름만 알면 그냥 사용하면 되고, 단순히 seed 나 salt 값을 어떻게 적용했는지의 문제일 뿐일 수 있다.)  그러면 hacking 해서 번호와 device id 에 대한 해독이 가능할 수 있다.
        하지만 이 경우에도 phone number 의 암호화가 되어 있는 경우에는 알아내기 힘들 수 있다.

        이 부분이 binary 로 되어 있어 decompile 이 어렵고 시간이 걸려서 포기하는 집단도 있을 것이다.

        application server 에 암호화, 해시함수를 두는 경우

        기기 id 와 폰 번호를 바로 server 로 넘기고, server 는 이 값을 가지고 hash function 을 이용해서 비밀번호를 만들어 저장해 놓는다.

        이 경우 hash function 은 노출되지 않아서 server db 를 해킹한 해커는 application server 에 대한 해킹을 다시 하지 않는 이상 db 에서 의미있는 값을 얻기 어렵다.

        하지만 client 쪽에서 format 만 맞춰서 쉽게 request 를 날릴 수 있게 된다. request 날리면 서버에서 알아서 암호화를 하고 비교를 할 테니, 암호화의 의미가 server db 가 해킹당했을 때의 대비만을 위한 것이 된다.



        만약 phone-number 가 노출된 경우

        phone number 를 phone SIM 에서 바로 가져오기 때문에(SIM 에서 안드로이드 SDK 를 통해) 직접 입력하지 않는다. 그래서 phone 의 SIM 에 새겨진 번호를 조작하지 않았다면 괜찮다.


        만약 SIM 을 조작했다면?(복제폰?)

        전화번호가 같더라도, device id 가 같지 않다. 그래서 이 경우에는 device id 까지 해커가 훔쳐야 한다.

        만약 SIM 을 복제 하고, device id 도 복제했다면

        폰으로 시도

        비밀번호를 몰라서 막히던지, 비밀번호 재설정을 할 때 막힌다.
        비밀번호 확인작업을 하는데, 이때 비밀번호 재설정도 할 수 있다. 그런데 재설정 작업은 이들이 자신만의 방법(계좌에 돈 보내고, 그 날짜로 확인)을 이용한다. 이과정 때문에 어쩔 수 없이 공인인증서 등으로 확인이 된다.
        그렇기 때문에 여기서 막힌다.

        pc로 시도

        여기에 어떻게 해서 이들이 send request format 에 맞춰서 송금 명령을 server 로 보냈다고 하자. 그러면 여기서 jwt token 을 얻고, 이 token 으로 계속 통신을 할 것이다. 하지만 송금할 때에는 다시 비밀번호를 직접 입력해야 한다. 결국 비밀번호를 몰라서 실패한다.



        기기 ID 가 노출되어서 알려진 경우

        기기id가 노출돼서 그것을 카피한 핸드폰으로 시도 해도 암호방식을 해킹해야 한다.

        암호방식 binary

        암호방식은 이것이 일단 binary라서 바로 해독은 불가능하지만 해킹이 불가능은 아니다. 그래도 memory 채 가져와서 사용할 수 있을지도.?


        그런데 시드 서버가 갖고 있어야 하는가?
        암호화한 값을 비교 할 수만 있면 된다.
        암호를 해독할 필요가 있나?
        서버가 털릴때를 대비해야한다.
        암호화도 털려서 온다해도 서버에서 인증이 거부 될만한 요소를 가지고 있는가?


        서버가 해킹될 때

        서버가 털리면
        • 암호화된 패스워드(기기id, IMEI)
        • 전화번호 : 암호화 하는 것이 나을 듯 하다. 속도의 저하가 있을 수 있지만 보안이 더 중요하다.
        • 실명
        • 암호화된 송금 비밀번호(hashed value)
        DB 암호화를 고려해 볼 수도 있다. (:: DBguide.net :: 데이터 전문가 지식포털)
        이 부분은 일단 많은 방법들이 나와 있어서 크게 문제되지는 않을 듯 하다.


        송금 비밀번호

        송금 비밀번호는 계속해서 다른 기기에서도 일치여부를 확인할 수 있어야 한다.
        그래서 서버쪽에서만 암호화 또는 hashing을 한다.

        hashing 의 salt 를 무엇으로 해야 하나?

        기기가 바뀌어도 유지돼야 해서, device id 는 안된다.
        폰번호가 바뀐 경우는 모르겠다.
        명확한 것은 실명인 듯 하다.


        스니핑에 대한 고려로

        송금 비밀번호를 서버쪽에 보낼 때 암호화가 필요한가? 필요할 듯 하다. 스니핑을 하지 않더라도, 임의로 값을 만들어서 보내는 경우에 앱을 통해서가 아니라 외부툴일 가능성이 있는데 외부 툴로 가능하게 되면, 쉽게 뚤린다. 토스의 5자리의 경우는 특히.

        그러므로 보내기 전에 한번 가공을 하고, 그 값을 서버 DB 에 저장된 값과 비교하는 것이 나을 듯 하다.

        이것도 마찬가지로 server db 가 해킹당한 후에 해커가 client 의 decompile 을 노릴 수 있다.



        서버쪽에서 해킹 당한 경우

        이 경우 hashing 되어 있어서, hashing algorithm 을 적용하고, salt 를 파악하지 못하면 의미가 없다. application server 도 해킹을 같이 당해야 한다.

        client 에서 당하는 경우


        • 클라이언트에서 입력한 상황에서 메모리의 값을 steal 할 확률 : 이정도의 해킹이 쉽게 될지 모르겠다. 메모리 주소를 쉽게 알 수 없을테니. 일단 잘모르겠다.
        • 키에 대한 로깅으로 해킹하는 방법이 있을 수 있는데 : 키에 대한 로깅을 방지하려고 난독 키보드를 이용한다.