개인적인 호기심에 Java Script 기반의 암호화 알고리즘 구현이 있을까 검색해보게 되었다. 혹시가 역시였는데 매우 다양한 버전의 Java Script 기반의 암호화 알고리즘을 찾을 수 있었다. 클라이언트에서 데이터를 암호화한 후 이것을 서버로 전송하고 이것을 서버에서 같은 비밀 키를 사용하여 해독한다는 개념은 이제는 너무 일반적인 것이라 굳이 언급하지 않아도 될 정도다. 하지만 놀랍게도 이런 구현 절차를 ActiveX에 너무 많이 기대고 있다는 것 또한 사실이다.

ActiveX 없이 다중 브라우저를 지원하면서도 일정 수준 이상의 보안을 충족하는 암호화 시스템을 어쩌면 간단히 구현해볼 수도 있지 않을까라는 호기심이 생겨서 몇 번 코드를 끄적여보았을 뿐인데 개인적으로나 일반적인 커뮤니티에 적용하기에는 딱 좋은 수준의 암호화 시스템이 나와서 글을 써본다. Security Critical한 서비스에서는 HTTPS, SSL, IP/sec 등을 사용하는 것이 100배 안전하지만 이것은 어디까지나 일상적인 암호화만을 다루는 것이다.

기본적인 원리는 간단하다. 같은 Java Script Source Code를 가지고 하나는 Internet Browser용 Java Script Code로 사용하고 또 하나는 JScript .NET 컴파일러용으로 패키징하여 ASP.NET에 통합하는 것이다. 이 글에서는 AES (Advanced Encryption Standard) 알고리즘을 채택하였다.

Java Script AES Implementation: http://www.movable-type.co.uk/scripts/aes.html

위의 사이트에서 핵심적인 AES 구현을 먼저 가져왔다. AES 알고리즘과 비밀 키를 통하여 평문을 암호문으로, 암호문을 평문으로 바꾸는 것이 정확하게 작동한다는 것을 테스트하였다. 하지만 암호문을 평문으로 바꾸는 과정에 있어서 암호문이 바이트의 배열로 출력된다는 점이 걸린다. 인코딩에 따라서는 완전히 다른 내용으로 읽혀져 손상될 가능성이 있기 때문이다. 그래서 BASE64 알고리즘을 다시 찾게 되었다.

Java Script BASE64 Implementation: http://rumkin.com/tools/compression/base64.php

AES 암호문을 BASE64로 보호하고, BASE64 디코딩으로 얻어낸 AES 암호문을 평문으로 바꾸는 것 또한 정확히 동작함을 확인하였다. 그리고 이번엔 정말 실용성이 있는지 확인해보고 싶어서 2바이트 문자열을 가지고 암호화 복호화를 시험해보았다. 하지만 이번엔 정확히 복원해내지 못한다는 것을 확인할 수 있었다. 다행히 2바이트 문자열에 대해서는 자바스크립트 내장 함수인 encodeURI와 decodeURI를 통하여 처리할 수 있었다. 평문에 관한 문제는 해결이 되었지만 비밀 키의 경우에는 이 방법도 의미가 없었다. 비밀 키는 1바이트 문자열 수준에서 해결해야 하는듯 보였다.

이러쿵 저러쿵하여 만든 JavaScript 코드와 바이너리를 ZIP 파일로 묶어서 올려본다. 여러 메서드가 있지만 이 글의 내용을 반영하여 만든 실질적인 메서드는 다음과 같다.

// JavaScript
AesEncrypt128(plainText, password);
AesEncrypt192(plainText, password);
AesEncrypt256(plainText, password):
AesDecrypt128(cipherText, password);
AesDecrypt192(cipherText, password);
AesDecrypt256(cipherText, password):

// C# (Need JScript.NET Runtime Assembly)
SecurityManaged.ComplexAes aesModule = new SecurityManaged.ComplexAes();
aesModule.AesEncrypt128(plainText, password);
aesModule.AesEncrypt192(plainText, password);
aesModule.AesEncrypt256(plainText, password);
aesModule.AesDecrypt128(cipherText, password);
aesModule.AesDecrypt192(cipherText, password);
aesModule.AesDecrypt256(cipherText, password);

