[컴][보안] 로그인 관련 보안 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 할 확률 : 이정도의 해킹이 쉽게 될지 모르겠다. 메모리 주소를 쉽게 알 수 없을테니. 일단 잘모르겠다.
  • 키에 대한 로깅으로 해킹하는 방법이 있을 수 있는데 : 키에 대한 로깅을 방지하려고 난독 키보드를 이용한다.








[컴][웹] lumen 에서 session 사용하기



lumen 에서 session 사용하기

  • lumen version: 5.4.*

config/session.php

session.php 는 laravel 의 config 에서 관련 config를 가져와서 <lumen>/config/ 에 copy 하면된다.

그리고 이 session.php 를 load 하려면 boostrap/app.php 에 code 를 추가해야 한다.
$app->configure('session');


가능한 설정들은 아래와 같다. 자세한 사항은 config file 의 주석을 참고하자.

  • 'driver' => env('SESSION_DRIVER', 'file'),
  • 'lifetime' => env('SESSION_LIFETIME', 120),
  • 'expire_on_close' => true,
  • 'encrypt' => false,
  • 'files' => storage_path('framework/sessions'),
  • 'connection' => null,
  • 'table' => 'sessions',
  • 'store' => null,
  • 'lottery' => [2, 100],
  • 'cookie' => env(
            'SESSION_COOKIE',
            str_slug(env('APP_NAME', 'laravel'), '_').'_session'
     ),
  • 'path' => '/',
  • 'domain' => env('SESSION_DOMAIN', null),
  • 'secure' => env('SESSION_SECURE_COOKIE', false),
  • 'http_only' => true,
  • 'same_site' => null,


illuminate/session

illuminate/session 이 필요하다. 일단 설치를 해주자. 참고로 lumen 의 버전과 맞춰야 했다.
composer require illuminate/session
composer require illuminate/cookie "^5.4"


bootstrap/app.php

StartSession Middleware

bootstrap/app.php 에 middleware 를 추가해주자.
$app->middleware([
    \Illuminate\Session\Middleware\StartSession::class,
]);

SessionServiceProvider

SessionServiceProvider를 등록해주자.
$app->register(Illuminate\Session\SessionServiceProvider::class);
$app->register(Illuminate\Cookie\CookieServiceProvider::class);


binding

$app->bind(Illuminate\Session\SessionManager::class, function ($app) {
    return $app->make('session');
});

// cookie relevant
$app->bind(Illuminate\Contracts\Cookie\QueueingFactory::class, 'cookie');

