Common Lisp에서 패키지 다시 컴파일하기.

Language/Common LISP 2011. 10. 14. 11:58 Posted by 알 수 없는 사용자
아. 리스프는 정말 쉽지가 않다. 언어 자체는 너무 마음에 들지만 패키지를 사용하는 것에서 상당히 혼란스럽다. 리스프의 패키지 시스템이 나빠서라고 말하기는 힘들다. ASDF라는 좋은 시스템을 가지고 있다.

단, 문제가 되는 것처럼 보이는 건 common lisp에 대한 구현이 많다는 점이다. Lispworks, Allego CL, SBCL, CLISP, CMUCL 등등. 이들은 물론 표준을 따르고 있지만 모든 구현들이 동일하게 동작하지는 않는다. 그럴 수도 없다. 구현물마다 다른 추가 구현도 가지고 있기도 하고. 이 때문에 다른 사람의 코드를 받아서 사용하려하면 오류가 발생하는 경우가 꽤 있다. 해커들에게는 또 하나의 즐거움일 수도 있지만, 입문자인 나에겐 참 힘든 일이다.

Perl, Python 등의 알려진 언어들은 보통 가장 널리 사용되는 하나의 구현을 가지고 있다. 또한 패키지 관리 시스템도 가지고 있으니 이런 점에서는 매우 편리하다. 괜히 이런 언어들이 많이 사용되는 것이 아니라는 것을 다시 한 번 느꼈다. 많이 사용되니 그만큼 잘 되어 있는 것일 수도 있겠지만.

서론이 길었다. 오늘 여기에 남기려고 하는 팁은 패키지를 다시 컴파일 하는 방법이다. 이걸 찾아보게 된 이유는 bordeaux-threads라는 패키지 때문이다. (이름도 어렵다. 사실 '보르도'라는 지명이야 잘 알고 있지만 불어다보니 참 단어의 철자가 안 외워진다.) 이 패키지를 컴파일 하고 잘 사용하고 있었는데, 무슨 문제가 있었는지, 다른 패키지가 이 패키지를 건드린 것인지, 갑자기 함수 하나가 동작하지 않았다. bordeaux-threads:make-thread 라는 함수이다. 이 함수가 갑자기 undefined라는 것이다. 정의되어 있다고 search는 되는데 실행하면 없는 함수라니.

이 함수를 로드하면 이미 컴파일이 되어 있기 때문에 컴파일된 fasl을 로드하게 되고 문제는 반복되었다. 그렇다면 다시 컴파일 하면 해결되지 않을까 생각했다. 방법은 다음과 같다.
(asdf:operate 'asdf:load-op 'bordeaux-threads :force t)
ASDF를 이용해서 피키지를 로드하는 코드와 거의 같은 코드다. :force라는 키워드를 추가하는 것 뿐이다. 이렇게 하면 처음 패키지를 가져올 때 하는 것처럼 컴파일을 다시 하게 된다.

우분투에서 리스프 패키지 직접 설치하기

Language/Common LISP 2011. 10. 14. 11:54 Posted by 알 수 없는 사용자
이 글이 쓰여지는 현재의 환경은 SBCL, 우분투 10.04이다.

우분투의 시넵틱 패키지 관리자를 이용하면 slime이나 emacs, sbcl 등을 쉽게 설치할 수 있다. cmucl은 현재 - 왜 그러한지 모르겠지만 - 존재하지 않지만 clisp도 제공하고 있다.

우분투의 패키지 관리 시스템에서 common-lisp 관련 라이브러리들은 cl- 로 시작된다. 예를 들면 cl-md5와 같은 패키지가 있으며 이를 설치하면 /usr/share/common-lisp/ 하에 설치되어 활용할 수 있게 된다. 여기에 설치되는 패키지들은 모두 common-lisp-controller가 관리하는데, sbcl을 설치하면 자동으로 이 패키지가 설치될 것이다. 이 패키지의 기능은 어떤 lisp implementation을 사용하든 상관없이 라이브러리를 활용할 수 있도록 하기 위함이다.

sbcl에서는 (require 'package-name)을 하면 사용할 수 있고 clisp와 같은 경우에는 (clc:clc-require 'package-name)을 사용하면 된다. sbcl은 아마 clc-require를 기본으로 hook하고 있는 듯 하다.

문제는 우분투에서 모든 lisp 관련 패키지를 제공하지 않는다는 것에 있다. 누군가가 패키지를 만들어주기를 하릴없이 기다릴 수는 없는 법. 직접 패키지를 다운 받아 설치하는 수밖에. 예를 들면 cl-fad나 hunchentoot와 같은 패키지는 제공되지 않는다.

조금 의외인 것은 직접 설치하는, 이 과정이 생각외로 매우 간단하다는 것이다. SBCL을 사용하기 때문인지는 잘 모르겠으나 아직까지 동작하지 않는 패키지를 만나지 못했다. 이렇게 간단히 문제가 해결되는 이유는 이전에도 이야기한 바 있는 ASDF라는 시스템 때문이다. 대부분의 리스프 라이브러리가 ASDF를 지원하고 있기 때문에 이를 이용하면 쉽게 사용할 수 있게 된다.

