안전한 PHP 응용 프로그램을 작성하는 일곱 가지 습관

웹 응용 프로그램의 보안성을 높이자

Nathan A. Good, Senior Information Engineer, Freelance Developer

요약:  PHP 응용 프로그램을 짤 때는 원격 보안과 지역 보안을 모두 고려해야 합니다. 이 기사에서는 두 가지 측면 모두에서 PHP 프로그램 보안을 높여줄 개발자를 위한 일곱 가지 프로그래밍 습관을 소개합니다.

원문 게재일:  2008 년 9 월 30 일  번역 게재일:   2009 년 2 월 24 일  난이도:  중급 

보안을 고려할 때는 실제 플랫폼과 운영체제 보안뿐만 아니라 응용 프로그램 보안 유지도 중요하다. 즉, 프로그래머는 안전한 프로그램을 짜야 한다. PHP 프로그램을 작성한다면 다음 일곱 가지 습관으로 프로그램 보안을 최대로 높여보자.

입력을 검증하라

입력 검증은 프로그램 보안을 높여주는 가장 중요한 습관이다. 입력을 검증하는 원칙은 간단하다. 사용자를 절대로 믿지 말라! 물론 대다수 사용자는 착해서 프로그램을 용도 그대로 사용할 가능성이 높다. 하지만 입력 필드가 존재하는 한 아주 아주 나쁜 입력이 들어올 가능성도 언제나 존재한다. 응용 프로그램 개발자는 나쁜 입력을 대비하여 프로그램을 짜야 한다. 프로그램이 어떤 입력을 허용할지 그리고 입력 값을 어떻게 사용할지 신중하게 고려해야 안전하고 안정적인 프로그램이 만들어진다.

파일 시스템과 데이터베이스에 관련한 보안은 나중에 다시 설명하겠지만, 다음에 입력 값을 검증하는 일반적인 방법을 정리해 보았다.

화이트 리스트는 유효한 값을 저장하는 목록이다. 유효하지 않은 값을 저장하는 블랙 리스트와 반대되는 개념이다. 검증 작업을 수행하는 경우에 종종 이런 구분이 필요하다. 일반적으로 입력 값은 유효한 값 수가 유효하지 않은 값 수보다 작다. 유효하지 않은 값은 대개 알려지지 않았거나 예상하지 못하는 값이기 때문이다.

입력을 검증할 때는, 때로는 알려지지 않은 모든 경우 수를 따지는 대신 응용 프로그램이 허용하는 입력을 개념적으로 해석해서 검증하는 편이 쉽다는 사실을 기억하자. 예를 들어, 한 필드에서 모든 값을 숫자로 제한하려면 입력이 모두 숫자인지 확인하는 함수를 작성한다. 입력에서 숫자가 아닌 값을 찾아서 특정 부분이 틀렸다고 표시하는 방식은 피한다.

파일 시스템을 보호하라

2000년 7월, 한 웹 사이트가 고객 정보를 유출했는데, 유출한 고객 정보는 웹 서버에 파일로 저장되어 있었다. 사이트 방문자는 URL을 조작하여 고객 정보 파일을 찾아냈다. 누군가 실수로 파일을 웹 서버에 올려서 발생한 사건이지만, 파일 시스템을 공격자로부터 보호해야 하는 중요성을 잘 보여주는 사례라 하겠다.

PHP 프로그램이 파일을 다룬다면, 그리고 사용자로부터 입력을 받는다면, 사용자가 조작하지 않기를 원하는 파일 시스템을 손상하지 못하도록 사용자 입력을 철저히 확인한다. Listing 1은 사용자가 이미지 파일 이름을 직접 입력해 파일을 내려받는 PHP 코드다.

Listing 1. 파일 내려받기

<?php
if ($_POST['submit'] == 'Download') {
    $file = $_POST['fileName'];
    header("Content-Type: application/x-octet-stream");
    header("Content-Transfer-Encoding: binary");
    header("Content-Disposition: attachment; filename=\"" . $file . "\";" );
    $fh = fopen($file, 'r');
    while (! feof($fh))
    {
        echo(fread($fh, 1024));
    }
    fclose($fh);
} else {
    echo("<html><head><");
        echo("title>Guard your filesystem</title></head>");
    echo("<body><form id=\"myFrom\" action=\"" . $_SERVER['PHP_SELF'] .
        "\" method=\"post\">");
    echo("<div><input type=\"text\" name=\"fileName\" value=\"");
    echo(isset($_REQUEST['fileName']) ? $_REQUEST['fileName'] : '');
    echo("\" />");
    echo("<input type=\"submit\" value=\"Download\" name=\"submit\" /></div>");
    echo("</form></body></html>");
}