위처럼 해주지 않으면 아래와 같은 exception 이 발생한다.
Illuminate\Contracts\Container\BindingResolutionException: Unresolvable dependency resolving [Parameter #0 [ <required> $app ]] in class Illuminate\Support\Manager


session 폴더 권한

windows 에서는 sessions 폴더를 만들어놔야 한다. 그렇지 않으면 ErrorException in Filesystem.php 이 발생한다. linux 에서도 만들어 놔야 하는지는 모르지만, 최소한 write 권한 설정은 해줘야 할 듯 하다.
<lumen>\storage\framework\sessions

session 사용법

당연한 이야기지만 session_domain 설정이 제대로 되어 있어야 session 이 동작한다.

.env file

SESSION_DOMAIN=.example.com
APP_NAME=company_name

Controller

$session = $request->session();
$session->put('sample','hello');
echo $session->get('sample');

$allValues = $request->session()->all();
echo $allValues['_token']
// delete
$request->session()->forget('key');
$request->session()->flush();


login

참고로 SessionGuard 에만 login() 이 존재한다. 로그인을 하게 되면 user 에 맞는 session 을 set 해주게 된다.(SessionGuard::updateSession)
  • Auth::login()
  • Auth::guard('web')->login()

view




References

  1. laravel - How can I use Illuminate\Session\Middleware\StartSession::class on lumen 5.2 - Stack Overflow
  2. laravel - Enabling session in lumen framework - Stack Overflow
  3. What's the best way to start the session manually?
  4. No longer works with Lumen 5.2 · Issue #23 · esbenp/lumen-api-oauth · GitHub

[컴][생각] 프로그래머의 초과근무

초과근무 /

프로그래머의 초과근무


Stack Overflow’s 2018 Developer Survey 에서 프로그래머들이 엄청나게 많은 양의 overtime 일을 하고 있다는 것이 드러났다. 그래서 관련되서 reddit 에 댓글들이 엄청달렸다.

reddit 에서 best 댓글은 아래와 같다.



프로그래머의 초과근무는 여러모로 좋지 않다. reddit 의 댓글에 있는 글들이 수많은 안좋은 이유를 알려준다.

프로그래머가 새로운것을 찾고, 학습하는 시간도 결국 프로그래머의 일하는 시간이지만, 안타깝게도 실제로 그것을 인정받기는 쉽지 않다.

그래서 나는 저 reddit 의 댓글에 찬성한다. 정말 이 한몸 불살라서 내가 돈을 많이 벌겠다는 의지가 아니라면, 정해진 시간만 일하라고 하고 싶다. 어차피 그 이외의 시간에도 풀리지 않았던 문제나 풀어야할 문제가 머리속에서 지워지지 않아서 자신도 모르는 사이에 일하게 될 테니 말이다.

References


  1. Stack Overflow’s 2018 Developer Survey reveals programmers are doing a mountain of overtime : programming

[컴][웹] sendmail 정보모음

sendmail

sendmail 버전확인

$>echo \$Z | /usr/sbin/sendmail -bt -d0

anti-spam 을 위해 "/etc/mail/access" 에 특정 domain 에 대해 어떻게 동작할지를 정해줄수 있다. 자세한 내용은 ref. 2를 보자. 여기서는 대략적인 이야기만 할 것이다.

  • /etc/mail/access

makemap

그런데 이 /etc/mail/access 가 text 파일인데 sendmail 에서는 이녀석을 이용하지 않는다. sendmail 이 이용하는 db로 변경해 주려면 makemap 라는 명령어를 사용해야 한다.(ref. 2, ref. 3 을 참고하자.)

/etc/mail$ makemap hash /etc/mail/access.db < /etc/mail/access

그러면 access.db 파일이 생성된다.

  • access.db

test 메일 보내기

$>echo "testing" | sendmail -f "nn.ng@tners.com" gack@gmail.com
  • -f option : from email 을 변경할 수 있다.

SMTP 가 TLS 를 사용하기

See Also

  1. GitHub - mjl-/mox: modern full-featured open source secure mail server for low-maintenance self-hosted email
  2. 쿠...sal: [컴][툴] 알아두면 언젠가 쓸만한 툴, 2023-04-29

References

  1. jnet_g > 이용안내 > [sendmail]센드메일 버전체크 하기 (리눅스서버에서)
  2. 불법스팸 - 메일 서버(Sendmail)관리자
  3. sendmail access.db by example | LinuxWebLog.com
  4. ''FEATURE(mailertable)'' ''' :: Chapter 4. Configure sendmail.cf with m4 :: Part I: Build and Install :: Sendmail :: Server Administration :: eTutorials.org
  5. Change sender address of outgoing emails in Sendmail

a

[컴] visual studio code 에서 유용한 extension 들

확장 / vscode 확장 / vscode plugin /



visual studio code 에서 유용한 extension 들

reactjs + typescript

See Also

[웹] 080 스팸 문자 거부 관련 사항

광고문자 / 스팸 거부 / 수신거부 / 080 문자 거부 시스템 / 무료 문자 거부 시스템


광고문자를 보낼때 '무료수신거부(080)' 관련 주의할 점

ref. 1 에서 080 관련 사항만 정리했다.

무료 번호인 080번호를 넣는 경우 “수신거부”만 기입하여도 되나요?
  • 정보통신망법 시행령 제62조에 따른 별표6에서 "수신자가 비용을 부담하지 아니함을 함께 안내"하도록 하고 있기 때문에 최소한 "무료"임을 표시하여야 함


발신번호를 080 무료수신거부 번호로 넣어서 전송 하는 경우 본문에 080 번호를 기입하지 않아도 되나요?
  • 080 무료수신거부번호가 발신번호(회신번호)로 되어 있는 경우에 무료수신거부방법을 안내만 하고 번호는 별도로 넣지 않아도 됨
  • '무료수신거부 : 통화'로 명시하면 됨


무료수신거부번호를 080 번호가 아니라 웹링크를 넣어 링크를 타고 들어와 수신거부 할 수 있도록 해도 되나요?
  • 무료라고 볼 수는 있지만 인터넷이 되지 않는 휴대전화 사용자가 있기 때문에 웹링크 방식에 따른 수신거부 방식을 안내하여서는 안됨
  • 스마트폰이 아닌 2G폰 사용자의 경우 데이터가 소진되는 경우에는 정보통신망법 제50조제6항에 위반될 수 있음


080 무료수신거부번호로 전화를 하는 경우 상담원과 24시간 연결되도록 운영해야 되나요?
  • 일반적인 영업시간 동안만 상담원 연결로 운영하여도 됨


수신거부 방법을 “수신거부(.무료.) 080-888-1992”로 표기하여도 되나요?
  • 법에서 요구하는 것은 수신자가 무료임을 알수있게 하여야 한다는 것과 해당번호로 전화를 하였을 경우 수신거부를 할 수 있음을 안내하도록 하는 것임
  • 문자수제한이 있는 상황에서 이를 이용자에게 설명하기 위한 가이드라인으로 "무료"라는 단어와 "거부"라는 단어를 사용하도록 안내를 하고 있는 것임
  • 따라서 위와 같이 표기를 하더라도 법에 위반되지 않음
  • 하지만 스팸수신거부를 회피할 목적으로 위와 같이 표기하는 경우 처벌이 될 수 있음

080 수신거부 시스템 제공 사이트

대체로 문자를 보내는 사이트에서 080 을 무료로 지원해준다.(계약서를 확인하자)



References

  1. [PDF]스팸 관련 정보통신망법 안내서 Q&A, 2016년 10월 18일

[웹] 메일관련 cloudflare DNS 설정하기

DNS MX 설정 / 클라우드 플레어


작성중...

cloudflare DNS 사용해서 메일 설정하기

다음의 스마트워크(see also. 1) 을 사용해서 기업메일 설정을 하고 있다. 그런데 webtizen DNS 의 mx 값을 daum 에서 잘 읽지못하는 경우가 있었다. 그래서 일단 cloudflare 로 옮겼다.

domain 구입하기

일단 도메인은 webtizen(웹티즌)에서 구매했다.(수수료가 저렴하다.) 관련 내용은 See Also 1 을 참고하자.

cloudflare 에서 DNS 를 사용하려면 domain 이 있어야 한다. 그래서 먼저 도메인을 구매해야 한다.

cloudflare 가입하고 DNS 세팅하기

MX 값과 함께 SPF(or TXT) 를 같이 설정해 주자. 그래야 daum email 이 spam 으로 빠지는 것을 막아줄 수 있다. 자세한 내용은 See Also 1 을 참고하자.

SPF 설정


  1. 사용자 가이드 - NAVER CLOUD PLATFORM
  2. 도메인 및 SMTP 서버에 SPF 적용하기 (이론) - 미니브러리











웹티즌에서 DNS 설정하기




See Also

  1. 무료 기업 이메일 계정