클라이언트 측에서는 AesEncrypt로 보호할 내용을 암호화한 후 서버에 전송하고, ASP.NET - 또는 - 이를 받아들일 소켓 서버 등에서는 SecurityManaged.dll 파일을 레퍼런스로 참조하고 SecurityManaged.ComplexAes 클래스의 인스턴스를 만들어 위의 AesDecrypt로 내용을 복구하면 되겠다. 참고로 128/192/256은 키의 길이에 해당된다.

첨부된 파일 안의 .Managed.js 파일은 JScript.NET 문법에 맞게 재배치한 것으로 DLL로 컴파일하는 것을 가능하게 해준다. 안의 내용이나 코드 문법은 오리지널 Java Script과 전혀 차이가 없지만 닷넷 어셈블리로 만들기 위해서 package 구문과 class 구문을 추가하였을 뿐이다. 또한, 가능성만을 타진해보기 위함이었으므로 JScript.NET에서만 가능한 명시적인 형식 지정 또한 누락되어있다. 만약 좀 더 최적화를 원한다면 코드를 수정해서 사용할 것을 권하며 필요한 경우 어트리뷰트 지정을 통하여 지연된 서명을 추가해볼수도 있겠다.

닷넷 프레임워크 2.0을 설치하였다면 명령 프롬프트에서 다음과 같이 입력하면 원하는 어셈블리를 직접 얻을 수 있다. (이 작업을 위해서 Visual Studio 2005나 2008은 필요하지 않다.)

%windir%\microsoft.net\framework\v2.0.50727\jsc.exe /target:library AesImpl.managed.js

이제 우리들만의 일상적이고도 간단한 AES 암호화 알고리즘 시스템을 얻을 수 있게 되었다. 그 다음 활용 방안은 다시 고민해봐야 하겠다. 자바스크립트 기반에 닷넷까지 지원되니 ASP.NET AJAX와 Silverlight에도 잘 어울릴듯 하다.

Creative Commons License
Creative Commons License
남정현 이 작성.

당신의 의견을 작성해 주세요.

[로그인][오픈아이디란?]
오픈아이디로만 댓글을 남길 수 있습니다

Windows Vista 호환성 문제 바로 알기

호환성과 ActiveX

Windows Vista에서 금융 사이트 등 웹사이트가 운영되지 않는다는 호환성 문제가 제기되고 있습니다. 그러나 정확한 의미에서 이 호환성 문제란 ActiveX 기술에 의존한 특정 웹사이트가 특정 버전의 윈도우와 특정 버전의 브라우저가 아니면 실행되지 않는 상황을 의미하며, 이는 수 년 전부터 기타 운영체제 및 기타 브라우저에서 호환되지 않는 문제와 동일한 맥락에서 해결법을 찾아야 합니다.

ActiveX는 웹 브라우저에서 PC의 모든 기능을 활용할 수 있게 하는 기능으로, 사용자에게 더 많은 가능성을 열어 준 기능입니다. 그러나 그 발표로부터 10년이 지난 지금 인터넷은 당시에는 생각하지 못했던 악성 소프트웨어로 보안 위협을 겪고 있습니다.

이는 마이크로소프트도 기술 개발 당시에는 예측하지 못했던 문제로, 스파이웨어나 바이러스 등 인터넷을 통해 사용자의 PC를 파괴할 위험성을 지닌 프로그램이 이 ActiveX에 의존하고 있습니다.

마이크로소프트는 2002년부터 점차적으로 포괄적인 ActiveX 컨트롤의 권한을 축소해 왔습니다.

인증 받지 못한 ActiveX의 실행을 막았으며, Windows Vista에서는 보호모드를 마련하여 컴퓨터 내의 특정 영역만 사용할 수 있도록 하였고, 관리자 권한도 제약을 두었습니다. 이 제약은 모두 향후 예측할 수 있는 모든 잠재적 보안 위협에 대응하기 위한 방향이고, 더 안전한 OS로 완성하기 위한 마이크로소프트의 노력과 방향성에 관련 업계는 세계적으로 동의를 보내고 있습니다.

따라서 보안 문제와, 호환성 문제를 해소하기 위해, 일반 웹사이트들의 개별적인 ActiveX 활용은 자제되어야 한다는 것이 마이크로소프트의 입장입니다.

