Entries Tagged as ColdFusion Code Snippets

최근에 개인정보보호와 관련하여 관련법이 강화되고 의무적으로 보안관련 이슈를 해결해야 하는 과정에서 DB암호화에 관한 부분이 홈페이지 분야에서 많이 대두 되고 있는 것 같습니다.

사실 DB암호화 솔루션의 경우 MySQL, MSSQL 등에 Plugin방식 등으로 탑재되는게 일반적이라고 할 수 있지만 전 그 역시 ActiveX적 사고에서 벗어나지 못한 일부 보안솔루션 회사들의 한계가 아닌가 싶어 아쉽습니다. 일단 뭔가를 열심히 서버에 설치해야 한다는 것. 

사실 DB를 암호화하는 가장 큰 이유는 유출된 데이터가 알 수 없는 코드로 암호화되어 개인정보 등이 노출되지 않도록 하기 위함입니다. 따라서 대부분의 개인정보는 암호화해서 저장되어야 하는데 암호화를 하는 방향에서 두가지로 나뉠 수 있습니다.

하나는 단방향암호화로서 일단 암호화를 하면 다시는 복호화가 불가능?하도록 하는 암호화와 또 하나는 암호화를 하되 필요시 복호화를 해서 내용을 확인해야 하는 암호화가 바로 그것이죠.

전자의 경우는 패스워드와 같이 일단 암호화를 하면 복호화가 안되도록 하는 곳에 주로 사용할 것 이고, 후자의 경우엔 이름이나 주소 등 다시 복호화해서 화면에 출력하거나 확인을 해야 하는 경우가 그 예가 될 수 있습니다.