위에서 보듯이 Listing 1은 매우 위험한 스크립트다. 웹 서버가 읽기 권한이 있는 파일은 어느 파일이나 제공한다. 세션 디렉터리에 있는 파일은 물론 /etc/passwd 같은 몇몇 시스템 파일도 포함한다(세션 파일은 “세션 정보를 보호하라” 절을 참조한다). 위 코드에서는 예제 목적으로 사용자로부터 파일 이름을 입력받지만, 손쉽게 질의 문자열에 파일 이름을 곧바로 추가해도 돌아간다.

사용자 입력으로 파일 시스템을 탐색하는 방식은 위험하므로 아예 피한다. 데이터베이스를 사용하거나 (사용자 모르게) 파일 이름을 생성하는 편이 낫다. 그러나 사용자 입력이 불가피한 경우도 있다. Listing 2는 사용자가 입력한 파일 이름을 검증하는 코드다. 정규 표현식을 사용하여 모든 문자가 유효한지 확인한다. 특히 디렉터리를 뜻하는 .. 문자를 주의해서 확인한다.

Listing 2. 파일 이름 문자가 유효한지 확인하기

function isValidFileName($file) {
    /* ..을 허용하지 않으며, 다른 "낱말" 글자 \ /를 허용한다 */
    return preg_match('/^(((?:\.)(?!\.))|\w)+$/', $file);
}

데이터베이스를 보호하라

2008년 4월, 미 교도국(Department of Corrections)이 SQL 열 이름을 질의 문자열에 사용하는 바람에 민감한 정보를 유출했다. 악의 있는 사용자가 질의 문자열에 열 이름을 추가한 후 페이지를 제출하면 웹 서버가 결과를 반환했다. 사용자들이 응용 개발자가 전혀 예상하지 못한 방식으로 입력을 악용하는 좋은 예다. 또한 SQL 삽입(injection) 공격에 대비할 필요성을 강조하는 예이기도 하다.

아래 Listing 3은 SQL 문을 실행하는 스크립트 예다. 이 예제에서 사용하는 동적 SQL 문은 방금 설명한 공격을 허용한다. 폼을 작성한 개발자는 사용자가 열 이름을 선택만 하므로 코드가 안전하다 여길지도 모르겠지만, 아래 코드는 폼 스푸핑(form spoofing)이라는 위험을 고려하지 않았다(폼 스푸핑은 마지막 습관으로 설명한다). 드롭다운 목록으로 선택을 제한했어도 (별표 [*]를 포함하여) 임의의 입력값으로 원하는 폼을 제출하는 방법은 있다.

Listing 3. SQL 문 실행하기

<html>
<head>
<title>SQL Injection Example</title>
</head>
<body>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
<div><input type="text" name="account_number"
    value="<?php echo(isset($_POST['account_number']) ?
        $_POST['account_number'] : ''); ?>" />
<select name="col">
<option value="account_number">Account Number</option>
<option value="name">Name</option>
<option value="address">Address</option>
</select>
<input type="submit" value="Save" name="submit" /></div>
</form>
<?php
if ($_POST['submit'] == 'Save') {
    /* do the form processing */
    $link = mysql_connect('hostname', 'user', 'password') or
        die ('Could not connect' . mysql_error());
    mysql_select_db('test', $link);

        $col = $_POST['col'];

    $select = "SELECT " . $col . " FROM account_data WHERE account_number = "
        . $_POST['account_number'] . ";" ;
    echo '<p>' . $select . '</p>';

    $result = mysql_query($select) or die('<p>' . mysql_error() . '</p>');

    echo '<table>';
    while ($row = mysql_fetch_assoc($result)) {
        echo '<tr>';
        echo '<td>' . $row[$col] . '</td>';
        echo '</tr>';
    }
    echo '</table>';

    mysql_close($link);
}
?>
</body>
</html>

그러므로 데이터베이스를 보호하려면 동적 SQL 코드를 최대한 자제한다. 동적 SQL 코드가 불가피하다면 적어도 열 이름을 그대로 사용하지 않는다. Listing 4는 계정 번호 필드가 숫자인지 확인하는 간단한 함수와 정적 열 이름을 사용하여 보안을 강화한 코드다.