방법은
  1. 필요한 라이브러리를 다운로드 한다. 대부분은 .tar.gz으로 묶여있지만 가끔은 cvs로 제공하거나 git을 사용하기도 한다. 어떤 경로든 무관하며 다운로드한 소스코드를 내가 두고 싶은 어느 디렉토리든 두면 된다. 내 경우에는 ~/asdf/ 에 모든 라이브러리 소스코드를 둔다.
  2. 홈 디렉토리에 .clc나 .sbcl이라는 디렉토리를 만든다. clc는 앞서 말한 common-lisp-controller의 약자다. 가능하면 .clc로 만드는 것이 좋을 듯 하다. 그러면 다른 lisp implementation에서도 사용할 수 있기 때문이다.
  3. (.clc로 만들었다고 가정하고) .clc내에 systems라는 디렉토리를 하나 만든다. 결론적으로 ~/.clc/systems/ 를 만드는 것. .sbcl을 만들어도 동일하다. systems라는 디렉토리를 그 안에 만든다.
  4. 이 systems/ 디렉토리 안에서 다운로드한 소스코드 중 한 파일로 심볼릭 링크를 건다. 링크를 걸 파일은 아까 풀어둔 소스코드의 .asd 파일이다. 사실 1번 과정에서 .asd 파일이 있는지 확인하는 것이 좋지만 대부분의 패키지는 .asd를 패키지 이름으로 만들어 두었기 때문에 꼭 확인하지 않아도 된다. 내 경우라면 md5 패키지를 다운로드 했을 경우, ln -s ~/asdf/md5-1.8.5/md5.asd 라고 하면 된다.
  5. 그러면 systems/ 내에 md5.asd 라는 심볼릭 링크가 생겼을 것이다. 이러면 설치가 완료된 것이다. 어떠한 컴파일 작업이나 다른 것이 필요없다. 압축을 풀고, 심볼릭 링크를 걸면 끝이다. 후에 패키지를 제거하고 싶으면 다운 받았던 패키지 디렉토리를 지워버리고 systems/ 에서 심볼릭 링크를 제거하면 된다.
  6. sbcl이 실행된 상태에서 (require 'md5) 라고 하면 첫 로드시에 알아서 패키지를 컴파일 한다. 다음부터는 컴파일 없이 바로 로드된다.
이와 같은 방법으로 어떤 패키지든 쉽게 사용할 수 있다.

clsql을 통해 sqlite3 DB 이용하기

Language/Common LISP 2011. 10. 14. 11:49 Posted by 알 수 없는 사용자
Common Lisp를 이용해서 DB 접속을 하기에 아주 좋은 패키지가 있다. CLSQL이다.

CLSQL을 다운받아 압축을 풀어보면 많은 수의 asd파일이 있음을 알 수 있다. clsql.asd, clsql-uffi.asd는 기본으로 심볼릭 링크를 걸고, 자신이 사용하고자 하는 데이터베이스에 해당되는 asd 파일을 링크걸면 된다.

db2, mysql, odbc, oracle, postgresql, sqlite 등 널리 사용되는 DB는 거의 지원한다. 이 글에서는 sqlite v3를 이용하는 방법을 살펴본다.
(require 'clsql-sqlite3)
명령어를 입력하여 패키지를 로드한다. 문제없이 로드가 되어야 CLSQL을 이용할 수 있다. asdf를 이용해서 로드할 경우에는
(asdf:oos 'asdf:load-op 'clsql-sqlite3)
로 로드할 수 있다.

sqlite3를 이용해서 우선 테스트할 테이블을 하나 만들어보자. 도시들의 온도를 저장하는 간단한 것.
j0nguk@netbook:~$ sqlite3 tem.db
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table cities (id integer primary key, name text, temp real);
sqlite> .tables
cities
sqlite> insert into cities values (null, "seoul", 25.8);
sqlite> insert into cities values (null, "suwon", 26.3);
sqlite> insert into cities values (null, "busan", 23.7);
sqlite> select * from cities;
1|seoul|25.8
2|suwon|26.3
3|busan|23.7
sqlite>
테스트할 데이터베이스를 만들었으니 리스프에서 접근해보자.
CL-USER> (clsql:connect '("/home/j0nguk/tem.db") :database-type :sqlite3)
#<CLSQL-SQLITE3:SQLITE3-DATABASE /home/j0nguk/tem.db OPEN {C5464B9}>
connect 함수는 이름 그대로 데이터베이스에 연결하는 함수다. tem.db라는 파일을 이용해서 sqlite3 DB를 만들었으니 경로를 정확히 지정해준다. 그리고 DB type이 sqlite3라는 것도 명시해준다. 오류없이 위와 유사한 결과가 나오면 연결이 된 것이다.
CL-USER> (clsql:query "select * from cities")
((1 "seoul" 25.8d0) (2 "suwon" 26.3d0) (3 "busan" 23.7d0))
("id" "name" "temp")
바로 쿼리를 보내보자. query라는 함수를 이용하면 된다. 결과는 리스프답게 리스트로 돌아온다. 첫 번째 리턴값은 쿼리에 대한 결과이고 두 번째 리턴값은 column의 이름이다.
CL-USER> (clsql:print-query "select * from cities")
1 seoul 25.8
2 suwon 26.3
3 busan 23.7
; No value
리스트로 돌아오지 않고 스트링으로 보고 싶을 때는 print-query라는 함수를 이용하면 된다.
CL-USER> (clsql:select '* :from 'cities)
((1 "seoul" 25.8d0) (2 "suwon" 26.3d0) (3 "busan" 23.7d0))
("id" "name" "temp")
query 함수는 스트링을 매개변수로 받기 때문에 변수를 쿼리에 이용하거나 할 때는 조금 불편하다. 이때는 select 함수를 이용하면 된다. select외에 SQL 명령어들을 다양한 함수로 지원한다.
CL-USER> (clsql:query "insert into cities values (null, 'daegu', 29.4)")
NIL
NIL
CL-USER> (clsql:select '* :from 'cities)
((1 "seoul" 25.8d0) (2 "suwon" 26.3d0) (3 "busan" 23.7d0) (4 "daegu" 29.4d0))
("id" "name" "temp")
insert 쿼리도 잘 적용되는 것을 볼 수 있다. insert가 실제로 잘 적용되었는지 sqlite3 인터페이스를 통해 확인해보자.
j0nguk@netbook:~$ sqlite3 tem.db
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from cities;
1|seoul|25.8
2|suwon|26.3
3|busan|23.7
4|daegu|29.4
sqlite>
모든 작업이 끝나면 disconnect 함수로 접속을 끊을 수 있다. 연결된 데이터베이스를 확인하는 함수는 connected-databases이다. 연결이 끊어졌기 때문에 NIL이 리턴되는 것을 알 수 있다.
CL-USER> (clsql:disconnect)
T
CL-USER> (clsql:connected-databases)
NIL

Ubuntu, Android, and Galaxy S

Android 2011. 10. 14. 11:42 Posted by 알 수 없는 사용자
우선 환경설정 -> 응용프로그램 -> 개발에 가서 "USB 디버깅"이 체크되어 있는지 본다. 설정을 바꾸지 않았다면 기본값이 체크다.

연결 후에 adb devices를 해보면 다음과 같이 나온다. 갤럭시 S를 우분투가 인식하긴 했으나 어떤 디바이스인지 잘 모르고 있다.
$ adb devices
List of devices attached
????????????    no permissions
/etc/udev/rules.d/51-android.rules 파일을 만든다. 당연히 root 권한으로 해야 한다.
$ sudo emacs /etc/udev/rules.d/51-android.rules
이 파일에 넣어야 할 내용은 다음과 같다.
SUBSYSTEM=="usb", SYSFS{idVendor}=="04e8", MODE="0666"
갤럭시S가 컴퓨터와 연결되어 있었다면 뽑은 후에 다시 연결하자. 다시 adb를 통해 확인하면 잘 인식됨을 볼 수 있다.
$ adb devices
List of devices attached
M110d3d33415    device

물건 분실을 파악하는 좋은 방법?

Security 2011. 10. 14. 11:37 Posted by 알 수 없는 사용자
지난 글에서 사물에 RFID tag를 부착하고 그것들을 coupling해서 함께 다녀야 하는 물건들 중에 무언가가 누락되거나 내것이 아닌 물건이 내게 딸려오는 등의 사고를 막는 이야기를 했었다. 지난 글의 저자들이 조금 더 예전에 다른 제목의 논문을 또 낸 것을 확인하고 읽어보았는데, 내용상 거의 차이는 없었다. 논문 제목은
    Ubi-Check - A Pervasive Integrity Checking System
    Michel Banatre, et al.
    INRIA Rennes / IRISA
이들의 연구를 보면 아이디어는 단순하지만 실제 구현을 직접 해봤다는 점에서 의미가 있어 보인다.

모든 태그를 빠르고 정확하게 인식시키는 것이 상당히 어렵다고 한다. 여러 명의 사람이 문을 통과할 경우 사람들이 지니고 있는 물건에 붙어 있는 모든 태그를 동시에 읽는 것이 만만치 않은 모양이다. 논문에서는 한 명씩 통과하는 것을 권고하고 있고, 사람이 들어오기 시작한 후 다음 사람이 들어오기까지 2초 ~ 3초의 간격이 있으면 좋다고 말한다.

인식률을 높이는 것이 결국 어렵다는 결론이 나온다면, 문을 회전문 방식으로 만들고 한 명씩 들어가게 하는 것도 방법일 듯 하다. 회전문은 개별 공간이 나름 밀폐된 공간이므로 reader를 여러 군데에 부착하기도 좋을 것 같고, 특수한 재질로 설계한다면 칸마다 Faraday cage와 같은 효과를 낼 수도 있지 않을까 생각이 든다.

회전문이 아니면 어떨까. 일반적인 건물의 문이라면 여러 사람에 동시에 들어올 것이다. 사람마다 미리 coupling된 물건들을 가지고 있을 것이므로 사물이 어떻게 grouping되었는지는 coupled signature (group의 ID를 hash하여 얻는 값)을 보면 될 것이다. 같은 그룹은 같은 signature를 가지고 있을 것이니까. 하긴, 문제는 인식률이라고 하니까.

또 하나 생각해볼 수 있는 것은 문을 통과할 때 이 coupled signature가 틀리는 경우다.
  1. 내가 1개 이상의 내 물건을 어딘가 다른 곳에 두고 문을 지나는 경우
  2. 내가 1개 이상의 타인 물건을 지니고 문을 지나는 경우
  3. 내가 1개 이상의 내 물건을 빠뜨리고 1개 이상의 타인 물건을 지니고 문을 지나는 경우
정도로 구분해볼 수 있겠다. 3번과 같은 케이스는 논문에서 언급이 되지 않고 있는데 내 카메라와 다른 사람 카메라가 똑같아서 내 것인줄 알고 가지고 가는 경우를 생각해볼 수 있다. 의외로 빈번히 발생할 수 있다고 본다.

각 케이스에 대해 정확히 판단을 내려줄 수 있는 방법은 없을까? 논문에서는 특정 디바이스에 전체 그룹의 구성원 수를 기록해둬서 그것을 이용해 판단한다는 이야기가 있다. 예를 들어 내가 지니고 있는 물건이 5개인데, 문을 나갈 때 6개의 사물이 인식이 되면 2번의 케이스라고 판단하고, 3개의 사물이 인식되면 1번의 케이스라고 판단한다는 것이다. 그러나 이것은 3번 케이스를 전혀 고려하지 않은 이야기다. 즉, 논문은 각 케이스를 구분하는 방법을 정확히 제시하지 못하고 있다. 전체 ID를 모아서 해시한 값을 모든 태그나 나눠서 가지기 때문에 당연한 결과인데, Bloom filter 등의 기법을 도입하여 다른 그룹 멤버에 대한 정보도 일부 가질 필요가 있다고 본다. 물론 각 케이스를 구분해야 하는 상황에서만. 구분할 필요 없이 이상이 있다 없다만으로 충분하다면 논문이 제시하는 이야기로도 충분히 해결이 된다.

논문을 보니 이것을 실제로 구현해서 전시회도 했다고 하는데, 이렇게 직접 구현하고 실험하고 하는 모습이 상당히 좋아보인다. 물론 귀찮겠지만 :p

'Security' 카테고리의 다른 글

NFC의 장단점?  (0) 2011.10.14
NFC 어플리케이션  (0) 2011.10.14
RFID Tag Coupling  (0) 2011.10.14
가장 비싼 1바이트의 실수  (0) 2011.10.14
HSTS: HTTP Strict Transport Security  (0) 2011.10.14

RFID Tag Coupling

Security 2011. 10. 14. 11:33 Posted by 알 수 없는 사용자
다음 논문을 읽고 감상을 남긴다.
Pervasive Integrity Checking With Coupled Objects
Paul Couderc, et al.
INRIA Rennes, Compus Universitaire de Beaulieu, FRANCE
이번에 ANT 2011이라는 학회에 운 좋게 참석하게 되었다. 캐나다의 나이아가라 폴스에서 개최되는 학회라 나이아가라 폭포까지 감상할 수 있었다. 정말 운도 좋다. 심지어 학회장이 폭포가 보이는 거리에서 100미터 정도밖에 떨어지지 않은 거리.

이 학회에서 위 논문의 발표를 들을 수 있었는데, 들었던 발표중 가장 기억에 남는 아이디어라 한국에 도착해서 프로시딩 CD를 뜯고 가장 먼저 읽어보게 되었다. 이 논문에서 이야기하는 주 아이디어는 RFID tag coupling이다. RFID tag에는 고유한 아이디가 있을 것이다. RFID가 막 뜨기 시작할 때 많이 언급된 어플리케이션으로 물류가 있었는데, 모든 아이템에 태그가 붙어 있으면, 리더가 원거리에서도 사물을 읽을 수 있으므로, 태그마다 고유 아이디를 가지고 있다면 해당 물품을 정확히 인식할 수 있다는 것이었다. 태그에 아이디는 MIT에서 제안한 Auto-ID 같은 것을 쓸 수 있겠다. 이 논문에서는 EPC ID라는 것을 언급했는데 96 bits라고 한다.

논문에서는 개별 사물의 인식이 아닌 그룹 구성원에 대한 인식에 초점을 맞춘다. 그룹 구성원의 변동이 없어야 하는 상황에 대해 언급하고 있는데 생각외로 이렇게 시각을 바꿈으로써 적용해볼 수 있는 어플리케이션이 많아지더라.
  • 유치원 선생님이 박물관에 아이들을 데려갔다고 하자. 30~40명 정도를 데리고 다녀야 하는 경우 한 두 명이 이탈하는 것을 파악하는 것이 쉽지 않다. 아이들에게 태그를 모두 부착해두면 어떨까? 선생님이 쉽게 이탈자 여부를 파악할 수 있지 않을까?
  • 식당과 같은 곳에 갔을 때 내가 가지고 들어갔던 사물들(핸드폰, 가방, 노트북, 지갑 등)을 식당 입구에서 체크해둔다. 내가 식당을 빠져나갈 때 '물건을 두고 나오셨습니다!'라고 알려줄 수 있다면 좋지 않을까? 식당보다 택시를 예로 든다면 더 좋겠다. 택시에 뭔가 떨어뜨리고 나오는 것은 생각만해도 아찔하지 않은가!
요즘 NFC가 사물 인식에 대세로 떠오르고 있지만 이 경우에는 RFID가 더 편할 듯하다. 사용자가 특별히 인식하지 않고도 서비스를 받을 수 있어야 하니까.

여기까지 이야기를 들으면 서비스 제공자가 사용자가 가지고 있는 태그들을 특정 시점에 모두 스캔하여 보관하고 있다가 후에 체크하는 방식을 취하면 되겠다고 생각할 수 있다. 예를 들어 내가 식당에 A, B, C, 세 가지 물건을 가지고 들어갔다면 식당은 이 정보를 보관하고 있다가 후에 나갈 때 A, B, C가 함께 나가는지 체크해주면 된다. 하지만 여기서 문제는 A, B, C가 그룹을 형성하고 있다는 것을 어떻게 알 수 있는가 하는 것이다. 식당에 들어올 때 한 명씩 시간 간격을 두고 들어와준다면 (나갈 때도 마찬가지) 구현 가능할 듯 하지만 불편함은 있다.

이 논문은 조금 다른 방식으로 접근한다. 그룹을 맺어야 하는 사물들이 미리 그룹을 형성한다. A, B, C, 세 가지 사물은 당연히 각자 자신들의 아이디를 가지고 있을 것이다. 여기에 더해서, 자신을 제외한 그룹 멤버들의 정보 또한 가지고 있자는 것이다. 즉, A의 경우 B와 C의 아이디를 저장하고 있으면 된다. 그런데 RFID의 메모리는 넉넉하지 않다. 일반적으로 512 bits 정도라고 하는데 아까 말했듯 식별 아이디 자체가 96 bits 정도이니 그룹 구성원의 수가 대여섯개가 넘어가기 시작하면 이 방식은 구현이 불가능하다. 영어 좀 쓰면 scalability 측면에서 좋지 못하다.

그래서 제안하는 방법은 해시를 이용하는 것이다. SHA-256을 사용했다고 한다. 자신을 포함한 모든 구성원의 아이디를 이용해 해시값을 얻는다. 모든 그룹 구성원이 같은 값을 얻게 될 것이다. 이것을 태그에 모두 저장해둔다. 이렇게되면 space 문제는 해결할 수 있다. 모든 태그가 2 * [the length of ID] 만큼의 공간만 있으면 된다.

이 방식을 사용해도  점검자(예를 들면 식당이나 공항의 출입구)가 체크를 할 때 어떤 범위로 태그 집합을 인식하고 그것을 바탕으로 해시값 비교를 할 것인가는 여전히 어려운 문제다. A, B, C, 세 사물을 커플링해둔 상태에서 입구로 들어갔을 때, reader가 A, B만 인식했다면, 또는 타인의 사물인 D까지 포함해서 A, B, C, D, 네 개의 사물을 인식했다면 오류를 일으킬 것이기 때문이다. 이 문제에 대해 논문은 별다른 언급을 하진 않았지만, 후자의 경우는 D가 다른 해시값을 가지고 있을 것이니 쉽게 제외시킬 수도 있을 것으로 생각된다. 그러나 전자의 경우는 방법이 없다.

논문은 태그를 읽는 방식을 soft, hard로 나누어서 구현 시 이슈로 언급하고 있다. 소프트는 차례로 태그들을 읽어가는 것을 말하며 하드는 - inventory read라고 불리는 - 하드웨어적으로 한 번에 여려 태그를 인식하는 방식을 말한다. 인식률면에서는 소프트가 좋다고 한다. 인벤토리 리드는 태그의 수가 많을 때 전체를 인식하지 못하고 상당한 수의 태그를 놓치게 된다고 한다. 물론 인식 속도는 당연히 하드가 빠르다. 소프트는 순차적으로 모든 태그를 읽어야 하기 때문에 태그의 수에 비례하여 읽는 시간이 소요된다.

예전에 RFID tag에 대해 한참 이야기를 많이 할 때, 이를 이용하여 계산대에서 바로 계산되는 어플리케이션을 많이들 이야기 했었다. 카트를 전속력으로 밀고 계산대를 지나가버리면 몇 개 물품은 계산되지 않는 문제가 있다고 살짝은 농담 섞어 이야기들을 하곤 했는데, 아주 심각한 문제였다. 상용화가 되려면 이런 오류는 용납되지 않으니까. 이런 이야기를 한 것이 벌써 5~6년은 된 것 같은데 아직도 이 문제는 해결되지 않았나보다.

논문을 읽다 궁금했던 점은 태그가 가지는 ID가 copy(clone)되는 일은 없을까 하는 것이다. 태그의 아이디는 쉽게 얻을 수 있는 값이므로 복사하여 바꿔치기할 수도 있을 것 같다는 생각이 든다. 논문에서 이에 대한 언급은 없다.

또 하나 논문에서 언급한 것은 proxy fragment인데, 여기서 fragment는 커플링되는 개별 사물을 말한다. 프록시 프래그먼트는 실존하지 않는 사물에게도 아이디나 기타 다른 비트스트링을 부여하여 함께 해시값을 얻을 수 있다는 것이다. 예를들어, 자전거와 자전거 주인을 커플링할 수 있다. 누군가가 자전거 보관소에서 내 자전거를 훔쳐 자기 것인 듯 끌고 나갔을 때 자전거 보관소의 입구에서 내 자전거의 태그와 그 사람의 정보를 가지고 해시값 비교를 해볼 수 있다. 그 사람이 나인 척 impersonation에 성공하지 않는 이상 간단히 도둑질이 발각될 것이다.

아주 심플한 아이디어고 태그에 데이터를 저장하기 때문에 별도의 데이터베이스도 필요없다. 별도의 데이터베이스에 정보를 저장하지 않기 때문에 프라이버시 측면에서도 나쁘지 않은 디자인이다. 태그 인식률과 속도가 개선되고 태그값이 복사되거나 스푸핑되지 않도록 할 수 있다면 심플하면서도 상당히 쓸모가 많은 아이디어가 아닌가 생각된다.

가장 비싼 1바이트의 실수

Security 2011. 10. 14. 11:18 Posted by 알 수 없는 사용자
The Most Expensive One-byte Mistake라는 글을 읽었다. acmqueue에 실린 글이고 Poul-Henning Kamp가 쓴 글이다. Kamp씨는 FreeBSD 커뮤니티에서 활동하는 사람이라 괜히 정감이 간다. 각설하고.

글쓴이는 역사상 가장 큰 비용의 실수는 뭔가? 하는 질문을 던진다. IT와 CS의 역사에서 잘못된 선택으로 인해 고생했던 몇 가지 예를 서두에 언급하지만 결국 하고자 하는 이야기는 NUL-terminated text string이다.

텍스트 스트링은 상당히 자주 사용되는 자료형이다. 자바 프로그램에서 가장 많이 생성되는 객체는 String이라는 글을 읽은 적이 있다. 초기에 C를 만든 세 명은 스트링을 표현하기 위해 다음 두 가지의 선택사항을 가지고 있었다. 물론 현재에도 누군가가 언어를 설계한다면 둘 중에 하나를 선택해야 할 것이다.
  1. address + length
  2. address + magic_marker (NULL)
그들은 2번을 선택했다. 최적화라는 취지에서 2번이 좋아보였을 것이다. 길이를 저장하기 위한 별도의 공간을 마련하지 않아도 되니까.

의외로, 그 당시 많은 언어들이 1번을 채택하고 있었다고 한다. 2번을 택했던 언어는 어셈블리였다고. 앞서 언급한대로 1번은 길이를 매번 따로 저장해야 하니 비효율적일 것이다라는 느낌을 준다. 하지만 유리한 점도 있다. 데이터 복사나 이동을 할 때 대상 데이터의 크기를 즉시 알 수가 있다는 점. Cache를 활용할 때도 유리할 수 있다. 2번과 같이 매직 마커를 쓰면 마커를 찾아야 하는 비용이 높다. 크기를 미리 안다면 블록 단위의 복사를 바로 실행할 수가 있는데, 마커를 사용하면 마커를 우선 찾고 복사를 시작해야 한다. memcpy와 strcpy가 다를 수밖에 없는 이유가 되는 것이다. Constant string의 경우 컴파일러가 그 크기를 알고 있기 때문에 사용자가 strcpy를 요청해도 memcpy로 대체하여 스피드면에서 이득을 얻기도 한다고 한다.

앞서 언급한 효율의 문제를 떠나 보안의 입장에서 바라보자. 2번을 택한 것이 훗날 버퍼 오버플로우가 일어날 수 있는 여지를 주었다. 이것은 정말 큰 문제고, 저자가 이 글을 쓴 이유다. gets()의 절망적인 보안 수준은 다들 공감할 것이다.

하지만 C를 만든 Ken, Dennis, Brian을 마냥 욕할 수는 없다. 그들이 C를 만들고 15년이 지나서야 사람들은 이게 보안적인 측면에서 나쁘다는 걸 알았다고 한다. 그러니 잘못된 선택을 했다고 비난하기는 힘들지 않은가.

현재 C로 직접 프로그래밍하는 사람이 예전만큼 많지는 않다. 그러나 대부분의 언어가 C로 구현되어있다. 다른 언어로 프로그래밍을 해도 결국엔 libc가 호출되고 여전히 NUL-terminated string은 쓰인다.

그럼 이제와서라도 2번을 버리고 1번을 선택해볼 것인가? 지금까지 만들어둔 프로그램이 아깝기 때문에, 당장 모든 대체 프로그램을 만들 수가 없기 때문에 바꿀 수는 없을 것이다. 이미 만들어진 프로그램의 수보다 앞으로 만들어질 프로그램의 수가 훨씬 많음에도 바꿀 수가 없는 것이다.

ps. 처음 이 글을 쓸 때는 살아있던 Dennis가 티스토리로 글을 옮기는 현재 세상에 있지 않다. 고인의 명복을 빈다.

'Security' 카테고리의 다른 글

물건 분실을 파악하는 좋은 방법?  (0) 2011.10.14
RFID Tag Coupling  (0) 2011.10.14
HSTS: HTTP Strict Transport Security  (0) 2011.10.14
DigiNotar의 구라 인증서에 대한 대처  (0) 2011.10.14
가짜 구글 인증서  (0) 2011.10.13

내가 프레임워크를 싫어하는 이유

번역 2011. 10. 14. 11:09 Posted by 알 수 없는 사용자
글이 너무 재밌어서 번역해본다. 너무 심각하게 읽을 필요는 없다. 이 글을 쓴 사람도 프레임워크에 대한 비난을 하기 보단 개천을 건너기 위해 배를 건조하는 일은 없도록 하자는 정도로 이렇게 표현했다고 본다. 즐거운 유머로 받아들이면 될 듯. 글 중간중간에 역주를 달고 싶은 유혹이 무척 많았지만 오히려 글을 망치는 것 같아 관뒀다. 그리고 영어를 읽을 수 있다면 가급적 원문을 읽으시길 권한다. 자연스럽게 읽히도록 하다 보니 직역을 하진 않았다. 번역문 시작!

제목: 내가 프레임워크를 싫어하는 이유

요즘 자바 웹 어플리케이션을 만들어보려고 계획하는 중이다. (어쩔 수 없다. 자바여야 한다. 여러가지 이유가 있는데 지금 설명하고 싶진 않다) 여튼 만들려고 하다보니, J2EE 포틀릿이 가능하고 JSR을 준수하는 MVC 롤 기반의 CMS 웹 서비스 어플리케이션 컨테이너 프레임워크를 몇 개 살펴보게 되었다.

각 프레임워크에 대한 문서를 수십시간 읽고났더니 눈이 빠지려 한다.

양념통 선반을 만들기로 했다고 상상해보자.

예전에 몇 번 비슷한 걸 나무로 만들어봐서 나름대로는 뭐가 필요한지 잘 알고 있다. 나무와 몇 가지 기본적인 도구가 있으면 된다. 줄자, 톱, 평평한 작업대, 망치 정도?

내가 만약에 양념통 선반이 아니라 집을 짓고 싶었다고 해도 여전히 자, 톱, 작업대, 망치는 필요하겠지.

어쨌든 도구를 사러 상점에 갔다. 점원에게 망치는 어디 있나 물어봤다.

점원이 대답한다. "망치요? 요즘에 아무도 망치 안 사요. 완전 유행 지났는데."

좀 놀랬다. 왜 그런지 물어봤다.

"흠, 망치의 문제는 말이죠, 종류가 너무 많다는 거죠. 큰 망치, 장도리, 볼핀 해머, ... 이런 거 중에 하나만 사셨다가 나중에 다른 게 또 필요하시면 어떡해요. 그럼 또 사셔야 되잖아요. 그래서 우리는 이런 생각을 했어요. 살면서 망치질 할 일이 있을 때, 어떤 경우에도 쓸 수 있는 망치를 사람들이 정말로 원하겠구나 하고요."

"흐음. 뭐, 맞는 말인 거 같네요. 그럼 그 만능 망치는 어디 있어요?"

"없어요. 더 이상 안 팔아요. 그것도 옛날 이야기죠."

"네? 좀 전에 만능 망치가 대세가 될 거라고 하지 않았어요?"

"만능 망치를 만들어보니 오히려 어디에도 별 쓸모 없다는 걸 알게 됐어요. 못 박는데 커다란 망치를 쓰면 불편하잖아요. 그리고 옛날 여자친구를 죽이고 싶으면 볼핀 해머만한게 없기도 하고요."

"그건 그렇네요. 그래서, 이제 아무도 만능 망치를 안 사고, 상점에서는 옛날 스타일의 망치를 안 파시고. 그럼 어떤 망치를 파세요?"

"사실, 이제 우린 전혀 망치를 팔지 않습니다."

"그러면..."

"우리가 연구를 좀 해봤는데요, 사람들이 원하는 건 만능 망치 같은 게 아니었어요. 일을 할 때 그 일에 딱 맞는 망치를 쓰는 게 중요하죠. 그래서 우리는 망치 공장을 팔기 시작했어요. 어떤 망치든 만들 수 있는 공장이요. 망치 공장에서 일할 사람 구하시고 재료 좀 사신 다음에 기계 돌리면 아주 빠르게 정확히 원하는 망치를 만드실 수 있죠."

"저 그런데 전 정말로 망치 공장을 사고 싶은 생각은 안 드는데요."

"네네. 사실 그것도 더 이상 안 팔아요."

"저기 근데 좀 전에..."

"대부분의 사람들이 말이죠, 공장을 통째로 사는 걸 별로 원하지 않는다는 걸 알게 됐거든요. 볼핀 해머가 전혀 필요 없는 사람이 있을 수도 있으니까요. 뭐 헤어진 여친이 없다거나 볼핀 해머 대신에 송곳으로 죽였거나 뭐 그런 사람들이요. 그래서 포인트는, 모든 망치를 다 만들 수 있는 망치 공장을 사는 사람은 없더라 이거죠."

"네. 말되네요."

"그래서, 대신에 공장을 만들 수 있는 설계도를 팔기 시작했어요. 고객들이 직접 망치 공장을 만들 수 있게 해주는 거죠. 원하는 망치들만 정확히 만들어 낼 수 있는 망치 공장을 만들 수 있지요."

"내 생각엔, 그것도 이제 안 파시죠?"

"네. 당연히 안 팔죠. 망치 몇 개 만들자고 공장을 짓는 걸 별로 원하지 않는다는 걸 알게 됐거든요. 공장을 만드는 건 공장 짓는 전문가들이 해야죠."

"맞는 말씀입니다."

"네. 그래서 설계도 파는 건 그만두고 망치 공장을 만드는 공장을 팔기 시작했어요. 망치 공장 공장으로 부를게요. 이 망치 공장 공장은 일반인들을 위해서 최정상급 전문가들이 만들었어요. 그러니 공장 내부에 대해서는 전혀 신경 쓰실 필요가 없죠. 그러면서도 사용자의 취향에 딱 맞는 망치 공장을 만들어낼 수가 있죠. 사용자가 필요한 대로 망치를 설계한 다음에 대량 생산할 수도 있어요."

"어, 글쎄요, 그건 그다지..."

"그렇게 말할 줄 알았어요!! 그것도 역시 지금은 안 팔아요. 몇 가지 이유로, 망치 공장 공장을 사는 사람도 별로 없더라고요. 그래서 이 문제를 해결하기 위한 새로운 해결책을 생각해냈죠."

"아하."

"사람들이 망치 공장 공장과 거기서 만들어진 망치 공장을 관리하고 가동하는 부분에서 많이 좌절하더라고요. 확실히 그런 작업이 좀 부담스럽긴 하죠. 그리고 다른 공구들도 생각해봤을 때, 줄자 공장 공장, 톱 공장 공장, 선반 공장 공장 같은 거 더 모두 작동하려면 좀 힘들긴 하잖아요? 그냥 양념통 선반이나 만들려고 했던 사람한테는 확실히 복잡한 과정이긴 하죠."

"네. 정말 그렇네요."

"그래서 이번 주에 우리가 신제품을 하나 내놨어요. 범용 공구 제작 공장 공장 공장인데요, 사람들이 필요로 하는 어떤 공구 공장 공장이라도 이 하나의 통합된 공장에서 만들 수 있어요. 이 공장 공장 공장은요, 딱 필요로 하는 도구에 대한 공장 공장만을 만드실 수 있거든요. 그러면 이 공장 공장에다가 필요한 공구의 스펙을 넣어주면 그 공구를 만드는 공장이 짠 하고 만들어지는 거죠. 뭔가 만들려고 할 때 그것을 위한 딱 맞는 공구셋을 이 과정을 통해서 얻으실 수 있겠지요. 물론 정확한 설정 파일들을 세팅해주셔야 하긴 합니다만 버튼 한 번 누르시면 정확히 필요했던 망치, 정확히 필요했던 자를 얻으실 수 있는거죠."

"그래서 이제 망치는 전혀 안 파시는거에요? 하나도요?"

"네. 고품질의 양념통 선반을 만들고 싶으시면 싸구려 도구 상점에서 파는 조잡한 망치보다는 뭔가 세련된 도구가 확실히 필요하죠."

"어... 다른 사람들도 다 그래요? 다들 망치 필요할 때 범용 도구 제작 공장 공장 공장을 쓰고 있는거에요?"

"그럼요."

"흠, 알겠어요. 저도 그래야겠네요. 다들 그렇게 하고 있다면 저도 어떻게 하는지 배우는게 좋겠네요."

"잘 생각하셨어요!!"

"설명서도 같이 주시죠?"

- Benji Smith, 2005년 9월 30일 금요일.
Why Undergraduates Should Learn the Principles of Programming Languages라는 글을 읽었다. 왜 학부생들이 언어의 원리를 알아야 하는가? 하는 물음이다.

컴퓨터 공학을 배우러 왔다는 것은 컴퓨터를 잘 이해하려고 온 것이고 컴퓨터를 이해한 뒤에 해야할 일은 잘 써먹는 것이겠다. 그러니 공학이라고 부르는 것이고. 컴퓨터에게 일을 시켜먹으려면 정확히 어떻게 일해야 하는지 잘 설명해줘야하고 의도를 잘 전달하기 위해서 우리는 다양한 언어(language)를 사용한다.

글의 제목은 의문문을 선택했지만 결국 하고 싶은 말은 프로그래밍 언어의 원리를 알아야 한다는 주장이다. 어떤 것을 공부하는데 있어 그 원리를 아는 것은, 사실, 당연한 일이다. 저자가 제목을 이렇게 단 것은 다음과 같은 이유다.

요즘 세상은 하나의 언어만 잘 아는 것으로는 부족하다. 요즘이 아니라도 예전에도 그랬을 것이다. 단 한대의 서버로 동작하는 웹서버를 만들더라도 SQL로 database와 이야기하고 자바로 웹서비스를 짜고, 클라이언트를 위해 자바스크립트도 써야 하지 않나.

언어가 많으니 난잡하다. 궁극의 언어가 있으면 좋지 않을까? Ultimate programming language? 하지만, 그런 것이 존재할 일은 없을 것이다. 지금 주요 언어들은 각자 자기의 영역을 확고히 하면서 생존하고 있다. 리눅스를 설치해보면 느낄 수 있다. Perl, Ruby, Python, ... 내가 설치하라 명령하지 않아도 기본적으로 패키지에 포함된다. 운영체제 설치 시 기본으로 포함되어 있는 필수 프로그램들이 저마다 다른 언어로 작성되어 있기 때문이다. 언어들은 살아남기 위해 치열하게 경쟁하고 있기도 하다. 옛날처럼 서버 스크립트가 몽땅 Perl로 짜여지고 있지 않다. (FreeBSD는 오래 전에 운영체제의 필수 스크립트를 Perl에서 shell script로 교체했다) 소위 4세대 언어라고 불리는(대표적으로 SQL) 언어들은 자기만의 독자적인 도메인을 가지고 있어 대체도 쉽지 않다.

언어가 많아서 난잡한 것이 아니라 언어가 다양함으로써 얻는 이득이 더 많은 것이 아닐까? 종의 다양성은 일반적으로 전체 생태계를 안정적으로 유지하는데 도움이 된다. 소프트웨어는 다양한 도메인이 있다. 그리고 각 도메인에 맞는 프로그래밍 언어가 있다. 상황에 맞게 언어를 선택하는 것이 중요하다는 이야기다. 엔지니어에게는 여러가지 상황이 발생할 수 있고 다시 말해서 새로운 언어를 습득해야 하면 유리할 경우가 발생할 수 있다. 결론적으로, 여러 언어에 쉽게 적응할 수 있도록 기초(fundamental)에 대한 습득이 필수적이다.

어차피 프로그램이란게 자료구조와 알고리즘 아닌가? 라고 말한다면 너무 기초로 간 것이고. 프로그래밍 언어에 따라 문제를 기술하고 해결하는 방식이 다르다는 것을 이해하고 각자가 가지는 장점과 단점이 무엇인가를 알 필요가 있다.

자, 그렇다면, 다시 글의 제목으로 돌아가자. 학부생에게 어떻게 프로그래밍의 기본 원리, 기초에 대해 정확히 교육시킬 것인가? 아쉽게도 이 글에서는 이 물음이 중요하다는 이야기만을 몇장에 걸쳐 하고 있다. How? 해결책은 구체적으로 나와있지 않다. 나도 모른다. 중요성에 대해서만 적극 공감할 뿐.

어설픈 의견을 내본다면, 여러 언어를 접해보는 것이 가장 좋은 방법이 아닐까 생각해본다. 언어라는 것은 부딪혀 직접 말해봐야 느는 것이니까. 자연어 세계에서 한 언어를 습득하면 그 언어만이 가지고 있는 표현 방식이나 단어 사용 패턴을 이해하게 되고 , 다른 언어에 그것을 잘 적용하면 굉장히 신선한 표현이 되는 경우가 많다. 이 원리는 컴퓨터 프로그래밍 언어에서도 다르지 않다.

HSTS: HTTP Strict Transport Security

Security 2011. 10. 14. 10:58 Posted by 알 수 없는 사용자
크롬에 대해서 보다가 HSTS라는 것을 보게 되었습니다. HTTP Strict Transport Security의 약자인데요, (정확히 이해했는지 확신이 아직 좀 없지만) 쉽게 말하면 "무조건 HTTPS를 쓸 것!"이 됩니다.

크롬을 사용하고 있다면,

chrome://net-internals/#hsts

이 링크로 접근 가능합니다.

여기에 등록해두면 해당 사이트에 접근할 때, 명시적으로 앞에 https:// 를 타이핑하지 않아도 무조건 https로 접속을 시도합니다.

그런데 사용자가 일일이 이 리스트를 입력하고 관리하는 것이 꽤나 귀찮은 일이죠. 그래서 크롬은 preloaded HSTS list라는 것을 built-in으로 가지고 있습니다. 몇 가지 예를 들면
  • www.paypal.com
  • (chrome|checkout|health|docs|spreadsheets|sites|appengine|encrypted).google.com
  • market.android.com
이런 사이트들이 포함되어 있지요. 이 리스트는 구글이 정해둔 것도 있겠지만 해당 웹사이트에서 요청한 것이 대부분입니다. 여러분 누구나 내 웹사이트는 무조건 https를 사용도록 강제하고 싶다면 구글에 요청 메일을 보내면 됩니다. (아마 사이트의 규모가 좀 있어야 해주겠죠?)

'Security' 카테고리의 다른 글

물건 분실을 파악하는 좋은 방법?  (0) 2011.10.14
RFID Tag Coupling  (0) 2011.10.14
가장 비싼 1바이트의 실수  (0) 2011.10.14
DigiNotar의 구라 인증서에 대한 대처  (0) 2011.10.14
가짜 구글 인증서  (0) 2011.10.13