환경적으로 볼 때, 한국의 인터넷 시장은 세계 어느 나라보다 먼저 다양한 서비스를 개발하였습니다. 그래서 당시 다양한 가능성을 열어 주었던 ActiveX를 적극 활용한 서비스를 기획했습니다. 그 결과, 세계적으로 ActiveX는 주로 UI의 보완을 위해서 활용되어 온 정도입니다만, 한국은 보안과 같은 시스템 솔루션이 ActiveX 기반으로 마련됩니다. 그러나 10년의 시간이 흐르면서 세계적인 보안 환경은 다양한 변화를 맞이합니다. 당시의 미비점도 해결이 되고, 또 당시 생각지 못했던 부차적인 그러나 더 심각한 보안 위협이 대두됩니다. 이에 효과적으로 대응하기 위한 방안을 마련할 시점에 오게 된 것입니다.

ActiveX 사용에 대한 대안의 제안

ActiveX를 보안과 같이 시스템 레벨에서 사용하는 것은 지양되어야 합니다.

128bit SSL을 비롯한 표준화된 인증 체제, 그리고 암호 발생기 등 다양한 보안 솔루션을 국가적 차원에서 열린 자세로 수용하여, 다양한 플랫폼에서 기 구현되고 검증된 인프라를 활용하도록 하는 것이 바람직합니다. 현재 Internet Explorer는 세계 표준적 보안 기능을 내장하고 있고, 세계 각국의 은행들은 브라우저 내장의 보안 기능을 활용하고 있습니다.

사용자의 다양한 UI 요구 수용을 위한 ActiveX 사용도 상황 별로 분별하는 것이 바람직합니다.

ActiveX를 지금과 같이 애플리케이션 레벨에서 사용자 편의를 위해 제공하는 것은 그대로 활용하실 수 있습니다. 그러나 일반 웹사이트 및 솔루션 벤더를 위한 마이크로소프트의 제안은 잠재적 보안 위험 요소로 구분되고 있는 ActiveX 대신, .NET Frameworks 3.0에 근거한 WPF 및 WPF/E와 같은 안전한 프레젠테이션 솔루션을 활용하여 사용자 체험을 강화하는 것입니다. 또 만약 구축하려는 사이트가 일반 사용자용인 경우는 되도록 웹의 권고안을 준수하여 멀티 플랫폼 멀티 브라우저용으로 만드는 것을 마이크로소프트는 추천하고 있습니다.

출처: 한국 Microsoft - 한글 Windows Vista 홈페이지

Creative Commons License
Creative Commons License
남정현 이 작성.

당신의 의견을 작성해 주세요.

[로그인][오픈아이디란?]
오픈아이디로만 댓글을 남길 수 있습니다

오랫만입니다. 얼마전에 해킹 존에 올린 프로그램은 잘 사용하고 계시겠지요? 소리바다에서 제공하는 "파도"라는 플레이어를 비롯한 PLA 포맷을 지원하는 대부분의 오디오 플레이어에서 유용하게 쓰실 수 있을겁니다. ^^

오늘은 대부분의 데이터 베이스 기반 웹 사이트들이 겪는 보안 상의 취약점인 SQL-Injection을 해결하는 범용적인 솔루션을 연구해 보도록 하지요.

SQL-Injection이란, 매개 변수를 강력하게 검사하지 않고 문법의 일부로 더하는 프로그램에서 흔하게 벌어지는 공격 기법입니다. 유별난 공격법이 아니지만 막대한 양의 정보가 한꺼번에 유출되거나, Microsoft SQL Server와 같이 관리자에게 너무나도 풍족한 리소스를 주는 데이터 베이스 서버에서는 다른 파티션을 포맷하는것까지도 가능하게 합니다. (SQL Server에서 기본으로 제공하는 스토어드 프로시저 중에는 셸 명령을 실행할 수 있도록 하는 프로시저도 제공됩니다. 얼마든지 응용하기 나름인 셈이지요.) 무시무시한 이야기이지요.

SQL-Injection이 어떻게 벌어지는지 그 과정을 살펴보도록 하지요.

string commandText = "SELECT * FROM USERS WHERE USER_ID='" + value + "'";