Listing 4. 입력을 검증하고 mysql_real_escape_string()으로 보호하기

<html>
<head>
<title>SQL Injection Example</title>
</head>
<body>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
<div><input type="text" name="account_number"
    value="<?php echo(isset($_POST['account_number']) ?
        $_POST['account_number'] : ''); ?>" /> <input type="submit"
    value="Save" name="submit" /></div>
</form>
<?php
function isValidAccountNumber($number)
{
    return is_numeric($number);
}

if ($_POST['submit'] == 'Save') {

    /* 습관 #1: '입력을 검증하라'를 기억하자! */
    if (isset($_POST['account_number']) &&
    isValidAccountNumber($_POST['account_number'])) {

        /* 폼 처리 작업을 수행한다. */
        $link = mysql_connect('hostname', 'user', 'password') or
        die ('Could not connect' . mysql_error());
        mysql_select_db('test', $link);

        $select = sprintf("SELECT account_number, name, address " .
        " FROM account_data WHERE account_number = %s;",
        mysql_real_escape_string($_POST['account_number']));
        echo '<p>' . $select . '</p>';

        $result = mysql_query($select) or die('<p>' . mysql_error() . '</p>');

        echo '<table>';
        while ($row = mysql_fetch_assoc($result)) {
            echo '<tr>';
            echo '<td>' . $row['account_number'] . '</td>';
            echo '<td>' . $row['name'] . '</td>';
            echo '<td>' . $row['address'] . '</td>';
            echo '</tr>';
        }
        echo '</table>';

        mysql_close($link);
    } else {
        echo "<span style=\"font-color:red\">" .
    "Please supply a valid account number!</span>";

    }
}
?>
</body>
</html>

위 예제는 mysql_real_escape_string() 함수도 사용한다. 이 함수는 입력에서 유효하지 않은 문자를 적절히 제거한다. 지금까지magic_quotes_gpc를 사용했다면 주의하기 바란다. PHP V6부터는 magic_quotes_gpc를 지원하지 않는다. 그러므로 앞으로는magic_quotes_gpc를 피하면서 안정적인 PHP 프로그램을 작성하는 습관을 들인다. ISP를 사용한다면 ISP가 magic_quotes_gpc 옵션을 꺼둘 가능성도 있으니 ISP 설정을 확인한다.

마지막으로 Listing 4를 보면 SQL 문이나 HTML 테이블이 입력 값에 따라 동적으로 변하지 않는다. 따라서 나중에 필요하다면 HTML 테이블에 다른 열을 추가하기가 쉬워진다. 프레임워크 내에서 데이터베이스를 사용한다면 프레임워크가 SQL을 미리 검증할지도 모른다. 자세한 내용은 프레임워크 문서를 참조한다. 혹시라도 확실하지 않다면 SQL을 검증하는 편이 안전하다. 프레임워크 내에서 데이터베이스를 사용하더라도 다른 검증이 여전히 필요하다.

세션을 보호하라

기본적으로 PHP 세션 정보는 임시 디렉터리에 기록된다. Listing 5에서 폼을 살펴보자. Listing 5는 세션에 사용자 ID와 계정 번호를 저장한다.

Listing 5. 세션 정보 저장하기

<?php
session_start();
?>
<html>
<head>
<title>Storing session information</title>
</head>
<body>
<?php
if ($_POST['submit'] == 'Save') {
    $_SESSION['userName'] = $_POST['userName'];
    $_SESSION['accountNumber'] = $_POST['accountNumber'];
}
?>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
<div><input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" name="userName"
    value="<?php echo(isset($_POST['userName']) ? $_POST['userName'] : ''); ?>" />
<br />
<input type="text" name="accountNumber"
    value="<?php echo(isset($_POST['accountNumber']) ?
    $_POST['accountNumber'] : ''); ?>" />
<br />
<input type="submit" value="Save" name="submit" /></div>
</form>
</body>
</html>

Listing 6은 /tmp 디렉터리 내용이다.

Listing 6. /tmp 디렉터리에 들어있는 세션 파일

-rw-------  1 _www    wheel       97 Aug 18 20:00 sess_9e4233f2cd7cae35866cd8b61d9fa42b

