포럼
서버→클라이언트 암호화 애드온 개발 실패 ㅠㅠ
2014.04.10 23:34
클라이언트→서버로의 폼 암호화 애드온을 개발에 성공해서, 서버→클라이언트로의 암호화 전송 애드온을 만들려고 했습니다.
간단한 아이디어는 다음과 같습니다.
1. 서버에서는 addon에서 최종출력전($called_position == 'before_display_content) 에 본문 내용($output) 변수를 전부 가로채서 php상에서 자체적으로 gzip(deflate)후 AES로 encrypt합니다. 그리고 Base64로 인코딩한 뒤에 자바스크립트 변수로 클라이언트에 쏴줍니다. (php상에서 자체적으로 gzip하는 이유는 불필요하게 낭비되는 공간을 잡아주기 위함입니다. 약 70%정도의 공간을 잡아줄수 있더군요. 게다가 암호화 하는 양 자체가 줄어들어서 모바일에서 암호를 빠르게 풀기 위해서는 이 방법이 필수라고 생각합니다.)
2. 클라이언트에서는 document가 로딩되자 마자, javascript 변수로 받은 본문내용을 AES로 decrypt합니다. 그리고 다시 Gzip으로 풀어준뒤에 utf-8형태로 변환하여 복원해 줍니다. 그리고 자바스크립트로 복원한 내용을 <body>태그 또는 자체 커스텸 태그(<ENCRYPTED>) 안에 몽땅 다 집어넣습니다...
(키 교환 과정은 생략합니다. 궁금하시면 댓글달아주시면 설명해 드릴게요.)
그러나 결론적으로 보면 실패했네요. 일단 저렇게 하니 CSS가 하나도 먹히지 않더군요. 만약 저 방법을 쓰려면 CSS 도 같이 암호화 하여 전송해야 할것(이런걸 동적로딩이라고 하나요?) 같네요. 그렇게 하려면 애드온에서 이것저것 할게 많아질것 같습니다. 그리고 가장 큰 문제로는 파이어폭스하고, 사파리에서는 저렇게 하면 CSS가 깨지긴 해도 본문 내용이 나와주는데, 크롬이나 IE에서는 보안문제(내부 정책?) 때문인지, 화면이 하나도 나오지 않더군요. 소스보기를 하면 태그는 정상적으로 출력이 되는데 제가 실력이 부족한건지 브라우저 차원에서 막아둔것지 잘 모르겠더군요.
P.S
참고사항 모바일에서 충분히 자바스크립트로 encrypt/decrypt 부하가 과도하게 가지 않는지 체크를 해 보았는데, 큰 무리가 가지 않았습니다. 암호해독 성능이 우려되어서 RC4, AES, Rabbit등을 체크해 보았는데 , RC4와 AES256 둘다 쓸만하며, RC4가 AES256보다 두배 정도 빠르더군요. 그러나 AES128을 이용한다면 RC4랑 동등한 속도를 제공해 줄것으로 생각하기에, 이왕이면 보안이 강한 AES 을 이용하면 좋을것 같습니다. AES256이 2배 정도 느려도 워낙 빨라서 체감하기는 조금 힘들것 같습니다.
rabbit algorithm도 이용해 보았는데, 속도가 AES 256과 큰 차이가 없었습니다. 오차범위내로 rabbit이 조금 빨랐네요. 그냥 AES가 킹왕짱 인듯 합니다. 결론적으로는 gzip을 한다면, AES256을 이용하여도 모바일에서도 충분히 암호화를 풀어 낼 수 있었습니다.
참고한 library는
zlib 을 javascript로 구현한것
https://github.com/imaya/zlib.js
함수명 : UTF8ArrToStr
여기서 solution2 입니다. uint8, 배열(위 zlib에서 사용되더군요ㅡㅡ)을 utf8로 바꿔주는 디코더
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
댓글 6
-
업글
2014.04.11 00:24
-
기진곰
2014.04.11 10:47
며칠 전 클라이언트→서버 암호화 애드온을 올리셨을 때
키교환 방식이 불안하다고 댓글 달았던 사람입니다.
이번에도 키교환 방식이 궁금하네요. 약속하신 대로 설명해 주세요^^
(만약 이쪽의 키교환 방식이 더 좋다면 클라이언트→서버 암호화에 사용되는 키도
같은 방식으로 한 번에 전달하면 어떨까 싶네요.)
-
AJKJ
2014.04.11 12:48
네 간단하게 소개해 볼게요. 아쉽게도, 저번이랑 키 교환 방식은 똑같아요. 역시 중간자 공격, 세션 스니핑에는 매우 취약할수밖에 없는것 같습니다.
댓글에 적어주신 대로 역시 키는 딱 한번만 쏘면 되겠지만, 이게특별히 보안상 더 좋은방식은 아닌것 같아요..
1. 서버에서 일괄적으로 클라이언트에 RSA public key를 javascript 변수로 내려줍니다.
(ajax로 상황에 따라 동적으로 로딩하는 방법도 있겠지요)
2. 클라이언트에서는 웹페이지가 로딩이 되자마자 100글자 정도의 Random text 를 만들고(이하 AES_KEY라고 합니다.) AES_KEY를 웹브라우저의 웹스토리지(세션스토리지)에 저장합니다. (저는 이것을 이번에 찾아보면서 알게 되었어요)
http://www.w3schools.com/html/html5_webstorage.asp
http://caniuse.com/namevalue-storage
3. 클라이언트에서 RSA_public key로 AES_KEY를 암호화 합니다.
4. RSA 암호화된 AES_KEY는 ajax post 방식으로 서버에 사전에 전송하거나, 로그인 폼을 전송할때 같이 전송합니다.(단 로그인 폼을 전송할때 전송한다면 로그인 전까지는 서버→클라이언트 구간에서 비암호화 통신을 하겠지요)
또한 앞으로 클라이언트에 폼을 전송할때는 세션스토리지에 저장된 AES_KEY를 이용하여 폼을 AES로 암호화 합니다.
5. 서버에서는 암호화된 AES_KEY를 서버가 가진 RSA_Private_Key로 풀어줍니다. 그리고 사용자의 세션에 저장합니다.
6. 서버에서는 클라이언트에서 데이터를 내보내기 전에 데이터를 AES로 암호화 합니다. 이때 사용되는 password는 세션에 저장된 AES_Key입니다.
나중에 천천히 이 방법이 아닌 다른방법을 시도해봐야 겠어요.ㅠㅠ 암튼 생각처럼 매우 간편하게 될것 같지는 않네요.ㅠㅠ
(다른방법 예상: HTML tag 구조는 그대로 내보내고 text, html 일부 tag 속성(input tag value) 등 주요 개인정보를 암호화한다. 그리고, javascript로 풀어줍니다.)
-
기진곰
2014.04.11 15:10
웹스토리지는 재미있는 아이디어네요.
만약 집에 있는 광랜으로 접속하면서 AES_KEY를 생성해 웹스토리지에 넣어두었다면, 나중에 그 컴퓨터를 가지고 커피숍에 가서 와이파이를 쓰더라도 AES_KEY는 이미 컴퓨터에 저장되어 있으므로 키를 다시 생성하여 전송할 필요가 없겠지요. 따라서 공격자가 가로챌 기회도 많이 줄어드는 거지요?
-
AJKJ
2014.04.11 18:04
AES_KEY는 웹스토리중에서 로컬스토리지가 아닌 세션스토리지에 넣어두는게 좋지 않을까 생각합니다. 키는 한번만 쓰고 버리는게 안전하다고 생각해요. 또한 로컬에 저장해 둔다 해도, 서버에서 세션이 끊나면 클라이언트에 저장된 키를 모르기에 로컬스토리지에 저정해둘 필요가 없지 않을까 생각해요. 그리고 저도 아직 웹스토리지를 안써봐서 자세히는 모르겠어요. 사용하기전에 가능한지 데모를 만들어 보고하고 있었는데, 그 이전에 더 중요한 부분에서 막혀서요.ㅠㅠ
그리고 사실 저는 RSA 나 AES로 암호화 됬으면 암호화 된게 얼마나 노출되는 큰 문제가 아니라고 생각해요. 일단 암호화를 풀어내는 정도가 거의 불가능에 가깝고, 만약 그것을 풀어낼 정도로 절박한 해커라면, 암호문은 crack하는 방법이 아닌 다른 방법을 사용해서 충분히 공격할거라고 생각해요.
-
기진곰
2014.04.14 10:14
네, RSA나 AES를 뚫으려고 시도하는 무대뽀 해커는 드물겠지요.
정말 뚫고 싶다면 처음에 키를 가로채는 것이 훨씬 편할 텐데 말이죠 ㅋㅋ
암호화는 공부한적이 없어서 그런지 어렵게 느껴지는군요 ㄷㄷ;;
멋지십니다..