위와 같은 코드를 IDbCommand.CommandText에 지정하고 ExecuteReader() 등으로 실행하면 원하는 결과가 나오리라 흔히 생각합니다. 하지만 큰 착각입니다. value에 무엇이 들어가느냐에 따라서 다음과 같이 크게 변조되니까요.

value = "admin"; // 이것이 흔히 기대하는 형태입니다.

// 완성된 질의문: "SELECT * FROM USERS WHERE USER_ID='admin'"

value = "admin' AND USER_NAME='관리자"; // 이와 같이 변형될 수 있습니다.

// 완성된 질의문: "SELECT * FROM USERS WHERE USER_ID='admin' AND USER_NAME='관리자'"

이런 엄청난 사태가 발생하지 않도록 하려면 몇 가지 해결책이 있습니다.

1. 동일한 기능을 수행하는 스토어드 프로시저 또는 함수를 데이터 베이스 서버에 직접 구축하고, 웹 어플리케이션은 단지 이것을 호출하는 것으로 구조를 변경합니다. 위와 같이 문자열이 전달되었을 경우 "admin' AND USER_NAME='관리자" 라는 문자 자체가 하나의 값으로 처리되고, 질의문, 스토어드 프로시저, 함수의 기능에는 영향을 주지 않으므로 제일 안전하고 빠른 방법입니다.

2. 강력한 형식 검사를 수행합니다. 이것이 오늘 살펴볼 방법이며, 위와 같이 스토어드 프로시저나 함수를 지원하지 않는 데이터 베이스에서도 유용하게 쓰일 수 있는 방법입니다. 프로그래밍 방식으로서, 비즈니스 계층 단위로서 문제를 해결할 수 있는 것이 특징입니다.

코드 살펴보기

아래의 함수는 문제가 될 수 있는 문자열을 제거하는 기능을 수행합니다. pattern이라는 매개 변수에는 제거하고 싶은 문자를 지정하며, 이스케이프 시퀀스가 필요한 문자인 백슬래시, 작은 따옴표, 큰 따옴표와 공백 문자 등을 지정합니다.

    public static string EnsureString(string pattern, string target)
    {
       bool flag = false;
       StringBuilder sb = new StringBuilder(target.Length);

       for(int i=0; i<target.Length; i++)
       {
           for(int j=0; j<pattern.Length; j++)
           {
               // 조건에 해당되는 문자임을 통지하고 검사 과정을 파기합니다.
               if(target[i].Equals(pattern[j]))
               {
                   flag = true;
                   break;
               }
           }

           // 조건에 해당하는 문자임을 확인하고 검사 문자를 생략합니다.
           if(flag)
           {
               flag = false;
               continue;
           }

           // 검사 조건에 해당하지 않는 문자이므로 추가합니다.
           sb.Append(target[i]);
       }

       return sb.ToString();
    }

위의 함수를 사용하여 SQL-Injection을 막아보도록 하겠습니다.

string commandText = "SELECT * FROM USERS WHERE USER_ID='" + EnsureString("\'\"", value) + "'";

// 공격 예시: "admin' AND USER_NAME='관리자";

// 방어 결과: "admin AND USER_NAME=관리자";

// 질의문 결과: "SELECT * FROM USERS WHERE USER_ID='admin AND USER_NAME=관리자'"

스토어드 프로시저나 함수를 이용했을 때와 같은 결과를 얻게 되었습니다. 이 함수를 사용함으로서 얻을 수 있는 또 하나의 장점은 이것이 SQL 질의문이 아니라 연결 문자열 등에도 활용될 수 있다는 점이며, 파일이나 디렉터리 경로를 통한 공격도 비슷한 형태로 막아낼 수 있다는 것이 장점입니다. 그리고 패턴은 얼마든지 추가가 가능하므로 공격 정보만 수집되면 몇 글자 추가하는 것으로 이와 유사한 형태의 공격을 방어할 수 있을 것입니다.

설날이 어느덧 돌아왔군요. 모두들 맛있는 떡국들 많이 드시고 올 해도 건강하십시오. ^^

Creative Commons License
Creative Commons License
남정현 이 작성.

당신의 의견을 작성해 주세요.

[로그인][오픈아이디란?]
오픈아이디로만 댓글을 남길 수 있습니다