Listing 7에서 보듯이 세션 파일 내용은 아주 읽기 쉬운 형식이다. 세션 파일은 웹 서버 사용자에게 읽기 권한과 쓰기 권한이 모두 있다. 그러므로 공유 서버를 사용하는 경우에 세션 파일이 문제를 일으킬 소지가 많다. 다른 사용자가 내 세션 파일을 읽어 세션에서 값을 추출하는 스크립트를 작성할 수도 있다.

Listing 7. 세션 파일 내용

userName|s:5:"ngood";accountNumber|s:9:"123456789";

세션 정보를 보호하는 방법은 두 가지다. 첫째는 세션 파일에 저장하는 정보를 모두 암호화하는 방법이다. 하지만 암호화했다고 100% 안전하지는 않다. 즉, 암호화만으로는 부족하다는 뜻이다. 둘째는 세션 정보를 (데이터베이스와 같이) 다른 장소에 저장하는 방법이다. 물론 데이터베이스도 보호해야 하지만, 두 번째 방법은 두 가지 문제를 해결한다. 첫째, 정보를 공유 파일 시스템보다 좀 더 안전한 장소에 보관한다. 둘째, 여러 호스트가 세션을 공유할 수 있으므로 여러 웹 서버로 응용 프로그램을 확장하기가 쉬워진다.

응용 프로그램에서 세션을 지속적으로 유지하고 싶다면 PHP 문서에서session_set_save_handler() 함수를 살펴본다. 이 함수를 사용하면 데이터베이스에 세션을 저장하거나 세션 정보를 암호화/해독하는 핸들러를 구현할 수 있다. Listing 8은 핸들러 함수를 정의하고 session_set_save_handler() 함수를 호출하는 예제다. 세션 정보를 데이터베이스에 저장하는 예제는 참고자료에서 제공한다. (링크 사라짐)

Listing 8. session_set_save_handler() 함수 예제

function open($save_path, $session_name)
{
    /* custom code */
    return (true);
}

function close()
{
    /* custom code */
    return (true);
}

function read($id)
{
    /* custom code */
    return (true);
}

function write($id, $sess_data)
{
    /* custom code */
    return (true);
}

function destroy($id)
{
    /* custom code */
    return (true);
}

function gc($maxlifetime)
{
    /* custom code */
    return (true);
}

session_set_save_handler("open", "close", "read", "write", "destroy", "gc");

XSS 취약점을 방어하라

2007년 문서로 보고된 웹 사이트 취약점 중 상당한 수가 XSS 취약점이다(자세한 내용은 참고자료를 살펴본다 - 링크 사라짐). XSS 취약점은 사용자가 웹 페이지에 HTML 코드를 삽입할 수 있을 때 생긴다. HTML 코드를 삽입할 수 있다면 script 태그 안에 자바스크립트 코드를 삽입할 수 있다는 뜻이다. 즉, 페이지를 그릴 때 사용자가 삽입한 자바스크립트 코드가 돌아간다. Listing 9는 포럼, 위키, 소셜 네트워크나 기타 사이트에서 아주 일반적으로 사용하는 입력 폼이다.

Listing 9. 문자열을 입력받는 폼

<html>
<head>
<title>Your chance to input XSS</title>
</head>
<body>
<form id="myFrom" action="showResults.php" method="post">
<div><textarea name="myText" rows="4" cols="30"></textarea><br />
<input type="submit" value="Delete" name="submit" /></div>
</form>
</body>
</html>

Listing 10은 폼에서 입력받은 문자열을 출력하는 페이지로 XSS 공격을 허용하는 예제다.

Listing 10. showResults.php

<html>
<head>
<title>Results demonstrating XSS</title>
</head>
<body>
<?php
echo("<p>You typed this:</p>");
echo("<p>");
echo($_POST['myText']);
echo("</p>");
?>
</body>
</html>

Listing 11은 새 창을 열어 구글 홈 페이지를 표시하는 스크립트다. 웹 사이트가 XSS 공격에 대비하지 않는다면 피해 정도는 공격자 상상력에 달려 있다. 예를 들어, 비슷한 웹 사이트를 만든 후 링크를 추가하여 사용자 정보를 피싱(phishing)하는 사례도 있다(자세한 내용은 참고자료를 살펴본다).

Listing 11. 악성 입력 예제

<script type="text/javascript">myRef = window.open('http://www.google.com','mywin',
'left=20,top=20,width=500,height=500,toolbar=1,resizable=0');</script>