사실 KISA에서도 이와 관련한 암호화방법에 관련된 기술자료를 오래전에 배포한 적이 있습니다.(참조 : http://seed.kisa.or.kr/iwt/ko/guide/EgovGuideDetail.do?bbsId=BBSMSTR_000000000011&nttId=37&pageIndex=1&searchCnd=&searchWrd=

위 자료의 요지는 앞에서 설명드린 단방향 암호화기법과 양방향암호화, 그리고 주로 쓰이는 ASP, JSP에서의 구현방법에 대한 내용입니다만, 여기서는 ColdFusion에서의 기법에 대해 몇자 적어보려 합니다.

타 웹 개발 언어와 마찬가지로 ColdFusion(CFML)에서도 Hash()함수등의 암호화 함수와 여러 국제적 표준의 알고리즘을 지원합니다. 그중 몇가지를 소개하고자 합니다.

Hash()

ColdFusion에서 사용하는 해시함수입니다. 대부분의 언어와 마찬가지로 사용법은 비슷합니다. 예제를 하나 만들어 보죠.

"안녕하세요?" 라는 평문을 Hash()함수로 암호화하면 다음과 같이 할 수 있습니다. Adobe ColdFusion의 Standard버전에서는 CFMX_COMPAT, MD5, SHA, SHA-256, SHA-384, SHA-512의 알고리즘을 지원하며 Enterprise버전에서는 좀 더 강화된 알고리즘을 지원합니다.(참조 : http://help.adobe.com/en_US/ColdFusion/10.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7c52.html)

<cfset hashDemo = Hash("안녕하세요?", "SHA-512", "UTF-8")>
<cfoutput>#hashDemo#</cfoutput>

위 실행 결과는

9F7384FE6552F1C7A9871C487B1760D011528BC58F556E3F27C6450C7FEB0C15C59AFDF13AB01
8E565764CB5AA35E15A9B7F48EDB745F92A33522FC57C3B6BA6

와 같은 문자열로 암호화 되어서 반환됩니다. 

위와 같이 해시함수로 암호화하면 이 암호를 푸는 인증키가 없기 때문에 해독이 불가능?합니다. (모든 알고리즘은 언젠가는 해독되게 마련이라 99%라고 할 수 있겠네요.)  이와같은 해시함수로 암호화된 데이터는 비밀번호 등 다시는 확인이 불가능한 데이터를 처리할 때 주로 사용합니다. 이 경우 사용자에게 입력받은 데이터를 해시함수로 암호화하여 저장된 데이터와 비교하여 정확한 값입력을 비교할 수 있습니다. 

Encrypt() Decrypt()

Encrypt()함수는 Decrypt()함수와 함께 보안키기반 암호화 함수입니다. 함수에 사용할 보안키를 임의로 생성한 후 해당 보안키로 문자열을 암호화 또는 복호화 합니다. 따라서 해당 보안키를 모르면 복호화가 불가능합니다. 두 함수 역시 다양한 알고리즘을 지원합니다만 각 Adobe ColdFusion에서 지원하는 알고리즘이 다르므로 기술문서를 참조해야 합니다. 보안키를 생성할 때는 GenerateSecretKey()함수를 이용해 임의로 난수 생성합니다. 역시 예제를 하나 살펴보죠.

Encrypt 함수참조 : http://help.adobe.com/en_US/ColdFusion/10.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7c2f.html

Decrypt 함수참조 : http://help.adobe.com/en_US/ColdFusion/10.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7c1c.html

예제 데모보기 : 암호화데모

<!--- AES 알고리즘 사용 --->
<cfset algorithm = "AES">

<!--- Hex 인크딩 사용 --->
<cfset encoding = "Hex">

<!--- 임의의 보안키생성 --->
<cfset encryptKey = "#generateSecretKey(algorithm)#">

<cfset strForEncrypt = "안녕하세요?">
<cfset encryptstr = encrypt(strForEncrypt, encryptKey, algorithm, encoding)>
<cfset decryptstr = decrypt(encryptstr, encryptKey, algorithm, encoding)>

<cfoutput>
<strong>보안키 :</strong> #encryptKey#<br />
<strong>문자열 :</strong> #strForEncrypt#<br />
<strong>암호화 :</strong> #encryptstr#<br />
<strong>복호화 :</strong> #decryptstr#<br />
</cfoutput>

Encrypt()와 Decrypt()함수는 개인정보 중 이름, 주소, 연락처, 이메일 등을 암호화하여 저장하고 필요시에 복호화해서 사용합니다. 중요한 것은 암호화시 사용한 보안키를 잘 보관해야 한다는것입니다. 이 키가 쉽게 노출된다면 복호화 역시 쉽게 될 수 있으니까요. 위에서 언급한 KISA에서 배포되는 자료에서도 해시함수나 블록암호알고리즘시 사용하는 SALT 또는 비밀키(보안키)를 안전한 곳에 잘 보관해야 하며 필요에 따라서는 외부에서 가져오길 권장합니다. DB암호화 솔루션 업체들의 개념을 보면 이 비밀키(보안키)와 같은 인증요소를 정책으로 지정하고 필요시에 인증을 거친 후 요청하도록 구성되어 있는 제품도 있었습니다.

자, ColdFusion에서도 Hash()와 Encrypt(), Decrypt()함수로 암호화 및 복호화를 할 수 있습니다. 국제적으로 공인받은 알고리즘을 사용하므로 시스템자체가 해킹되거나 취약점으로 인해 보안키가 노출되지 않도록만 한다면 간단하게 데이터를 암호화 할 수 있습니다. 하나만 더 붙히면 이와같이 평문의 문자열을 암호화할때 함수실행 전 단계에서 유출될 수 있으므로 SSL과 같은 보안서버의 구축 역시 필수겠죠?

EncryptBinary() DecryptBinary()

그렇다면 이렇게 문자열은 암호화해서 DB에 넣어두고 열심히 나름 보안을 챙겼다고 합시다. 그럼 사용자가 업로드한 파일은? 가령 개인정보가 적혀있는 이력서.doc파일이 업로드되었다고 해 봅시다. 대부분은 웹루트 하위 디렉토리에 파일이 저장되는 구조로 웹어플리케이션을 구성합니다. 이런 구조는 인증절차(로그인과 같은)을 거쳐 다운로드하도록 구성했어도 구글과 같은 검색엔진에 의해 충분히 해당 디렉토리와 파일이 그대로 노출됩니다. 업로드시 파일명을 변경한다 해도 파일자체를 숨기지는 못합니다. 

따라서 파일 업로드와 같은 경우에는 웹루트가 아닌 다른 곳에 파일을 저장하고, 다운로드시 해당 파일을 불러와 다운로드시켜주는 로직으로 구성해야 합니다. ColdFusion에서의 이와 관련된 이전의 제 글이 있으니 참조바랍니다. (http://archives.nooree.com/blog/post.cfm/coldfusion-dilemma-web-browser)

그런데 어떤 경우로 웹루트에 파일을 저장해야 한다고 가정해 봅시다. 그런 경우에는 파일 자체를 암호화 해줘야 합니다. 함부러 열어볼 수 없도록 말이죠. 이를 위해 ColdFusion에서는 EncryptBinary()와 DecryptBinary() 두 함수를 지원합니다. 사용법은 Encrypt()와 Decrypt()함수와 거의 동일 합니다. 문자열 대신 바이너리파일을 대입하는 것이죠.

EncryptBinary 함수참조 : http://help.adobe.com/en_US/ColdFusion/10.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-6e75.html

DecryptBinary 함수참조 : http://help.adobe.com/en_US/ColdFusion/10.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-6e77.html

가령 업로드된 파일이 JPG이미지 파일일 경우 EncryptBinary()로 암호화 해버리면 해당 파일을 다운로드 해가더라도 이미지파일로 인식할 수 없어 열어 볼 수 없습니다. 역시 예제하나 살펴보죠. 

<!--- AES 알고리즘 사용 --->
<cfset algorithm = "AES">

<!--- Hex 인크딩 사용 --->
<cfset encoding = "Hex">

<!--- 임의의 보안키생성 --->
<cfset encryptKey = "#generateSecretKey(algorithm)#">

<!--- 암호화할 파일 로드 --->
<cffile file="#ExpandPath('./sampleppt.pptx')#" action="readBinary" variable="sampleFile"> 

<!--- 파일암호화 --->
<cfset fileEncrypt = encryptBinary(#sampleFile#, encryptKey, algorithm)>
<!--- 암호화된 파일을 저장 --->
<cffile file="#ExpandPath('./sampleppt_enc.pptx')#" action="write" output="#fileEncrypt#"> 

<!--- 파일복호화 --->
<cfset fileDecrypt = DecryptBinary(#fileEncrypt#, encryptKey, algorithm)>
<!--- 복호화된 파일을 저장 --->
<cffile file="#ExpandPath('./sampleppt_dec.pptx')#" action="write" output="#fileDecrypt#"> 

위 코드에서 쓰인 PPT샘플외에 다양한 이미지, 텍스트파일을 직접 다운로드하여 열어 보시길 바랍니다. (마우스 오른쪽 다른 이름으로 저장하시길 바랍니다.) 

원본 이미지 : sampleimage.png
암호화된 이미지 : sampleimage_enc.png (이미지 파일이 볼 수 있나요?)
​복호화된 이미지 : sampleimage_dec.png (복호화된 원본과 같은 이미지)

원본 텍스트파일 : samplefile.txt
암호화된 텍스트파일 : samplefile_enc.txt (열리나요?)
복호화된 텍스트파일 : samplefile_dec.txt

원본 PPT파일 : sampleppt.pptx
암호화된 PPT파일 : sampleppt_enc.pptx (열리나요?)
복호화된 PPT파일 : sampleppt_dec.pptx

별거 아닌걸 디게 거창하게 이야기했습니다만 웹의 특성상 오픈된 시스템이므로 구현시 꼼꼼한 자세가 필요해 보닙니다. 문자열에 대한 암호화 뿐만 아니라 보안키에 대한 보관방법, 업로드되는 파일의 암호화 등 웹개발자는 신경쓸 것이 참 많습니다. ^^

JPG나 PNG에는 이미지의 다양한 정보가 들어 있습니다. EXIF, IPTC, XMP 같은 것 들이죠. 카메라 제조사마다 약간씩 차이는 있겠지만 이미지노출정보라던가 촬영일, GPS가 내장된 기기라면 촬영장소 등이 저장되는 정보입니다. 

일반적으로 개인소장 이미지라면 별 문제가 없지만 인터넷에 공개될 이미지라면 이들 정보가 들어가 있으면 용량도 커지고 개인정보 노출 등의 문제점도 있으므로 공개할 이미지에서는 웬만하면 이들 메타정보를 제거하는게 낫다고 합니다.(http://html.nhncorp.com/markup_tools/imgoptimizer 참조)

보통의 경우 Photoshop에서 Save for Web 옵션으로 저장한 경우 이들 메타정보가 제거되지만 이미 서버상에 수많이 올라온 이미지들의 메타정보를 한번에 제거하려면, ColdFusion에서 처리하는 방법과 외부 Tool을 이용해서 처리할 수 있습니다.

하지만 ColdFusion에서 제공하는 Image관련 함수와 태그로 제거하려면 이미지를 재합성하는 등 프로세싱에 많은 자원이 소모되므로 간단하게 쉘 응용프로그램(ImageMagick)을 이용해서 바꾸도록 하는 것이 낫겠죠.

ColdFusion에서 자체적으로 제공하는 태그와 함수외에 Java를 응용하려면 Sanselan 이라는 라이브러리(http://commons.apache.org/proper/commons-imaging/index.html)를 이용할 수 도 있습니다. 간단하게 Javaloader를 이용해서 Sanselan 라이브러리를 로드한 다음 Sanselan에서 제공하는 removeExifMetadata()함수를 이용하여 제거할 수 있습니다. (http://stackoverflow.com/questions/5520444/generating-thumbnails-using-cf8-cfimage-tag-large-filesize-caused-by-image-met 참조)

<cfscript>
// setup and init the Sanselan library
SanselanPath = arrayNew(1);
arrayAppend(SanselanPath, expandPath("./sanselan-0.97-incubator.jar"));
javaloader = createObject("component", "javaloader.JavaLoader").init(SanselanPath);

// setup your source and destination image
pathToInFile = ExpandPath("./myImage.jpg");
pathToOutFile = ExpandPath("./MyImagewoEXIF.jpg");
inFile = javaloader.create("java.io.FileInputStream").init(pathToInFile);
outFile = javaloader.create("java.io.FileOutputStream").init(pathToOutFile);

// create the exifRewriter 
exifRewriter = javaloader.create("org.apache.sanselan.formats.jpeg.exifRewrite.ExifRewriter").init();

// call the method removeExifMetadata
exifRewriter.removeExifMetadata(inFile,outFile);
outFile.close();
</cfscript>

하지만 특정 디렉토리에 들어있는 모든 이미지의 메타정보를 지우려면 역시나 쉘응용프로그램을 이용하는 것이 낫겠죠? ImageMagick과 같은 쉘응용프로그램에서 다음과 같이 한줄로 처리할 수 있습니다. 바로 ImageMagick에서 제공하는 mogrify 명령을 이용합니다.(http://www.imagemagick.org/www/mogrify.html 참조)

Shell상에서는 다음과 같이 특정 디렉토리(image라는 디렉토리라고 가정)의 모든 JPG파일을 일괄변환할 수 있습니다.

find ./image -name *.jpg | xargs mogrify -strip

물론 단일 파일에 대해서는 mogrify - strip sample.jpg와 같이 쓸 수 있겠지만 ColdFusion에서 <cfexecute>태그의 arguments속성에 |(pipe)기호를 쓸 수 없으므로 디렉토내의 모든 JPG파일을 반환하는 루프를 ColdFusion으로 작성해야 합니다. 하지만 단일 이미지의 변환은 다음과 같이 쉽게 할 수 있겠죠?

<cfexecute name="mogrify" arguments="-strip /이미지절대경로/sample.jpg" timeout="60" variable="result"></cfexecute>

제목만 놓고 보면 사실 대단한거 같지만 모든 훌륭한 소프트웨어가 단순한 아이디어와 몇줄의 코드로 시작한다고 볼때 어쩌면 도움이 되는 팁이 아닐까 싶어 몇자 적습니다. 사실은 제가 이번 지방자치단체 홈페이지 접속불가 사태에 대응하는 훌륭한 도구가 되어서 소개할까 합니다.

몇년전에도 제 이전 블로그에서도 비슷한 글을 남기것 같지만 사실 같은 코드로 다양하게 응용할 수 있습니다. ColdFusion의 3인방 Adobe ColdFusion, Railo, Open Bluedragon(.net의 BlueDragon포함)에는 훌륭한 Scheduled Task 툴이 내장되어 있습니다.

ASP나 PHP등에서는 외부의 도움없이는 아예 구현이 힘들고 JSP쪽은 Java로 별도로 구현하거나 또는 내장된 WAS를 써야하지만 어쨌든 HTTP기반으로 서비스되는 스크립트문서의 특성상 일정주기를 가지고 자동으로 실행되게 하는 것은 말과는 다르게 은근 구현과 운영이 힘듭니다.

ColdFusion의 내장 Scheduled Task(이하 스케줄러)는 자기자신이 설치된 서버상의 ColdFusion파일들 즉, cfm이나 cfc와 같은 파일들을 실행하기도 하지만 외부의 서버의 다른언어 ASP나 PHP, JSP와 같은 외부의 URL을 주기적으로 실행할 수 도 있습니다. 

특정포트도 지정할 수 있으며, 외부의 그 URL에 해당되는 페이지의 보안을 위하여 Apache인증과 같은 웹서버인증이 걸린 페이지라 하더라도 미리 아이디와 패스워드를 지정해 놓으면 알아서 로그인?하여 페이지를 실행해 줍니다.

스케줄링은 크게, Task의 이름, 실행할 URL, 포트, 프록시(해당되는 경우만)설정, 웹서버인증(해당되는 경우만), 실행주기, 로깅유무 등을 지정하고 저장만 해 놓으면 알아서 해당 주기별로 URL을 실행해 줍니다. 물론 이 기능 자체만으로 외부서버의 상태에 대해 알 수는 없죠. 해당 페이지가 있던 없던 주기별로 실행해 버리고 마니까요.

현재 기획단계이기는 하지만 위에서 설명드린 비슷한 기능을 하는 프로젝트를 구상중입니다. 가볍게 만들고 요긴하게 쓰이는 웹기반 어플리케이션을 만들자가 저의 기본 철학이므로 "워드프레스"급 성능과 기능을 요구하시면 안됩니다.

어쨋든 이제 슬슬 본론으로 들어가서, 우선 각 ColdFusion 엔진별로 Scheduled Task의 기능을 살펴봅시다. 대부분의 Java기반 WAS가 그렇듯 웹기반의 관리자모드를 지원합니다. 코드량이 극히 적고 초보자의 이해와 습득에 최정상급임을 자타가 공인하는 언어이지만,  대부분 실제 코드를 더 줄여주는 설정을 미리 하기 위한 것이 각 ColdFusion엔진의 Administrator의 역할입니다.

간단하게 소개하자면, SMTP나 LDAP, Session관리, DBMS와의 연동을 위한 Data Source Name 설정, WebService의 설정, 기타 보안관련 설정 등을 하기 위한 관리자모드입니다. 오픈소스 Java서블릿엔진들이 대부분 conf파일로 지정하게 한 것을 웹에서 관리하도록 만든거라 생각하시면 되겠네요. 마치 PHP의 단순 php.ini와 ZendServer와 같은 개념으로.

각, ColdFusion엔진의 Administrator모드로 접속을 하여 Scheduled Task를 접속하면, 아래와 같은 화면을 보실 수 있을 겁니다.

ColdFusion엔진별 Scheduled Task 비교

adobecf_scheduledtask_s.png

<Adobe ColdFusion 10 - 클릭하면 크게 볼 수 있습니다>

adobecf_scheduledtask_s.png

<Railo 4.0 - 클릭하면 크게 볼 수 있습니다>

adobecf_scheduledtask_s.png

<Open Bluedragon 3.0 - 클릭하면 크게 볼 수 있습니다>

각 엔진별로 기능은 대동소이 합니다만, 최근 Adobe ColdFusion 10의 경우엔 이전 버전과 달리 Scheduled Task 부분에 많이 기능이 더 추가되었습니다. (최근 Adobe 내부에서 가장 Hot한 부서중 하나가 ColdFusion개발부서가 아닐까 생각합니다.) 스케줄러에 대한 자세한 설명은 여기서 다 할 수 없으니 차후로 약속을 드리면서, 각 엔진 중 Adobe ColdFusion의 경우 개발자버전에 한해 기간제한 무료로 쓸 수 있습니다.(커넥션이 10개로 제한됩니다만 스케줄링에서는 제한이 없습니다.) 나머지 Railo나 OpenBD의 경우 오픈소스이기 때문에 프로덕션 환경에서도 사용할 수 있습니다.

여기서는 가장 간단한?하지만 가장 핵심적인 기능을 제공하는 OpenBD를 기준으로 설명드리겠습니다. 정작 중요한 것은 각 엔진의 스케줄러가 아니라, 스케줄러 실행할 오늘 만들 ColdFusion 코드이니까요. (Adobe ColdFusion이나 Railo를 이용해서 동일하게 Scheduled Task를 설정하면 됩니다.)

OpenBD Scheduled Task를 이용하기

먼저, 테스트를 위해 OpenBD를 다운로드합니다. 테스트용으로 사용할 것이지만 본인이 운영하는 J2EE기반의 서블릿엔진(Tomcat 등)이 있다면, 즉시 Deploy해서 사용할 수 도 있겠죠?

OpenBD 다운로드 http://openbd.org/downloads/

위 다운로드 페이지에서 압축만 풀고 바로 사용할 수 있도록 OpenBD Desktop 버전을 다운로드 합니다. Windows/Linux/Mac 모두 지원합니다만, 시스템에 미리 JDK가 설치되어 있어야 합니다. 단순히 압축을 풀고 내부의 명령어를 각 운영체제에 맞게 실행하면 됩니다. Windows의 경우 OpenBlueDragonDesktop.exe를 실행하면 됩니다. 이후 아래와 같은 패널이 실행되면 홈디렉토리와 포트, 그리고 관리자모드 생성하도록 체크하고 시작하시면 됩니다. 80포트로 지정했다면 브라우저에서 http://127.0.0.1:80으로 접속하면 되겠죠?

OpenBlueDragonDesktopServerPanel.png 

Web App Folder : 사용자의 홈디렉토리를 지정합니다. 여기에 .cfm(ColdFusion 문서) 파일을 만들것입니다.
Web Port : 사용할 포트를 지정합니다. 이미 IIS 등 웹서버가 구동중이라면 다른 포트를 지정하세요. 
Options : Enable Admin Console /bluedragon 옵션을 체크하세요.
RunTime Engine : Standard Engine

자, 이제 Start Web App 버튼을 눌러 OpenBD는 시작합니다. 브라우저에서 http://127.0.0.1:지정한포트/bluedragon/administrator 로 접속해 봅니다. 관리자모드로 접속이 되면 admin(초기비밀번호)을 입력하고 로그인합니다. 그런 다음 Scheduled Task 메뉴에서 적절히 샘플 작업하나를 등록해 봅시다.

openbd_sampletask.png

Task Name : sampletask 라고 입력합니다.
Duration - Start Date : 오늘 날짜로 지정합니다. (오늘 이전날짜 임의지정 가능)
Duration - End Date : 스케줄링이 끝날 날짜를 지정합니다. 항시 실행하려면 공란.
Interval : Daily Every 180 seconds from 00:00  매일 자정부터 매 180초마다 실행. to 항목 공란.
Full URL : 실행할 URL의 경로지정. 여기서는 이따 만들 servercheck.cfm 파일을 실행할 것이므로 지정함.
Full URL - Port : OpenBD패널에서 지정한 포트를 입력해야 로컬페이지를 실행할 수 있겠죠?
Request Timeout : 스케줄링이 실행될 시간. 50초이내에 "한번의" 스케줄링을 끝내도록 지정합니다.

나머지 항목은 기본값으로 둡니다. 자 submit 버튼을 눌러 등록한 후 맨 위의 Scheduled task 목록의 연필모양의 아이콘 왼쪽의 실행버튼을 눌러 스케줄링을 시작합니다. 

하지만 아직, servercheck.cfm 파일을 만들지 않았기 때문에 스케줄링은 되지만 어떠한 일도 발생하지 않습니다. 즉, 스케줄러가 실행할 servercheck.cfm파일을 만들어 해당경로에 두고 실행하면 매 180초마다 servercheck.cfm파일을 실행할 것 입니다.

그렇다면 이제 servercheck.cfm 파일은 무슨 기능을 하도록 프로그래밍해야 할까요? 우선 내가 체크하고자 하는 외부서버의 경로를 점검하여 정상적인 웹서버의 응답코드 "200 OK"가 아닌 경우 메일과 문자로 알려주는 기능을 만들어 봅시다.

HTTP 응답코드는 다양한 코드를 웹서버가 응답해 주는데, 가령 페이지를 찾을 수 없는 경우엔 404 Not Found 등이 바로 그것입니다. 자세한 응답코드에 대한 설명은 http://ko.wikipedia.org/wiki/HTTP 에서 확인해 볼 수 있습니다. 중요한 것은 "200 OK"만이 정상적인 웹서버의 응답이라는 것 입니다. 예를 들어 404나 500과 같은 응답코드가 수신되었다면 아마도 브라우저로 해당 경로에 접속했을때 정상적인 화면을 볼 수 없을 것 입니다.

코드작성

자, 이제 간단한 ColdFusion코드를 살펴봅시다. 메일도 보내고, 문자도 보낸다고 코드가 길고 복잡할 것 같지만 ColdFusion은 태그기반의 간결하고 매우 짧은 코드를 작성하도록 고안된 언어이기 때문에 누구나 쉽게 처음 배워도 대강의 코드만 보고 이것이 무슨 역할을 하는지 맞춰볼 수 있을 정도입니다.

servercheck.cfm

<cfprocessingdirective pageencoding="utf-8" />
<cfcontent type="text/html; charset=utf-8">

<!---
<cfset AuthIps="이 페이지가 실행되고 있는 서버 자신의 IP주소">
<cfif ListFind(AuthIps, #CGI.REMOTE_ADDR#) EQ 0>
	<cfabort>
</cfif>
--->

<cfset checkDomain = "http://www.someremoteserver.com/test.jsp">

<cftry>
	<cfhttp url="#checkDomain#" method="post" resolveurl="yes" throwOnError="yes" port="80" timeout="60" />
<cfcatch>
	<cfset cfhttp.statuscode="unavailable" />
</cfcatch>
</cftry>

<cfif cfhttp.statuscode NEQ "200 OK">

	<!--- Email 알림 --->
	<cfmail from="서버체크 <check@mydomain.com>"
			to="alert@mydomain.com"
			bcc=""
			cc=""
			subject="홈페이지 접속오류 발생"
			charset="utf-8"
			timeout="60"
			server="SMTP Server"
			port="SMTP Port"
			username = "SMTP user ID" 
			password="SMTP user password"
		    useSSL = "yes or no" 
		    useTLS = "yes or no" 
			>
	도메인 : #checkDomain#
	점검시각 : #DateFormat(Now(), "yyyy년 mm월 dd일")# #TimeFormat(Now(), "HH시 MM분 SS초")#
	상태 : #cfhttp.statuscode#
	</cfmail>

	<!--- SMS 알림 : Cafe24 SMS의 경우 --->
	<cfhttp method="post" url="https://sslsms.cafe24.com/sms_sender.php" charset="utf-8">
		<cfhttpparam type="formfield" name="user_id" value="">
		<cfhttpparam type="formfield" name="secure" value="">
		<cfhttpparam type="formfield" name="sphone1" value="012">
		<cfhttpparam type="formfield" name="sphone2" value="345">
		<cfhttpparam type="formfield" name="sphone3" value="6789">
		<cfhttpparam type="formfield" name="rphone" value="000-111-2222">
		<cfhttpparam type="formfield" name="msg" value="홈페이지 접속오류 발생 #cfhttp.statuscode#">
	</cfhttp>

</cfif>

간결한 코드로 보이시나요? 별거 없습니다. 우선 맨 위 두줄은 ColdFusion에서 문서의 인코딩과 코드를 유니코드로 처리하도록 지정하는 코드입니다. 여기서는 큰 의미는 없습니다. Railo와 OpenBD는 문서를 저장할 때 utf-8방식으로 저장하거나 서버상에서 항상 utf-8로 처리하도록 지정할 수 있기에 이 두줄은 Adobe ColdFusion에서만 해당됩니다.

<cfif ListFind(AuthIps, #CGI.REMOTE_ADDR#) EQ 0> 부분은 보안을 위한 코드로 servercheck.cfm 도 하나의 문서이기때문에 외부에서 브라우저접속으로 실행이 가능합니다. 따라서 스케줄러 즉, ColdFusion엔진이 구동중인 서버 자신만 이 페이지를 실행하도록 서버자신의 아이피를 지정하여 해당 아이피가 아닌 경우 실행을 중지 <cfabort>합니다. 단, 127.0.0.1과 같은 로컬주소를 지정하면 안됩니다.

<!--- --->와 같은 HTML의 주석과 비슷하지만 대시(-)가 하나 더 있는 것이 ColdFusion의 주석입니다. 주석처리되어 있는 부분은 실행이 안됩니다.

<cfset checkDomain="">으로 지정된 주소가 실행시 점검할 대상이 되는 URL입니다. 스케줄러가 이 페이지(servercheck.cfm)를 실행하면 이 페이지는 <cfset checkDomain="">에서 지정한 페이지를 실행합니다.

실제로 외부URL에 접속하여 해당 웹서버의 헤더를 받아오는 일을 처리하는 태그는 <CFHTTP>태그입니다. <CFTRY>태그로 래핑되어 있는 코드구간 중에 CFHTTP태그는 원격서버에서 웹서버의 헤더를 수신하는 일을 처리하고, 만약 알 수 없는 오류가 난다면 <CFTRY>와<CFCATCH>로 예외처리를 해줍니다. CFHHTP에서 원격서버의 웹서버 헤더정보는 cfhttp.statuscode로 리턴되기 때문에 알 수 없는 오류가 나오거나 원격서버의 웹서버가 아예 죽어버려 응답조차 못할 경우를 예외처리하기 위함 입니다.

매우 간단하게 단 한줄로 원격 웹서버의 상태를 확인할 수 있겠죠? 자, 이제 그 서버에서 200 OK 를 보내오지 않는 다면 문제가 있는 것이므로 관리자에게 확인해 보라는 메일과 SMS를 보낼 차례입니다. 

<cfif cfhttp.statuscode NEQ "200 OK"> 코드 블럭안이 바로 그것입니다. <CFMAIL>태그는 메일을 송신하는 역할을 하는 태그입니다. <CFHTTP>태그가 또 한번 쓰였네요. <CFHTTP>태그는 원격 웹서버의 정보를 받아오기도 하지만 HTML의 FORM처럼 GET/POST로 데이터를 전송하는 역할도 같이 하는 기특한 태그입니다. <CFHTTPPARAM>태그로 전송할 변수명(name)과 데이터(value)를 지정하여 전송합니다.

여기서는 제가 이용중인 Cafe24의 SMS를 이용하여 전송하는 예제입니다만, 여러분이 이용하시는 SMS의 전송경로에 맞춰 수정하시면 됩니다. 각 SMS제공사에서 URL로 POST로 전송되어야 하는 변수와 값의 쌍을 알려주므로 <CFHTTPPARAM>부분의 name과 value값을 변경하시면 되겠죠?

결과

자, 이제 servercheck.cfm 파일을 로컬에서 실행중인 OpenBD의 홈디렉토리에 저장하고, 180초를 기다려 봅시다. 정상적으로 스케줄링을 등록하고, 코드에 이상이 없다면 아래와 같이 문자와 메일이 수신되어 확인하라는 메시지를 알려줄 것 입니다.

check_mail_list.png

check_sms_list.png

Powered by

© 2010-2018 NOOREE.COM