XSS 공격으로부터 웹 사이트를 보호하려면 변수 값을 출력할 때 htmlentities() 함수를 사용한다. htmlentities() 함수는 문자열에서 HTML 엘리먼트를 걸러낸다. 앞서 언급했듯이 이름, 전자편지 주소, 전화 번호, 우편물 주소 등의 입력은 화이트 리스트로 값을 검증해야 한다는 사실도 명심한다.

Listing 12는 좀 더 안전하게 입력을 처리하는 코드다.

Listing 12. 좀 더 안전한 폼

<html>
<head>
<title>Results demonstrating XSS</title>
</head>
<body>
<?php
echo("<p>You typed this:</p>");
echo("<p>");
echo(htmlentities($_POST['myText']));
echo("</p>");
?>
</body>
</html>

폼 정보를 보호하라

폼 스푸핑(Form Spoofing)이란 예상하지 못한 곳에서 내 폼으로 정보를 보내는 행위를 뜻한다. 폼 정보를 조작하는 가장 쉬운 방법은 폼을 제출하는 페이지를 만들어 모든 값을 넘기는 방법이다. 웹 응용 프로그램은 무상태형(stateless)이므로 폼 정보가 여러분이 원하는 올바른 페이지에서 오는지 확인할 방법은 전혀 없다. IP 주소에서 호스트 이름까지 별의별 내용을 조작 가능하다. Listing 13은 조작이 쉬운 일반적인 폼이다.

Listing 13. 입력 문자열을 처리하는 폼

<html>
<head>
<title>Form spoofing example</title>
</head>
<body>
<?php
if ($_POST['submit'] == 'Save') {
    echo("<p>I am processing your text: ");
    echo($_POST['myText']);
    echo("</p>");
}
?>
</body>
</html>

Listing 14는 사용자에게 정보를 입력받아 Listing 13으로 넘긴다. 실제로 테스트하려면 Listing 13을 웹 서버에 올린 후 Listing 14를 로컬 시스템에 HTML로 저장한다. 그런 다음, 브라우저에서 HTML 파일을 열고 정보를 입력한 후 폼을 제출하고 결과를 확인한다.

Listing 14. 사용자로부터 자료를 수집하는 폼

<html>
<head>
<title>Collecting your data</title>
</head>
<body>
<form action="http://path.example.com/processStuff.php" method="post">
<select name="answer">
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<input type="submit" value="Save" name="submit" />
</form>
</body>
</html>

누군가 폼 정보를 가로채려 든다면 드롭다운 목록, 라디오 버튼, 체크박스 등으로 입력을 제한해도 소용이 없다. Listing 15는 잘못된 값을 폼으로 넘기는 예제다.

Listing 15. 잘못된 입력 값을 넘기는 폼

<html>
<head>
<title>Collecting your data</title>
</head>
<body>
<form action="http://path.example.com/processStuff.php"
    method="post"><input type="text" name="answer"
    value="There is no way this is a valid response to a yes/no answer..." />
<input type="submit" value="Save" name="submit" />
</form>
</body>
</html>

흔히 드롭다운 상자나 라디오 버튼으로 사용자 입력을 제한했다는 이유로 입력 값을 검증할 필요가 없다고 유혹에 빠지기 쉽다. 애초에 사용자에게서 특정한 입력을 받으려고 폼을 사용하지 않던가? 그러므로 폼 스푸핑을 제한하려면 폼을 제출하는 사람이 올바른지 확인하는 방어막을 친다. 한 가지 방법이 일회용 토큰이다. 일회용 토큰은 폼 스푸핑을 100% 막지는 못하지만 굉장히 번거롭게 만든다. 폼을 제출할 때마다 토큰이 변하므로 악의적인 해커는 폼이 전송되는 도중에 가로채서 토큰을 찾아낸 후 스푸핑에 사용할 폼에다 넣어야 한다. 영구적인 웹 폼을 만들어 웹 사이트에 악의적인 요청을 전송하려는 해커라면 너무도 번거로워서 시도할 가능성이 낮아진다. Listing 16은 일회용 폼 토큰을 사용하는 예제다.

Listing 16. 일회용 폼 토큰 사용하기

<?php
session_start();
?>
<html>
<head>
<title>SQL Injection Test</title>
</head>
<body>
<?php

echo 'Session token=' . $_SESSION['token'];
echo '<br />';
echo 'Token from form=' . $_POST['token'];
echo '<br />';

if ($_SESSION['token'] == $_POST['token']) {
    /* 훌륭하다. 정상으로 돌아간다. 다른 토큰을 만들자. */

} else {
    echo '<h1>Go away!</h1>';
}
$token = md5(uniqid(rand(), true));
$_SESSION['token'] = $token;
?>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
<div><input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" name="myText"
    value="<?php echo(isset($_POST['myText']) ? $_POST['myText'] : ''); ?>" />
<input type="submit" value="Save" name="submit" /></div>
</form>
</body>
</html>

CSRF를 방어하라

CSRF(Cross-Site Request Forgeries) 공격은 사용자 권한을 악용하여 공격을 수행한다. CSRF 공격에서 웹 사이트 사용자는 본의 아니게 공범이 된다. Listing 17은 특정 작업을 수행하는 페이지 예제다. 이 페이지는 쿠키에서 사용자 로그인 정보를 찾는다. 쿠키가 유효한 동안 웹 서버는 사용자 요청을 처리한다.

Listing 17. CSRF 예제

<img src="http://www.example.com/processSomething?id=123456789" />

CSRF 공격은 흔히 <img> 태그 형태를 띈다. 브라우저가 이미지를 가져오려고 URL을 무조건 호출하기 때문이다. 하지만 HTML은 이미지 URL에 반드시 이미지를 지정할 필요가 없다. 이미지 대신 인수를 받아서 뭔가 작업을 수행하는 페이지를 지정해도 아무런 문제가 없다. XSS 공격에 <img> 태그를 넣는다면 사용자는 알아채지 못한 채 악의적인 작업을 수행하게 된다. 즉, 사용자 자격을 위조하게 된다(이는 가장 흔한 공격 유형이다).

CSRF 공격으로부터 사이트를 보호하려면 일회용 토큰을 사용하여 폼 정보를 검증하는 습관을 길러야 한다. 또한 $_REQUEST 대신에 명시적으로 $_POST 변수를 사용한다. Listing 18은 웹 페이지를 가져오는 바람직하지 못한 방법을 보여준다. 코드는 GET 요청과 POST요청을 모두 처리한다.

Listing 18. $_REQUEST에서 정보 가져오기

<html>
<head>
<title>Processes both posts AND gets</title>
</head>
<body>
<?php
if ($_REQUEST['submit'] == 'Save') {
    echo("<p>I am processing your text: ");
    echo(htmlentities($_REQUEST['text']));
    echo("</p>");
}
?>
</body>
</html>

Listing 19는 Listing 18을 개선한 코드다. 폼 POST로 넘기는 정보만 처리한다.

Listing 19. $_POST에서만 정보를 가져오기

<html>
<head>
<title>Processes both posts AND gets</title>
</head>
<body>
<?php
if ($_POST['submit'] == 'Save') {
    echo("<p>I am processing your text: ");
    echo(htmlentities($_POST['text']));
    echo("</p>");
}
?>
</body>
</html>

결론

지금까지 소개한 일곱 가지 습관을 익혀 좀 더 안전한 PHP 웹 응용 프로그램을 작성한다면 악의적인 공격으로 인해 피해를 입을 확률이 크게 낮아진다. 여느 습관처럼 처음에는 어색할지도 모르지만 시간이 지나면서 익숙해지리라 믿는다.

첫 번째 습관이 가장 중요하다. 입력을 검증하라. 입력을 확실히 검증했다면 다음으로 파일 시스템, 데이터베이스, 세션을 보호한다. 마지막으로 XSS 공격, 폼 스푸핑, CSRF 공격에 대비한다. 체계적으로 습관을 잘 들인다면 악의적인 공격으로부터 웹 사이트를 보호할 수 있다.

참고자료

교육

제품 및 기술 얻기

필자소개

Nathan Good은 미네소타 주 트윈시에 산다. 그는 전문 소프트웨어 개발자, 소프트웨어 아키텍트, 시스템 운영자다. 소프트웨어를 만들지 않을 때는 PC와 서버를 조립하거나 신기술에 대한 글을 읽거나 신기술을 가지고 이것저것 해보거나 친구들을 오픈 소스 소프트웨어로 끌어들이려 애쓴다. 그는 Professional Red Hat Enterprise Linux 3, Regular Expression Recipes: A Problem-Solution Approach, Foundations of PEAR: Rapid PHP Development를 비롯해 많은 책과 기사를 썼다.